[3depict] 01/04: * Update to 0.0.17

D Haley mycae-guest at moszumanska.debian.org
Sun Sep 28 15:46:52 UTC 2014


This is an automated email from the git hooks/post-receive script.

mycae-guest pushed a commit to branch master
in repository 3depict.

commit 06a21f13b28b411d6b2ee51ac2a1ace9c935d69d
Author: D Haley <mycae at gmx.com>
Date:   Sun Sep 28 16:53:51 2014 +0200

    * Update to 0.0.17
---
 ChangeLog                                          |   37 +
 TODO                                               |   16 +-
 aclocal.m4                                         |   58 +-
 config.h.in                                        |    6 -
 configure                                          |  246 +-
 configure.ac                                       |   95 +-
 data/naturalAbundance.xml                          |   16 +-
 docs/developers/code-notes.txt                     |    5 -
 docs/developers/filter-template.patch              |  295 ++
 docs/manual-latex/figures/Screenshot-thumb.png     |  Bin 0 -> 43986 bytes
 docs/manual-latex/manual.blg                       |    2 +-
 docs/manual-latex/manual.log                       |   30 +-
 docs/manual-latex/manual.pdf                       |  Bin 4517180 -> 4550865 bytes
 docs/manual-latex/manual.tex                       |    6 +-
 docs/web/about.html                                |    3 +
 docs/web/compiling-OSX.html                        |   74 +
 docs/web/compiling-cross.html                      |   56 +
 docs/web/compiling-linux.html                      |  153 +
 docs/web/compiling-macosx.html                     |   78 +
 docs/web/compiling.html                            |  528 +---
 docs/web/contact.html                              |    3 +-
 docs/web/documentation.html                        |   25 +-
 docs/web/download.html                             |   37 +-
 docs/web/images/3Depict-icon.png                   |  Bin 0 -> 9132 bytes
 docs/web/images/Screenshot-thumb.png               |  Bin 0 -> 39680 bytes
 docs/web/images/cu-ppt-cluster-analysis.png        |  Bin 0 -> 116809 bytes
 docs/web/images/exportanimParamDialog.png          |  Bin 0 -> 89361 bytes
 docs/web/images/laser-data1.png                    |  Bin 0 -> 322814 bytes
 docs/web/images/laser-data2.png                    |  Bin 0 -> 193987 bytes
 docs/web/images/resolution-example.png             |  Bin 0 -> 201393 bytes
 docs/web/images/voxel-representations.png          |  Bin 0 -> 1034586 bytes
 docs/web/index.html                                |   31 +-
 docs/web/manual.html                               |    2 +-
 docs/web/news.html                                 |   35 +-
 docs/web/questions.html                            |   25 +-
 docs/web/rss.xml                                   |   42 +-
 docs/web/screenshots.html                          |   60 +
 docs/web/videos.html                               |   37 +-
 install-sh                                         |    1 -
 locales/de_DE/LC_MESSAGES/3Depict.mo               |  Bin 49844 -> 45179 bytes
 packaging/RPM/3Depict-0.0.15-manual-pdf-loc.patch  |   16 -
 ...t-path.patch => 3Depict-0.0.17-font-path.patch} |    8 +-
 packaging/RPM/3Depict-0.0.17-manual-pdf-loc.patch  |   16 +
 packaging/RPM/3Depict-0.0.17-upstream.patch        |   65 +
 packaging/RPM/3Depict.spec                         |   14 +-
 packaging/debian/3depict.install                   |    0
 packaging/debian/changelog                         |   16 +-
 packaging/debian/control                           |    2 +-
 packaging/debian/copyright                         |    0
 packaging/debian/patches/patch-caching-bug         |   35 -
 packaging/debian/patches/series                    |    2 -
 packaging/debian/rules                             |    9 +-
 packaging/deps/getDeps                             |  122 +-
 packaging/mac/3package.sh                          |   18 +
 packaging/mac/makeMacOSXApp                        |    2 +
 packaging/makeTarball.sh                           |   21 +-
 packaging/mingw-debian-cross/bootstrap.sh          |  245 +-
 .../mingw-debian-cross/patches/cmake-toolchain32   |   25 +
 .../mingw-debian-cross/patches/cmake-toolchain64   |   24 +
 .../patches/ftgl-mingw32-prototype                 |    0
 .../patches/ftgl-override-configure                |    0
 .../patches/gettext-disable-tools                  |    0
 .../patches/gettext-win32-prefix                   |    0
 packaging/mingw-debian-cross/patches/glew-makefile |   31 +-
 .../mingw-debian-cross/patches/glew-makefile.base  |   27 +-
 .../mingw-debian-cross/patches/gsl-config.patch    |    0
 .../mingw-debian-cross/patches/zlib-no-lc.patch    |    0
 packaging/mingw-debian-cross/windows-installer.nsi |   41 +-
 src/3Depict.cpp                                    |  108 +-
 src/Makefile.am                                    |   16 +-
 src/Makefile.in                                    |   74 +-
 src/backend/APT/APTFileIO.cpp                      |   49 +-
 src/backend/APT/APTFileIO.h                        |    7 +-
 src/backend/APT/APTRanges.cpp                      |   58 +-
 src/backend/APT/APTRanges.h                        |   12 +-
 src/backend/APT/abundanceParser.cpp                |   73 +
 src/backend/APT/abundanceParser.h                  |   10 +-
 src/backend/APT/ionhit.cpp                         |    6 +
 src/backend/APT/ionhit.h                           |    2 +
 src/backend/animator.cpp                           |   48 +-
 src/backend/configFile.cpp                         |   10 +-
 src/backend/filter.cpp                             |  188 +-
 src/backend/filter.h                               |  115 +-
 src/backend/filters/algorithms/K3DTree-mk2.cpp     |  143 +-
 src/backend/filters/algorithms/K3DTree-mk2.h       |   19 +-
 src/backend/filters/allFilter.h                    |    1 -
 src/backend/filters/annotation.cpp                 |  247 +-
 src/backend/filters/annotation.h                   |    2 +-
 src/backend/filters/boundingBox.cpp                |  106 +-
 src/backend/filters/boundingBox.h                  |    2 +-
 src/backend/filters/clusterAnalysis.cpp            |  257 +-
 src/backend/filters/clusterAnalysis.h              |    3 +
 src/backend/filters/compositionProfile.cpp         |  280 +-
 src/backend/filters/compositionProfile.h           |    2 +-
 src/backend/filters/dataLoad.cpp                   |  132 +-
 src/backend/filters/dataLoad.h                     |    5 +-
 src/backend/filters/externalProgram.cpp            |  136 +-
 src/backend/filters/filterCommon.cpp               |   46 +-
 src/backend/filters/filterCommon.h                 |   12 +-
 src/backend/filters/ionClip.cpp                    |  139 +-
 src/backend/filters/ionColour.cpp                  |   57 +-
 src/backend/filters/ionColour.h                    |    2 +
 src/backend/filters/ionDownsample.cpp              |   88 +-
 src/backend/filters/ionInfo.cpp                    |   76 +-
 src/backend/filters/rangeFile.cpp                  |  266 +-
 src/backend/filters/rangeFile.h                    |    4 +
 src/backend/filters/spatialAnalysis.cpp            |  815 ++++--
 src/backend/filters/spatialAnalysis.h              |   23 +-
 src/backend/filters/spectrumPlot.cpp               |  162 +-
 src/backend/filters/spectrumPlot.h                 |    2 +-
 src/backend/filters/transform.cpp                  |  144 +-
 src/backend/filters/voxelise.cpp                   |  267 +-
 src/backend/filters/voxelise.h                     |    2 +-
 src/backend/filtertree.cpp                         |   91 +-
 src/backend/filtertree.h                           |    8 +-
 src/backend/filtertreeAnalyse.cpp                  |    5 +-
 src/backend/plot.cpp                               | 1006 ++++---
 src/backend/plot.h                                 |  223 +-
 src/backend/state.cpp                              |  154 +-
 src/backend/state.h                                |    7 +-
 src/backend/tree.hh                                |    0
 src/backend/viscontrol.cpp                         |  257 +-
 src/backend/viscontrol.h                           |   35 +-
 src/common/array2D.h                               |  223 ++
 src/common/basics.cpp                              |  411 ++-
 src/common/basics.h                                |  176 +-
 src/common/{translation.h => constants.cpp}        |   39 +-
 src/common/constants.h                             |   29 +-
 src/common/stringFuncs.cpp                         |   77 +-
 src/common/stringFuncs.h                           |   18 +-
 src/common/translation.h                           |    5 -
 src/gl/cameras.cpp                                 |   99 +-
 src/gl/cameras.h                                   |   24 +-
 src/gl/drawables.cpp                               |  334 ++-
 src/gl/drawables.h                                 |  223 +-
 src/gl/glDebug.h                                   |   37 +-
 src/gl/scene.cpp                                   |  118 +-
 src/gl/scene.h                                     |    8 +-
 src/gl/textures.h                                  |    9 +
 src/gl/tr.cpp                                      |   49 +-
 src/gl/tr.h                                        |   21 +
 src/gui/dialogs/ExportPos.cpp                      |   36 +-
 src/gui/dialogs/ExportRngDialog.cpp                |   56 +-
 src/gui/dialogs/StashDialog.cpp                    |   71 +-
 src/gui/dialogs/StashDialog.h                      |    5 +-
 src/gui/dialogs/animateFilterDialog.cpp            |  174 +-
 src/gui/dialogs/animateFilterDialog.h              |    5 +-
 .../animateSubDialogs/choiceKeyFrameDialog.cpp     |    2 +-
 .../animateSubDialogs/colourKeyFrameDialog.cpp     |   36 +-
 .../animateSubDialogs/stringKeyFrameDialog.cpp     |   48 +-
 src/gui/dialogs/autosaveDialog.cpp                 |    8 +-
 src/gui/dialogs/filterErrorDialog.cpp              |   10 +-
 src/gui/dialogs/prefDialog.cpp                     |  290 +-
 src/gui/dialogs/prefDialog.h                       |    9 +-
 src/gui/dialogs/rangeEditDialog.cpp                |  112 +-
 src/gui/dialogs/rangeEditDialog.h                  |    2 +-
 src/gui/dialogs/resolutionDialog.cpp               |   42 +-
 src/gui/glPane.cpp                                 |  296 +-
 src/gui/glPane.h                                   |    9 +-
 src/gui/glade-skeleton/animateFilterDialog.wxg     |    0
 .../animateSubDialogs/choiceKeyFrameDialog.wxg     |    0
 .../animateSubDialogs/colourChooserDialog.wxg      |    0
 .../animateSubDialogs/realKeyFrameDialog.wxg       |    0
 .../animateSubDialogs/stringKeyFrameDialog.wxg     |    0
 src/gui/glade-skeleton/autosaveDialog.wxg          |    0
 src/gui/glade-skeleton/errorDialog.wxg             |    0
 src/gui/glade-skeleton/mainWindow.wxg              |    0
 src/gui/glade-skeleton/preferencesDialog.wxg       |    0
 src/gui/glade-skeleton/resDialog.wxg               |    0
 src/gui/mainFrame.cpp                              | 1499 +++++-----
 src/gui/mainFrame.h                                |   55 +-
 src/gui/mathglPane.cpp                             |  296 +-
 src/gui/mathglPane.h                               |   18 +-
 src/testing/filtertesting.cpp                      |   31 +-
 src/testing/mglTesting.cpp                         |   30 +-
 src/testing/mglTesting.h                           |   18 +
 src/testing/testing.cpp                            |   49 +-
 src/testing/testing.h                              |    1 +
 src/wx/propertyGridUpdater.cpp                     |  320 +++
 src/wx/propertyGridUpdater.h                       |   43 +
 src/wx/wxcommon.cpp                                |  112 +-
 src/wx/wxcommon.h                                  |   12 +-
 src/wx/wxcomponents.cpp                            |  512 +---
 src/wx/wxcomponents.h                              |   97 -
 test/dogtail/test.py                               |    2 +-
 translations/3Depict_base.pot                      | 2799 +++++++++---------
 translations/3Depict_de_DE.mo                      |  Bin 49844 -> 45179 bytes
 translations/3Depict_de_DE.po                      | 2979 ++++++++++----------
 translations/makeTranslations                      |    6 +-
 189 files changed, 11057 insertions(+), 9676 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 42b3ac6..6f343ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+* 01 Sep 2014 : 0.0.17
+	Features
+	- Upgrade to wxWidgets 3 (wx3)
+		- Now using wx3 property grid. Property grid interaction
+		  greatly improved.
+			- Categories collapsible
+			- file browse buttons
+			- One-click check buttons/dropdown
+	- Set (Subtraction/Union/Intersection) operations on points
+		- Can, eg load data from separate file after performing
+		operations on primary file
+		
+
+	User Visible Changes
+	- Fix bug in left/right panel startup size setting
+	- Exporting images with colour bar now works correctly
+	- Cursor now shows OS' busy status during refresh
+	- Files no longer disappear from recent when loading
+	- Fix range propagation behaviour when using spatial analysis
+	- Clustering now supports cluster ID->value mode (Feature request)
+	- Status messages are now queued, so they won't be missed
+	- Fixed profile minimum events not working
+
+	Technical bugfixes/changes:
+	- wxWidgets < 2.9 (prior to 2010) no longer supported
+		- Remove 2.8 conditional code
+	- Mathgl < 2.0 (prior to 2011) no longer supported
+		- Remove 1.x conditional code
+	- Fix relatively frequent crashes when sampling data files
+		under parallel mode
+	- 2D plots (f(x,y) and scatter+size) now supported, but no
+	   filter actually currently uses this
+	- All filter properties must have a group title
+	- Fix crash in mac OSX if expected data files not found
+	- Refactoring for filter caching and property setting
+	- Fix linker failure when using distcc
+
 * 01 Mar 2014 : 0.0.16
 	Features:
 	- Added experimental LAWATAP (ATO) file support
diff --git a/TODO b/TODO
index d425a18..c648e05 100644
--- a/TODO
+++ b/TODO
@@ -1,14 +1,16 @@
 TODO List - worlds simplest bugtracking system 
 
 --Packaging--
+	* Update manual with
+		- cluster ID 
+		- Set operations
 
 --Main app--
 	To Implement:
 		== Next version ==
+		* Alpha blending on plane slice?
 	
 		== Eventually == 
-		* Support for XY scatter plots
-		* Status bar message queue
 		* Voxel export dialog 
 		* VTK voxel data export
 		* OPS and other 3DAP formats reader?
@@ -36,10 +38,9 @@ TODO List - worlds simplest bugtracking system
 
 	Outstanding bugs:
 		== Next release==
-		* Colour bar drawing broken when tiling an output image
-		* Fix voxelisation "filter" option 
-			
+	
 		== Eventually==
+		* Fix voxelisation "filter" option 
 		* Cluster filter wont save state correctly if parent
 		  rangefile has disabled ions. It will output incorrect
 		  number of enabled ions, and get wiped during next ::initFilter
@@ -68,7 +69,6 @@ TODO List - worlds simplest bugtracking system
 		* Pos limit loader could alter its behaviour when
 		 sampling rates some percentage to be determined (load
 		 file, skip buffer).
-		* KD tree could implement proper range queries, eg bounds overlaps box
 		* Clustering could be paralellised, but is complex. Split & weld along KD tree lines using 
 		  cluster BB interactions.
 		* Examine performance characteristics of HULL_GRAB in ioninfo
@@ -80,9 +80,6 @@ TODO List - worlds simplest bugtracking system
 
 
 -- Refactor/cleanup --
-	* updateFilterPropertyGrid is in a bad location, need new
-	  file that knows about filters and wx at the same time,
-	  but is not viscontrol ;)
 	* Plotting code is a nightmare. Data model for plot.h is not
 	   very well thought out, leading to large duplication, and elaborate special-case-ing
 		- Plots need log/non-log axes
@@ -91,7 +88,6 @@ TODO List - worlds simplest bugtracking system
 		- Plots need to be able to set strings/legends
 		- There is little diference between plot1D and plot2D, really.
 	* work out which inline FIXMEs and TODOs are still valid, and need attention
-	* I have multiple colour classes floating about. might be an idea to unify them.
 	* K3DTree currently requires public access to members of boundcube
 	* Enums should be, where possible, moved into their relevant class' namespace
 	* Better error code behaviour for filters. There is a lot of needless duplication
diff --git a/aclocal.m4 b/aclocal.m4
index 7bf2270..170ae3e 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -180,6 +180,61 @@ else
 fi[]dnl
 ])# PKG_CHECK_MODULES
 
+
+# PKG_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable pkgconfigdir as the location where a module
+# should install pkg-config .pc files. By default the directory is
+# $libdir/pkgconfig, but the default can be changed by passing
+# DIRECTORY. The user can override through the --with-pkgconfigdir
+# parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+    [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+    [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_INSTALLDIR
+
+
+# PKG_NOARCH_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable noarch_pkgconfigdir as the location where a
+# module should install arch-independent pkg-config .pc files. By
+# default the directory is $datadir/pkgconfig, but the default can be
+# changed by passing DIRECTORY. The user can override through the
+# --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+    [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+    [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+    [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_NOARCH_INSTALLDIR
+
+
+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])# PKG_CHECK_VAR
+
 # Copyright (C) 2002-2013 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
@@ -733,8 +788,7 @@ to "yes", and re-run configure.
 END
     AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
   fi
-fi
-])
+fi])
 
 dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion.  Do not
 dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
diff --git a/config.h.in b/config.h.in
index 60472de..affad5d 100644
--- a/config.h.in
+++ b/config.h.in
@@ -24,9 +24,6 @@
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
-/* MathGL compilation OK */
-#undef HAVE_MGL
-
 /* PNG compilation OK */
 #undef HAVE_PNG
 
@@ -90,9 +87,6 @@
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
-/* "Enable mgl1 support" */
-#undef USE_MGL1
-
 /* "Enable mgl2 support" */
 #undef USE_MGL2
 
diff --git a/configure b/configure
index 62f3ce3..045e12b 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for 3Depict 0.0.16.
+# Generated by GNU Autoconf 2.69 for 3Depict 0.0.17.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -577,8 +577,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='3Depict'
 PACKAGE_TARNAME='3depict'
-PACKAGE_VERSION='0.0.16'
-PACKAGE_STRING='3Depict 0.0.16'
+PACKAGE_VERSION='0.0.17'
+PACKAGE_STRING='3Depict 0.0.17'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -779,8 +779,6 @@ with_libqhull_flags
 with_libqhull_link
 with_libpng_flags
 with_libpng_link
-enable_mgl2
-enable_mgl1
 with_mgl_flags
 with_mgl_libs
 with_gsl_flags
@@ -791,6 +789,7 @@ enable_gsltest
 with_intl_libs
 enable_openmp_parallel
 enable_debug_checks
+enable_ubsan
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1352,7 +1351,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures 3Depict 0.0.16 to adapt to many kinds of systems.
+\`configure' configures 3Depict 0.0.17 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1422,7 +1421,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of 3Depict 0.0.16:";;
+     short | recursive ) echo "Configuration of 3Depict 0.0.17:";;
    esac
   cat <<\_ACEOF
 
@@ -1436,11 +1435,10 @@ Optional Features:
                           do not reject slow dependency extractors
   --disable-dependency-tracking
                           speeds up one-time build
-  --enable-mgl2 Enable mathgl 2.x support
-  --enable-mgl1 Enable mathgl 1.x support
   --disable-gsltest       Do not try to compile and run a test GSL program
   --enable-openmp-parallel  Enable OpenMP multi-CPU usage; requires GCC > 4.2 for parallel STL support
   --disable-debug-checks Disable any debug checking, provides faster operation, but less information needed to debug internal problems, or to provide problem reports to developers
+ --disable-ubsan Disable undefined behaviour sanitizer. Only takes effect on certain ubsan supporting compilers. Useful for working around ubsan aborts that you cant fix (eg 3rd party libs
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1554,7 +1552,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-3Depict configure 0.0.16
+3Depict configure 0.0.17
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2194,52 +2192,6 @@ fi
 
 } # ac_fn_cxx_check_header_mongrel
 
-# ac_fn_cxx_try_link LINENO
-# -------------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_cxx_try_link ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  rm -f conftest.$ac_objext conftest$ac_exeext
-  if { { ac_try="$ac_link"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && {
-	 test -z "$ac_cxx_werror_flag" ||
-	 test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-	 test "$cross_compiling" = yes ||
-	 test -x conftest$ac_exeext
-       }; then :
-  ac_retval=0
-else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-	ac_retval=1
-fi
-  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
-  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
-  # interfere with the next link command; also delete a directory that is
-  # left behind by Apple's compiler.  We do this before executing the actions.
-  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
-
-} # ac_fn_cxx_try_link
-
 # ac_fn_c_check_type LINENO TYPE VAR INCLUDES
 # -------------------------------------------
 # Tests whether TYPE exists after having included INCLUDES, setting cache
@@ -2364,7 +2316,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by 3Depict $as_me 0.0.16, which was
+It was created by 3Depict $as_me 0.0.17, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3227,7 +3179,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='3depict'
- VERSION='0.0.16'
+ VERSION='0.0.17'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3319,7 +3271,6 @@ END
     as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
   fi
 fi
-
 ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
 ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -5372,7 +5323,7 @@ fi
   if test "$WX_CONFIG_PATH" != "no" ; then
     WX_VERSION=""
 
-    min_wx_version=2.6.0
+    min_wx_version=2.9.0
     if test -z "" ; then
       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5
 $as_echo_n "checking for wxWidgets version >= $min_wx_version... " >&6; }
@@ -5544,20 +5495,23 @@ fi
 
 
 #Append the --gl-libs flag
-WX_LIBS="$WX_LIBS `$WX_CONFIG_PATH --gl-libs`"
+WX_LIBS="$WX_LIBS `$WX_CONFIG_PATH --libs gl,propgrid`"
 
 WANT_WINDRES="no"
 case "${host_os}" in
-	*w64_mingw*)
+	*mingw*)
 		#wx-config is a little unreliable in cross-compile mode
 		# Manually append -DUNICODE to cppflags/cxxflags
 		WX_CXXFLAGS="$WX_CXXFLAGS -DUNICODE"
 		WX_CPPFLAGS="$WX_CPPFLAGS -DUNICODE"
-		WANT_WINDRES="true"
+		WANT_WINDRES="yes"
 		;;
 esac
 
- if  test x$WANT_WINDRES= xtrue  ; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Want windres... $WANT_WINDRES" >&5
+$as_echo "Want windres... $WANT_WINDRES" >&6; }
+
+ if  test x"$WANT_WINDRES" == "xyes" ; then
   HAVE_WINDRES_TRUE=
   HAVE_WINDRES_FALSE='#'
 else
@@ -6800,20 +6754,6 @@ esac
 CFLAGS_ORIG="$CFLAGS"
 LDFLAGS_ORIG="$LDFLAGS"
 
-# Check whether --enable-mgl2 was given.
-if test "${enable_mgl2+set}" = set; then :
-  enableval=$enable_mgl2;
-fi
-
-# Check whether --enable-mgl1 was given.
-if test "${enable_mgl1+set}" = set; then :
-  enableval=$enable_mgl1;
-fi
-
-
-if test x"${enable_mgl2}" == x"yes"  && test x"${enable_mgl1}" == x"yes"; then
-	as_fn_error $? "\"Can specify mgl1, or mgl2 - not both\"" "$LINENO" 5
-fi
 
 
 # Check whether --with-mgl-flags was given.
@@ -6841,8 +6781,6 @@ fi
 
 LDFLAGS="$LDFLAGS $MGL_LIBS"
 
-#Note:
-#  mathgl1.x uses mgl_c.h as c functions.
 #  mathgl2.x uses mgl_cf.h for c functions.
 ac_ext=cpp
 ac_cpp='$CXXCPP $CPPFLAGS'
@@ -6850,11 +6788,10 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
 
-if test x"${enable_mgl2}" == x"yes" ; then
 
 $as_echo "#define USE_MGL2 1 " >>confdefs.h
 
-	as_ac_Header=`$as_echo "ac_cv_header_"mgl2/mgl_cf.h"" | $as_tr_sh`
+as_ac_Header=`$as_echo "ac_cv_header_"mgl2/mgl_cf.h"" | $as_tr_sh`
 ac_fn_cxx_check_header_mongrel "$LINENO" ""mgl2/mgl_cf.h"" "$as_ac_Header" "$ac_includes_default"
 if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
 
@@ -6863,100 +6800,6 @@ else
 fi
 
 
-else
-	if test x"${enable_mgl1}" == x"yes" ; then
-
-$as_echo "#define USE_MGL1 0 " >>confdefs.h
-
-		as_ac_Header=`$as_echo "ac_cv_header_"mgl/mgl_c.h"" | $as_tr_sh`
-ac_fn_cxx_check_header_mongrel "$LINENO" ""mgl/mgl_c.h"" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-
-else
-  as_fn_error $? "\"mgl specified, but header mgl/mgl_c.h not found\"" "$LINENO" 5
-fi
-
-
-	else
-		#mgl2 is installed into different path (at least under debian)
-		#  /usr/include/mgl2/
-		MGL_TEST_HEADERS="mgl2/mgl_cf.h mgl/mgl_c.h"
-		for ac_header in $MGL_TEST_HEADERS
-do :
-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
- HAVE_MGL_H=1; break;
-fi
-
-done
-
-
-		#check our set HAVE_MGL_H for *any* mglh
-		if  test $HAVE_MGL_H -ne 1  ; then :
-   as_fn_error $? "\"MGL headers not found, looking for any of $MGL_TEST_HEADERS\"" "$LINENO" 5
-fi
-
-		#Check MGL 2:
-		if  test x"$ac_cv_header_mgl2_mgl_cf_h" == x"yes" ; then :
-   $as_echo "#define USE_MGL2 1" >>confdefs.h
-
-else
-   USE_MGL2=0
-fi
-
-
-
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for mgl_set_def_param in -lmgl" >&5
-$as_echo_n "checking for mgl_set_def_param in -lmgl... " >&6; }
-if ${ac_cv_lib_mgl_mgl_set_def_param+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lmgl -lmgl $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char mgl_set_def_param ();
-int
-main ()
-{
-return mgl_set_def_param ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_cxx_try_link "$LINENO"; then :
-  ac_cv_lib_mgl_mgl_set_def_param=yes
-else
-  ac_cv_lib_mgl_mgl_set_def_param=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_mgl_mgl_set_def_param" >&5
-$as_echo "$ac_cv_lib_mgl_mgl_set_def_param" >&6; }
-if test "x$ac_cv_lib_mgl_mgl_set_def_param" = xyes; then :
-
-$as_echo "#define HAVE_MGL /**/" >>confdefs.h
-
-else
-  as_fn_error $? "Required MathGL libraries not found" "$LINENO" 5
-fi
-
-
-	fi
-fi
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -7298,6 +7141,15 @@ else
 fi
 
 
+# Check whether --enable-ubsan was given.
+if test "${enable_ubsan+set}" = set; then :
+  enableval=$enable_ubsan;  enable_no_ubsan="yes"
+else
+  enable_no_ubsan="no"
+fi
+
+
+
 
 if test x"$enable_openmp_parallel" != x"" ;
 then
@@ -7319,14 +7171,43 @@ then
 
 
 
-	if test x"$GCC" = xyes; then
+	if test x"$GCC" = x"yes" ; then
 		# Strip optimsation flags from debug build
+		#--
 
 		CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9s]*//g'`
 		CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/-O[0-9s]*//g'`
 
 		CFLAGS="$CFLAGS -g"
 		CXXFLAGS="$CXXFLAGS -g"
+		#--
+
+		#Check for UbSan availability
+		#--
+		if test x"${enable_no_ubsan}" == x"no" ; then
+
+			USE_UBSAN="no"
+
+			case "${host_os}" in
+				*inux*)
+					GCC_VER=`gcc --version | head -n 1 | awk '{ print $(NF)}'`
+					case "${GCC_VER}" in
+						4.9*)
+							USE_UBSAN="yes"
+						;;
+					esac
+				;;
+			esac
+
+			if test x"$USE_UBSAN" == x"yes" ; then
+				CFLAGS="$CFLAGS  -fsanitize=address -fsanitize=undefined -fsanitize=return -fsanitize=integer-divide-by-zero -fsanitize=vla-bound -fsanitize=null -fsanitize=signed-integer-overflow"
+				CXXFLAGS="$CXXFLAGS  -fsanitize=address -fsanitize=undefined -fsanitize=return -fsanitize=integer-divide-by-zero -fsanitize=vla-bound -fsanitize=null -fsanitize=signed-integer-overflow"
+				LDFLAGS="$LDFLAGS  -fsanitize=address -fsanitize=undefined -fsanitize=return "
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"Enabling Gcc-UbSan\"" >&5
+$as_echo "\"Enabling Gcc-UbSan\"" >&6; };
+			fi
+		fi
+		#--
 
 	fi
 
@@ -7337,6 +7218,13 @@ else
 	fi
 fi
 
+if test x"$CXX" = xdistcc ; then
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: \"Adding distcc link flags\"" >&5
+$as_echo "\"Adding distcc link flags\"" >&6; };
+	#Add -lstdc++ to libs for distcc
+	LIBS="$LIBS -lstdc++"
+fi
+
 # Checks for typedefs, structures, and compiler characteristics.
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5
 $as_echo_n "checking for stdbool.h that conforms to C99... " >&6; }
@@ -8126,7 +8014,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by 3Depict $as_me 0.0.16, which was
+This file was extended by 3Depict $as_me 0.0.17, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -8192,7 +8080,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-3Depict config.status 0.0.16
+3Depict config.status 0.0.17
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 4a35591..c38c1c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_INIT([3Depict], [0.0.16]) 
+AC_INIT([3Depict], [0.0.17]) 
 AM_INIT_AUTOMAKE([foreign subdir-objects])
 AC_PROG_CXX
 AC_PROG_CC
@@ -18,7 +18,7 @@ dnl Test for wx-widgets
 dnl ----------
 AM_OPTIONS_WXCONFIG
 
-AM_PATH_WXCONFIG(2.6.0, wxWin=1)
+AM_PATH_WXCONFIG(2.9.0, wxWin=1)
 
 if test "$wxWin" != 1; then
 AC_MSG_ERROR([
@@ -34,20 +34,22 @@ fi
 
 
 #Append the --gl-libs flag
-WX_LIBS="$WX_LIBS `$WX_CONFIG_PATH --gl-libs`"
+WX_LIBS="$WX_LIBS `$WX_CONFIG_PATH --libs gl,propgrid`"
 
 WANT_WINDRES="no"
 case "${host_os}" in 
-	*w64_mingw*)
+	*mingw*)
 		#wx-config is a little unreliable in cross-compile mode
 		# Manually append -DUNICODE to cppflags/cxxflags
 		WX_CXXFLAGS="$WX_CXXFLAGS -DUNICODE"
 		WX_CPPFLAGS="$WX_CPPFLAGS -DUNICODE"
-		WANT_WINDRES="true"
+		WANT_WINDRES="yes"
 		;;
 esac
 
-AM_CONDITIONAL([HAVE_WINDRES], [ test x$WANT_WINDRES= xtrue ] )
+AC_MSG_RESULT([Want windres... $WANT_WINDRES])
+
+AM_CONDITIONAL([HAVE_WINDRES], [ test x"$WANT_WINDRES" == "xyes"] )
 
 
 AC_SUBST(WX_LIBS)
@@ -280,14 +282,6 @@ dnl ----------
 CFLAGS_ORIG="$CFLAGS"
 LDFLAGS_ORIG="$LDFLAGS"
 
-AC_ARG_ENABLE(mgl2,
-  [  --enable-mgl2 Enable mathgl 2.x support])
-AC_ARG_ENABLE(mgl1,
-  [  --enable-mgl1 Enable mathgl 1.x support])
-
-if test x"${enable_mgl2}" == x"yes"  && test x"${enable_mgl1}" == x"yes"; then 
-	AC_MSG_ERROR(["Can specify mgl1, or mgl2 - not both"])
-fi
 
 AC_ARG_WITH(mgl-flags,
   [  --with-mgl-flags=PATH : specify compiler flags for mathgl])
@@ -307,36 +301,10 @@ fi
 AC_SUBST(MGL_LIBS)
 LDFLAGS="$LDFLAGS $MGL_LIBS"
 
-#Note:
-#  mathgl1.x uses mgl_c.h as c functions. 
 #  mathgl2.x uses mgl_cf.h for c functions.
 AC_LANG_PUSH([C++])
-if test x"${enable_mgl2}" == x"yes" ; then 
-	AC_DEFINE(USE_MGL2, 1 , ["Enable mgl2 support"])
-	AC_CHECK_HEADER("mgl2/mgl_cf.h",[],[AC_MSG_ERROR(["mgl2 specified, but header mgl2/mgl_cf.h not found"])],[])
-else 
-	if test x"${enable_mgl1}" == x"yes" ; then
-		AC_DEFINE(USE_MGL1, 0 , ["Enable mgl1 support"])
-		AC_CHECK_HEADER("mgl/mgl_c.h",[],[AC_MSG_ERROR(["mgl specified, but header mgl/mgl_c.h not found"])],[])
-	else
-		#mgl2 is installed into different path (at least under debian)
-		#  /usr/include/mgl2/
-		MGL_TEST_HEADERS="mgl2/mgl_cf.h mgl/mgl_c.h"
-		AC_CHECK_HEADERS($MGL_TEST_HEADERS,[HAVE_MGL_H=1; break;], [])
-
-		#check our set HAVE_MGL_H for *any* mglh
-		AS_IF([ test $HAVE_MGL_H -ne 1 ] , [ AC_MSG_ERROR(["MGL headers not found, looking for any of $MGL_TEST_HEADERS"])]) 
-
-		#Check MGL 2:
-		AS_IF([ test x"$ac_cv_header_mgl2_mgl_cf_h" == x"yes" ], [ AC_DEFINE(USE_MGL2,1)  ], [ USE_MGL2=0 ])
-
-		
-		
-		AC_CHECK_LIB(mgl, mgl_set_def_param, [AC_DEFINE(HAVE_MGL,[],[MathGL compilation OK])] , 
-				AC_MSG_ERROR([Required MathGL libraries not found]), -lmgl)
-
-	fi
-fi
+AC_DEFINE(USE_MGL2, 1 , ["Enable mgl2 support"])
+AC_CHECK_HEADER("mgl2/mgl_cf.h",[],[AC_MSG_ERROR(["mgl2 specified, but header mgl2/mgl_cf.h not found"])],[])
 AC_LANG_POP([C++])
 
 
@@ -408,6 +376,11 @@ AC_ARG_ENABLE(openmp-parallel,
 AC_ARG_ENABLE(debug-checks,
   [  --disable-debug-checks Disable any debug checking, provides faster operation, but less information needed to debug internal problems, or to provide problem reports to developers ],[enable_no_debug_checks="yes"],[enable_no_debug_checks="no"])
 
+AC_ARG_ENABLE(ubsan,
+	[ --disable-ubsan Disable undefined behaviour sanitizer. Only takes effect on certain ubsan supporting compilers. Useful for working around ubsan aborts that you cant fix (eg 3rd party libs ],
+		[ enable_no_ubsan="yes"],[enable_no_ubsan="no"])
+
+
 
 if test x"$enable_openmp_parallel" != x"" ; 
 then
@@ -429,15 +402,43 @@ then
 
 	AC_SUBST(DEBUG_FLAGS)
 
-	if test x"$GCC" = xyes; then
+	if test x"$GCC" = x"yes" ; then
 		# Strip optimsation flags from debug build
+		#--
 		changequote({,})
 		CFLAGS=`echo "$CFLAGS" | sed -e 's/-O[0-9s]*//g'`
 		CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's/-O[0-9s]*//g'`
 		changequote([,])
 		CFLAGS="$CFLAGS -g"
 		CXXFLAGS="$CXXFLAGS -g"
-
+		#--
+
+		#Check for UbSan availability
+		#--
+		if test x"${enable_no_ubsan}" == x"no" ; then
+
+			USE_UBSAN="no"
+
+			case "${host_os}" in
+				*inux*)
+					GCC_VER=`gcc --version | head -n 1 | awk '{ print $(NF)}'`
+					case "${GCC_VER}" in
+						4.9*)
+							USE_UBSAN="yes"
+						;;
+					esac
+				;;
+			esac
+
+			if test x"$USE_UBSAN" == x"yes" ; then
+				CFLAGS="$CFLAGS  -fsanitize=address -fsanitize=undefined -fsanitize=return -fsanitize=integer-divide-by-zero -fsanitize=vla-bound -fsanitize=null -fsanitize=signed-integer-overflow"
+				CXXFLAGS="$CXXFLAGS  -fsanitize=address -fsanitize=undefined -fsanitize=return -fsanitize=integer-divide-by-zero -fsanitize=vla-bound -fsanitize=null -fsanitize=signed-integer-overflow"
+				LDFLAGS="$LDFLAGS  -fsanitize=address -fsanitize=undefined -fsanitize=return "
+				AC_MSG_RESULT(["Enabling Gcc-UbSan"]);
+			fi
+		fi
+		#--
+	
 	fi
 
 else 
@@ -447,6 +448,12 @@ else
 	fi
 fi
 
+if test x"$CXX" = xdistcc ; then
+	AC_MSG_RESULT(["Adding distcc link flags"]);
+	#Add -lstdc++ to libs for distcc
+	LIBS="$LIBS -lstdc++"
+fi
+
 # Checks for typedefs, structures, and compiler characteristics.
 AC_HEADER_STDBOOL
 AC_C_CONST
diff --git a/data/naturalAbundance.xml b/data/naturalAbundance.xml
index 7a371b0..b321d61 100644
--- a/data/naturalAbundance.xml
+++ b/data/naturalAbundance.xml
@@ -129,7 +129,7 @@ http://www.iupac.org/publications/pac/2003/7506/7506x0683.html
       <mass value="15.9994" error="0.0003"/>
       <isotope mass-number="16">
         <mass value="15.9949146223" error="0.0000000025"/>
-        <abundance value="0.99759" error="0.00016"/>
+        <abundance value="0.99757" error="0.00016"/>
       </isotope>
       <isotope mass-number="17">
         <mass value="16.99913150" error="0.00000022"/>
@@ -267,7 +267,7 @@ http://www.iupac.org/publications/pac/2003/7506/7506x0683.html
       <mass value="39.948" error="0.001"/>
       <isotope mass-number="36">
         <mass value="35.96754626" error="0.00000027"/>
-        <abundance value="0.0003365" error="0.000030"/>
+        <abundance value="0.003365" error="0.000030"/>
       </isotope>
       <isotope mass-number="38">
         <mass value="37.9627322" error="0.0000005"/>
@@ -328,7 +328,7 @@ http://www.iupac.org/publications/pac/2003/7506/7506x0683.html
   <entry symbol="Sc" atomic-number="21">
     <natural-abundance>
       <mass value="44.955910" error="0.000008"/>
-      <isotope mass-number="45">
+<isotope mass-number="45">
         <mass value="44.9559102" error="0.0000012"/>
         <abundance value="1" error="0"/>
       </isotope>
@@ -353,6 +353,10 @@ http://www.iupac.org/publications/pac/2003/7506/7506x0683.html
         <mass value="48.9478707" error="0.0000010"/>
         <abundance value="0.0541" error="0.0002"/>
       </isotope>
+      <isotope mass-number="50">
+        <mass value="49.9447912" error="0.0000010"/>
+        <abundance value="0.0518" error="0.0002"/>
+      </isotope>
     </natural-abundance>
   </entry>
   <entry symbol="V" atomic-number="23">
@@ -445,7 +449,7 @@ http://www.iupac.org/publications/pac/2003/7506/7506x0683.html
       </isotope>
       <isotope mass-number="62">
         <mass value="61.9283484" error="0.0000015"/>
-        <abundance value="0.0036345" error="0.000017"/>
+        <abundance value="0.036345" error="0.000017"/>
       </isotope>
       <isotope mass-number="64">
         <mass value="63.9279692" error="0.0000016"/>
@@ -732,7 +736,7 @@ http://www.iupac.org/publications/pac/2003/7506/7506x0683.html
       </isotope>
       <isotope mass-number="99">
         <mass value="98.9059385" error="0.0000022"/>
-        <abundance value=".01276" error="0.0014"/>
+        <abundance value=".1276" error="0.0014"/>
       </isotope>
       <isotope mass-number="100">
         <mass value="99.9042189" error="0.0000022"/>
@@ -1024,7 +1028,7 @@ http://www.iupac.org/publications/pac/2003/7506/7506x0683.html
       </isotope>
       <isotope mass-number="135">
         <mass value="134.905684" error="0.000003"/>
-        <abundance value="0.000003" error="0.00012"/>
+        <abundance value="0.06592" error="0.00012"/>
       </isotope>
       <isotope mass-number="136">
         <mass value="135.904571" error="0.000003"/>
diff --git a/docs/developers/code-notes.txt b/docs/developers/code-notes.txt
deleted file mode 100644
index 39213c2..0000000
--- a/docs/developers/code-notes.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-String comments that can be searched for in the code:
-	COMPAT_BREAK : items that need to be changed at some point, but require a compatability break with earlier versions
-	TODO : Deferred/nice-to-have/not-sure-about-fix items
-	FIXME : Not nicely written bits of code, or known minor problems/failure edge cases.
-
diff --git a/docs/developers/filter-template.patch b/docs/developers/filter-template.patch
new file mode 100644
index 0000000..b86ee77
--- /dev/null
+++ b/docs/developers/filter-template.patch
@@ -0,0 +1,295 @@
+diff -r e500a2602f86 src/Makefile.am
+--- a/src/Makefile.am	Sun Jul 20 15:44:52 2014 +0100
++++ b/src/Makefile.am	Sun Jul 20 15:49:30 2014 +0100
+@@ -38,7 +38,7 @@
+ 		backend/filters/compositionProfile.cpp backend/filters/spatialAnalysis.cpp \
+ 		backend/filters/clusterAnalysis.cpp backend/filters/ionInfo.cpp \
+ 		backend/filters/annotation.cpp backend/filters/geometryHelpers.cpp \
+-		backend/filters/algorithms/binomial.cpp  
++		backend/filters/algorithms/binomial.cpp  backend/filters/filterTemplate.cpp 
+ 
+ FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h \
+ 		backend/filters/dataLoad.h backend/filters/ionDownsample.h \
+@@ -48,7 +48,7 @@
+ 		backend/filters/compositionProfile.h backend/filters/spatialAnalysis.h \
+ 		backend/filters/clusterAnalysis.h backend/filters/ionInfo.h \
+ 		backend/filters/annotation.h backend/filters/geometryHelpers.h \
+-		backend/filters/algorithms/binomial.h 
++		backend/filters/algorithms/binomial.h backend/filters/algorithms/filterTemplate.h
+ 
+ BACKEND_SOURCE_FILES = backend/animator.cpp backend/filtertreeAnalyse.cpp backend/filtertree.cpp \
+ 		     	backend/APT/ionhit.cpp backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp backend/APT/abundanceParser.cpp \
+diff -r e500a2602f86 src/backend/filter.cpp
+--- a/src/backend/filter.cpp	Sun Jul 20 15:44:52 2014 +0100
++++ b/src/backend/filter.cpp	Sun Jul 20 15:49:30 2014 +0100
+@@ -63,7 +63,8 @@
+ 				"clusteranalysis",
+ 				"voxelise",
+ 				"ioninfo",
+-				"annotation"
++				"annotation",
++				"template"
+ 				};
+ 
+ size_t numElements(const vector<const FilterStreamData *> &v, unsigned int mask)
+diff -r e500a2602f86 src/backend/filter.h
+--- a/src/backend/filter.h	Sun Jul 20 15:44:52 2014 +0100
++++ b/src/backend/filter.h	Sun Jul 20 15:49:30 2014 +0100
+@@ -71,6 +71,7 @@
+ 	FILTER_TYPE_VOXELS,
+ 	FILTER_TYPE_IONINFO,
+ 	FILTER_TYPE_ANNOTATION,
++	FILTER_TYPE_TEMPLATE,
+ 	FILTER_TYPE_ENUM_END // not a filter. just end of enum
+ };
+ 
+diff -r e500a2602f86 src/backend/filters/allFilter.cpp
+--- a/src/backend/filters/allFilter.cpp	Sun Jul 20 15:44:52 2014 +0100
++++ b/src/backend/filters/allFilter.cpp	Sun Jul 20 15:49:30 2014 +0100
+@@ -104,6 +104,9 @@
+ 		case FILTER_TYPE_ANNOTATION:
+ 			f = new AnnotateFilter;
+ 			break;	
++		case FILTER_TYPE_TEMPLATE:
++			f = new TemplateFilter;
++			break;	
+ 		default:
+ 			ASSERT(false);
+ 	}
+diff -r e500a2602f86 src/backend/filters/allFilter.h
+--- a/src/backend/filters/allFilter.h	Sun Jul 20 15:44:52 2014 +0100
++++ b/src/backend/filters/allFilter.h	Sun Jul 20 15:49:30 2014 +0100
+@@ -32,6 +32,7 @@
+ #include "voxelise.h"
+ #include "ionInfo.h"
+ #include "annotation.h"
++#include "filterTemplate.h"
+ 
+ //!Returns true if the string is a valid filter name
+ bool isValidFilterName(const std::string &s);
+diff -r e500a2602f86 src/gui/mainFrame.cpp
+--- a/src/gui/mainFrame.cpp	Sun Jul 20 15:44:52 2014 +0100
++++ b/src/gui/mainFrame.cpp	Sun Jul 20 15:49:30 2014 +0100
+@@ -116,7 +116,7 @@
+ //MainFrame's constructor
+ 
+ //--- These settings must be modified concomitantly.
+-const unsigned int FILTER_DROP_COUNT=14;
++const unsigned int FILTER_DROP_COUNT=15;
+ 
+ const char * comboFilters_choices[FILTER_DROP_COUNT] =
+ {
+@@ -134,6 +134,7 @@
+ 	NTRANS("Range File"),
+ 	NTRANS("Spat. Analysis"),
+ 	NTRANS("Voxelisation"),
++	NTRANS("Template")
+ };
+ 
+ //Mapping between filter ID and combo position
+@@ -152,6 +153,7 @@
+ 	FILTER_TYPE_RANGEFILE,
+ 	FILTER_TYPE_SPATIAL_ANALYSIS,
+ 	FILTER_TYPE_VOXELS,
++	FILTER_TYPE_TEMPLATE,
+  };
+ //----
+ 
+diff -r 036cf664e28d docs/developers/filter-template.patch
+--- a/docs/developers/filter-template.patch	Sun Aug 24 14:17:50 2014 +0100
++++ b/docs/developers/filter-template.patch	Sun Aug 24 14:18:26 2014 +0100
+@@ -1,97 +0,0 @@
+-diff -r e500a2602f86 src/Makefile.am
+---- a/src/Makefile.am	Sun Jul 20 15:44:52 2014 +0100
+-+++ b/src/Makefile.am	Sun Jul 20 15:49:30 2014 +0100
+-@@ -38,7 +38,7 @@
+- 		backend/filters/compositionProfile.cpp backend/filters/spatialAnalysis.cpp \
+- 		backend/filters/clusterAnalysis.cpp backend/filters/ionInfo.cpp \
+- 		backend/filters/annotation.cpp backend/filters/geometryHelpers.cpp \
+--		backend/filters/algorithms/binomial.cpp  
+-+		backend/filters/algorithms/binomial.cpp  backend/filters/filterTemplate.cpp 
+- 
+- FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h \
+- 		backend/filters/dataLoad.h backend/filters/ionDownsample.h \
+-@@ -48,7 +48,7 @@
+- 		backend/filters/compositionProfile.h backend/filters/spatialAnalysis.h \
+- 		backend/filters/clusterAnalysis.h backend/filters/ionInfo.h \
+- 		backend/filters/annotation.h backend/filters/geometryHelpers.h \
+--		backend/filters/algorithms/binomial.h 
+-+		backend/filters/algorithms/binomial.h backend/filters/algorithms/filterTemplate.h
+- 
+- BACKEND_SOURCE_FILES = backend/animator.cpp backend/filtertreeAnalyse.cpp backend/filtertree.cpp \
+- 		     	backend/APT/ionhit.cpp backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp backend/APT/abundanceParser.cpp \
+-diff -r e500a2602f86 src/backend/filter.cpp
+---- a/src/backend/filter.cpp	Sun Jul 20 15:44:52 2014 +0100
+-+++ b/src/backend/filter.cpp	Sun Jul 20 15:49:30 2014 +0100
+-@@ -63,7 +63,8 @@
+- 				"clusteranalysis",
+- 				"voxelise",
+- 				"ioninfo",
+--				"annotation"
+-+				"annotation",
+-+				"template"
+- 				};
+- 
+- size_t numElements(const vector<const FilterStreamData *> &v, unsigned int mask)
+-diff -r e500a2602f86 src/backend/filter.h
+---- a/src/backend/filter.h	Sun Jul 20 15:44:52 2014 +0100
+-+++ b/src/backend/filter.h	Sun Jul 20 15:49:30 2014 +0100
+-@@ -71,6 +71,7 @@
+- 	FILTER_TYPE_VOXELS,
+- 	FILTER_TYPE_IONINFO,
+- 	FILTER_TYPE_ANNOTATION,
+-+	FILTER_TYPE_TEMPLATE,
+- 	FILTER_TYPE_ENUM_END // not a filter. just end of enum
+- };
+- 
+-diff -r e500a2602f86 src/backend/filters/allFilter.cpp
+---- a/src/backend/filters/allFilter.cpp	Sun Jul 20 15:44:52 2014 +0100
+-+++ b/src/backend/filters/allFilter.cpp	Sun Jul 20 15:49:30 2014 +0100
+-@@ -104,6 +104,9 @@
+- 		case FILTER_TYPE_ANNOTATION:
+- 			f = new AnnotateFilter;
+- 			break;	
+-+		case FILTER_TYPE_TEMPLATE:
+-+			f = new TemplateFilter;
+-+			break;	
+- 		default:
+- 			ASSERT(false);
+- 	}
+-diff -r e500a2602f86 src/backend/filters/allFilter.h
+---- a/src/backend/filters/allFilter.h	Sun Jul 20 15:44:52 2014 +0100
+-+++ b/src/backend/filters/allFilter.h	Sun Jul 20 15:49:30 2014 +0100
+-@@ -32,6 +32,7 @@
+- #include "voxelise.h"
+- #include "ionInfo.h"
+- #include "annotation.h"
+-+#include "filterTemplate.h"
+- 
+- //!Returns true if the string is a valid filter name
+- bool isValidFilterName(const std::string &s);
+-diff -r e500a2602f86 src/gui/mainFrame.cpp
+---- a/src/gui/mainFrame.cpp	Sun Jul 20 15:44:52 2014 +0100
+-+++ b/src/gui/mainFrame.cpp	Sun Jul 20 15:49:30 2014 +0100
+-@@ -116,7 +116,7 @@
+- //MainFrame's constructor
+- 
+- //--- These settings must be modified concomitantly.
+--const unsigned int FILTER_DROP_COUNT=14;
+-+const unsigned int FILTER_DROP_COUNT=15;
+- 
+- const char * comboFilters_choices[FILTER_DROP_COUNT] =
+- {
+-@@ -134,6 +134,7 @@
+- 	NTRANS("Range File"),
+- 	NTRANS("Spat. Analysis"),
+- 	NTRANS("Voxelisation"),
+-+	NTRANS("Template")
+- };
+- 
+- //Mapping between filter ID and combo position
+-@@ -152,6 +153,7 @@
+- 	FILTER_TYPE_RANGEFILE,
+- 	FILTER_TYPE_SPATIAL_ANALYSIS,
+- 	FILTER_TYPE_VOXELS,
+-+	FILTER_TYPE_TEMPLATE,
+-  };
+- //----
+- 
+diff -r 036cf664e28d src/Makefile.am
+--- a/src/Makefile.am	Sun Aug 24 14:17:50 2014 +0100
++++ b/src/Makefile.am	Sun Aug 24 14:18:26 2014 +0100
+@@ -38,7 +38,7 @@
+ 		backend/filters/compositionProfile.cpp backend/filters/spatialAnalysis.cpp \
+ 		backend/filters/clusterAnalysis.cpp backend/filters/ionInfo.cpp \
+ 		backend/filters/annotation.cpp backend/filters/geometryHelpers.cpp \
+-		backend/filters/algorithms/binomial.cpp  
++		backend/filters/algorithms/binomial.cpp  backend/filters/filterTemplate.cpp 
+ 
+ FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h \
+ 		backend/filters/dataLoad.h backend/filters/ionDownsample.h \
+@@ -48,7 +48,7 @@
+ 		backend/filters/compositionProfile.h backend/filters/spatialAnalysis.h \
+ 		backend/filters/clusterAnalysis.h backend/filters/ionInfo.h \
+ 		backend/filters/annotation.h backend/filters/geometryHelpers.h \
+-		backend/filters/algorithms/binomial.h 
++		backend/filters/algorithms/binomial.h backend/filters/algorithms/filterTemplate.h
+ 
+ BACKEND_SOURCE_FILES = backend/animator.cpp backend/filtertreeAnalyse.cpp backend/filtertree.cpp \
+ 		     	backend/APT/ionhit.cpp backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp backend/APT/abundanceParser.cpp \
+diff -r 036cf664e28d src/backend/filter.cpp
+--- a/src/backend/filter.cpp	Sun Aug 24 14:17:50 2014 +0100
++++ b/src/backend/filter.cpp	Sun Aug 24 14:18:26 2014 +0100
+@@ -63,7 +63,8 @@
+ 				"clusteranalysis",
+ 				"voxelise",
+ 				"ioninfo",
+-				"annotation"
++				"annotation",
++				"template"
+ 				};
+ 
+ size_t numElements(const vector<const FilterStreamData *> &v, unsigned int mask)
+diff -r 036cf664e28d src/backend/filter.h
+--- a/src/backend/filter.h	Sun Aug 24 14:17:50 2014 +0100
++++ b/src/backend/filter.h	Sun Aug 24 14:18:26 2014 +0100
+@@ -71,6 +71,7 @@
+ 	FILTER_TYPE_VOXELS,
+ 	FILTER_TYPE_IONINFO,
+ 	FILTER_TYPE_ANNOTATION,
++	FILTER_TYPE_TEMPLATE,
+ 	FILTER_TYPE_ENUM_END // not a filter. just end of enum
+ };
+ 
+diff -r 036cf664e28d src/backend/filters/allFilter.cpp
+--- a/src/backend/filters/allFilter.cpp	Sun Aug 24 14:17:50 2014 +0100
++++ b/src/backend/filters/allFilter.cpp	Sun Aug 24 14:18:26 2014 +0100
+@@ -104,6 +104,9 @@
+ 		case FILTER_TYPE_ANNOTATION:
+ 			f = new AnnotateFilter;
+ 			break;	
++		case FILTER_TYPE_TEMPLATE:
++			f = new TemplateFilter;
++			break;	
+ 		default:
+ 			ASSERT(false);
+ 	}
+diff -r 036cf664e28d src/backend/filters/allFilter.h
+--- a/src/backend/filters/allFilter.h	Sun Aug 24 14:17:50 2014 +0100
++++ b/src/backend/filters/allFilter.h	Sun Aug 24 14:18:26 2014 +0100
+@@ -32,6 +32,7 @@
+ #include "voxelise.h"
+ #include "ionInfo.h"
+ #include "annotation.h"
++#include "filterTemplate.h"
+ 
+ //!Returns true if the string is a valid filter name
+ bool isValidFilterName(const std::string &s);
+diff -r 036cf664e28d src/gui/mainFrame.cpp
+--- a/src/gui/mainFrame.cpp	Sun Aug 24 14:17:50 2014 +0100
++++ b/src/gui/mainFrame.cpp	Sun Aug 24 14:18:26 2014 +0100
+@@ -121,7 +121,7 @@
+ //MainFrame's constructor
+ 
+ //--- These settings must be modified concomitantly.
+-const unsigned int FILTER_DROP_COUNT=14;
++const unsigned int FILTER_DROP_COUNT=15;
+ 
+ const char * comboFilters_choices[FILTER_DROP_COUNT] =
+ {
+@@ -139,6 +139,7 @@
+ 	NTRANS("Range File"),
+ 	NTRANS("Spat. Analysis"),
+ 	NTRANS("Voxelisation"),
++	NTRANS("Template")
+ };
+ 
+ //Mapping between filter ID and combo position
+@@ -157,6 +158,7 @@
+ 	FILTER_TYPE_RANGEFILE,
+ 	FILTER_TYPE_SPATIAL_ANALYSIS,
+ 	FILTER_TYPE_VOXELS,
++	FILTER_TYPE_TEMPLATE,
+  };
+ //----
+ 
diff --git a/docs/manual-latex/figures/Screenshot-thumb.png b/docs/manual-latex/figures/Screenshot-thumb.png
new file mode 100644
index 0000000..ad53949
Binary files /dev/null and b/docs/manual-latex/figures/Screenshot-thumb.png differ
diff --git a/docs/manual-latex/manual.blg b/docs/manual-latex/manual.blg
index 6f03a0c..2d3519b 100644
--- a/docs/manual-latex/manual.blg
+++ b/docs/manual-latex/manual.blg
@@ -1,4 +1,4 @@
-This is BibTeX, Version 0.99d (TeX Live 2013/Debian)
+This is BibTeX, Version 0.99d (TeX Live 2014/Debian)
 Capacity: max_strings=35307, hash_size=35307, hash_prime=30011
 The top-level auxiliary file: manual.aux
 The style file: unsrt.bst
diff --git a/docs/manual-latex/manual.log b/docs/manual-latex/manual.log
index 6eb8f8e..38771a5 100644
--- a/docs/manual-latex/manual.log
+++ b/docs/manual-latex/manual.log
@@ -1,10 +1,10 @@
-This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013/Debian) (format=pdflatex 2014.4.17)  17 APR 2014 22:03
+This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014/Debian) (preloaded format=pdflatex 2014.6.29)  2 AUG 2014 00:59
 entering extended mode
  restricted \write18 enabled.
  %&-line parsing enabled.
 **manual.tex
 (./manual.tex
-LaTeX2e <2011/06/27>
+LaTeX2e <2014/05/01>
 Babel <3.9k> and hyphenation patterns for 2 languages loaded.
 (/usr/share/texlive/texmf-dist/tex/latex/base/article.cls
 Document Class: article 2007/10/19 v1.4h Standard LaTeX document class
@@ -28,10 +28,10 @@ Package: fullpage 1999/02/23 1.1 (PWD)
 \FP at margin=\skip43
 )
 (/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty
-Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR)
+Package: graphicx 2014/04/25 v1.0g Enhanced LaTeX Graphics (DPC,SPQR)
 
 (/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty
-Package: keyval 1999/03/16 v1.13 key=value parser (DPC)
+Package: keyval 2014/05/08 v1.15 key=value parser (DPC)
 \KV at toks@=\toks14
 )
 (/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty
@@ -555,13 +555,12 @@ Package pdftex.def Info: ./figures/externalProgBash.png used on input line 1601
  [47 <./figures/externalProgBash.png>]
 LaTeX Font Info:    Try loading font information for OMS+cmtt on input line 165
 8.
+LaTeX Font Info:    No file OMScmtt.fd. on input line 1658.
 
-(/usr/share/texmf/tex/latex/R/tex/latex/omscmtt.fd
-File: omscmtt.fd 
-)
-LaTeX Font Info:    Font shape `OMS/cmtt/m/n' in size <10> not available
-(Font)              Font shape `OMS/cmsy/m/n' tried instead on input line 1658.
 
+LaTeX Font Warning: Font shape `OMS/cmtt/m/n' undefined
+(Font)              using `OMS/cmsy/m/n' instead
+(Font)              for symbol `textbraceleft' on input line 1658.
 
 <./figures/externalProgCpp.png, id=1502, 2123.935pt x 839.135pt>
 File: ./figures/externalProgCpp.png Graphic file (type png)
@@ -583,6 +582,9 @@ Package rerunfilecheck Info: File `manual.out' has not changed.
 (rerunfilecheck)             Checksum: 5D9DF5F8101C21D1BE54E57385EA4596;5634.
 
 
+LaTeX Font Warning: Some font shapes were not available, defaults substituted.
+
+
 LaTeX Warning: There were undefined references.
 
 
@@ -591,10 +593,10 @@ LaTeX Warning: Label(s) may have changed. Rerun to get cross-references right.
 Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 1911.
  ) 
 Here is how much of TeX's memory you used:
- 5708 strings out of 495028
- 87083 string characters out of 6181497
- 165098 words of memory out of 5000000
- 8634 multiletter control sequences out of 15000+600000
+ 5698 strings out of 495021
+ 86846 string characters out of 6181344
+ 165106 words of memory out of 5000000
+ 8630 multiletter control sequences out of 15000+600000
  13156 words of font info for 46 fonts, out of 8000000 for 9000
  14 hyphenation exceptions out of 8191
  29i,11n,28p,1058b,447s stack positions out of 5000i,500n,10000p,200000b,80000s
@@ -615,7 +617,7 @@ re/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmti8.pfb></usr/share/texl
 ive/texmf-dist/fonts/type1/public/amsfonts/cm/cmtt10.pfb></usr/share/texlive/te
 xmf-dist/fonts/type1/public/amsfonts/cm/cmtt12.pfb></usr/share/texlive/texmf-di
 st/fonts/type1/public/amsfonts/cm/cmtt8.pfb>
-Output written on manual.pdf (59 pages, 4517180 bytes).
+Output written on manual.pdf (59 pages, 4550865 bytes).
 PDF statistics:
  1660 PDF objects out of 1728 (max. 8388607)
  1281 compressed objects within 13 object streams
diff --git a/docs/manual-latex/manual.pdf b/docs/manual-latex/manual.pdf
index b81c71a..fef3e72 100644
Binary files a/docs/manual-latex/manual.pdf and b/docs/manual-latex/manual.pdf differ
diff --git a/docs/manual-latex/manual.tex b/docs/manual-latex/manual.tex
index 5f4f518..26d9ee5 100644
--- a/docs/manual-latex/manual.tex
+++ b/docs/manual-latex/manual.tex
@@ -40,7 +40,7 @@
 \begin{minipage}{0.3\textwidth}
 \begin{flushright} \large
 \emph{Version:} \\
- 0.0.16, Apr 2014\end{flushright}
+ 0.0.17, Sep 2014\end{flushright}
 \end{minipage}
 
 \vfill
@@ -53,7 +53,7 @@
 \tableofcontents
 \clearpage
 \pagenumbering{arabic}
-\title{3Depict -- Valued point cloud visualisation and analysis}
+\title{3Depict -- Visualisation and Analysis for Atom Probe}
 
 \widowpenalty = 10000
 
@@ -62,7 +62,7 @@
 \section{Foreword}
 \subsection{Introduction}
 
-\emph{3Depict} is an open source computer program designed for the analysis of point clouds with an associated scalar value. The program is designed around interactive data analysis, with a view to combine rapid feedback, ease of use and flexibility in a single system.  At time of writing, \emph{3Depict} is in the so-called ``alpha'' prototyping stage, and should be used where helpful, but may contain rough-edges.
+\emph{3Depict} is an open source computer program designed for the analysis of point clouds with an associated scalar value. The software is designed around interactive data analysis, with a view to combine rapid feedback, ease of use and flexibility in a single system.  At time of writing, \emph{3Depict} is in the so-called ``alpha'' prototyping stage, and should be used where helpful, but may contain rough-edges.
 
 \emph{3Depict} is designed purely for post-processing of 3D point data, and was originally primarily targeted to users of Atom Probe Tomography. Other users (\emph{e.g.} in astronomical, geospatial or digital preservation fields) may find the program useful, and are encouraged to seek assistance. 
  
diff --git a/docs/web/about.html b/docs/web/about.html
index 5bbb4a1..e2e973f 100644
--- a/docs/web/about.html
+++ b/docs/web/about.html
@@ -7,6 +7,9 @@
 
 	<title>About 3Depict </title> 
 	<link rel="stylesheet" href="style.css" type="text/css"/>
+	<link rel="icon" type="image/png" href="favicon.png"/>
+
+
 </head>
 
 <body>
diff --git a/docs/web/compiling-OSX.html b/docs/web/compiling-OSX.html
new file mode 100644
index 0000000..56dc075
--- /dev/null
+++ b/docs/web/compiling-OSX.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"/>
+<link rel="stylesheet" href="style.css" type="text/css"/>
+<link rel="icon" type="image/png" href="favicon.png"/>
+
+<title>compiling.html</title></head><body>
+<div id="header">
+<h1>3Depict - Valued point cloud visualisation and analysis</h1>
+<ul id="nav">
+	<li><a href="index.html">Home</a></li>
+	<li><a href="download.html">Download</a></li>
+	<li><a href="questions.html">Questions</a></li>
+	<li><a href="documentation.html">Documentation</a></li>
+	<li><a href="contact.html">Contact</a></li>
+	<li><a href="about.html">About</a></li>
+</ul>
+</div>
+
+<div id="left">
+<div class="box">
+<h2>Get the code</h2>
+<p> <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code for the latest version of 3Depict for your platform.</p> Alternately, download the latest <a href="http://sourceforge.net/p/threedepict/code/ci/default/tree/">development version</a>.
+</div>
+<div class="box">
+<h3>Stuck on how to compile?</h3>
+Try asking for help on the <a href="https://sourceforge.net/apps/phpbb/threedepict/">forums</a>
+<p></p>
+</div>
+<center>
+<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=341003&type=2" alt="SourceForge.net Logo" border="0" height="37"/></a>
+</center>
+</div>
+<div id="content">
+<div id="right">
+
+<h1> Preface </h1>
+
+Mac OSX is currently a "contributed" build platform, and thus the build systems are more rough than for other systems. Some scripts are provided to smooth the process, however these may be out of date. The developers cannot continuously build this platform, as it is against the OSX licence to run OSX on virtual machines. Cross-compilation is not readily feasible either. If you can assist in building for this platform, please <a href="contact.html">contact us</a>.
+
+<h1>Compiling</h1>
+
+Mac OS does not have a proper package management system. You need XCode installed (<a href="http://developer.apple.com/mac/library/documentation/Xcode/Conceptual/XcodeCoexistence/Contents/Resources/en.lproj/Basics/Basics.html">here</a>). For the latest version of OSX for some reason this is not quite free, and you now are required to use the app store or something to get this or build gcc yourself (somehow) it appears. So we can't easily automate this procedure for you.
+
+Considering GCC (the bit we need) is completely free (GPL), it is unclear what the deal is here. To make matters more complex, there are <i>two</i> compilers (clang & GCC)  and <i>two</i> standard libraries (libstdc++ and libc++), all of which are incompatible with the alternate. This means you must compile everything with the same compiler the whole time - read <a href="https://trac.macports.org/wiki/UsingTheRightCompiler">here</a> for how to do this (macports & local). Check to mak [...]
+
+Note that at time of writing the wxWidgets version provided with XCode is several years out-of-date and won't work. Please don't try to use any of the built-in libraries provided with XCode - firstly, you cannot mix and match library linkage, it simply won't work (crashes) and secondly they are all very out of date.  In fact, using XCode at all is highly discouraged, due to its poor portability, and the difficultly scripting solutions and debugging problems.
+
+<br/>
+
+There is an automatic dependency grabbing script in the 3Depict source
+code under the "deps" folder. Run that (ensure you are connected to the
+Internet) to automatically download, build and install all the software
+dependencies. If it does not work, this is a bug, so let us know.<br/>
+
+<br/>
+To run the script, simply open terminal.app, navigate to the "packaging/deps" folder containing "getDeps", then type:<br/>
+<br/>
+<span style="font-family: monospace;">$ ./getDeps</span><br/>
+
+<br/>
+This will check your system for a compiler, and then will proceed to download and install the needed components in an automatic fashion. The compilation process can take several hours.<br/>
+<br/>
+
+<h2>Packaging</2>
+Due to some design decisions under OSX, programs cannot be directly run, but first must be packaged. Attempts to run programs without creating the <a href="http://wiki.wxwidgets.org/WxMac-specific_topics#Building_a_MacOSX_application_bundle">".app package"</a> (actually a folder with metadata), will cause the program to function incorrectly (eg user input will be ignored).
+
+To aid compilation and packaging, use the "3package.sh" script in the "packaging/mac" folder. Execute this to build and package the program. In this way, a .app package should be built and ready for use.
+
+</div></div>
+
+</body></html>
diff --git a/docs/web/compiling-cross.html b/docs/web/compiling-cross.html
new file mode 100644
index 0000000..e8bb836
--- /dev/null
+++ b/docs/web/compiling-cross.html
@@ -0,0 +1,56 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"/>
+<link rel="stylesheet" href="style.css" type="text/css"/>
+<link rel="icon" type="image/png" href="favicon.png"/>
+
+<title>compiling.html</title></head><body>
+<div id="header">
+<h1>3Depict - Valued point cloud visualisation and analysis</h1>
+<ul id="nav">
+	<li><a href="index.html">Home</a></li>
+	<li><a href="download.html">Download</a></li>
+	<li><a href="questions.html">Questions</a></li>
+	<li><a href="documentation.html">Documentation</a></li>
+	<li><a href="contact.html">Contact</a></li>
+	<li><a href="about.html">About</a></li>
+</ul>
+</div>
+
+<div id="left">
+<div class="box">
+<h2>Get the code</h2>
+<p> <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code for the latest version of 3Depict for your platform.</p> Alternately, download the latest <a href="http://sourceforge.net/p/threedepict/code/ci/default/tree/">development version</a>.
+</div>
+<div class="box">
+<h3>Stuck on how to compile?</h3>
+Try asking for help on the <a href="https://sourceforge.net/apps/phpbb/threedepict/">forums</a>
+<p></p>
+</div>
+<center>
+<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=341003&type=2" alt="SourceForge.net Logo" border="0" height="37"/></a>
+</center>
+</div>
+<div id="content">
+<div id="right">
+
+<h1>Cross Compilation</h1>
+
+<p>Compiling under windows is quite tricky.  Compiling for windows under a Linux environment is significantly easier. Easier still, we have automated the procedure to build windows executables via a technique known as <a href="https://en.wikipedia.org/wiki/Cross_compiler">Cross compiling</a>. This technique is used for the official 3Depict builds.</p>
+
+<p>To run the cross compilation script, you must first have an installed Debian-like Linux system. We recommend "Debian", however you can probably use Linux Mint or Ubuntu. We have not tried these. </p>
+
+<p>For windows users, you can install a <a href="http://www.brianlinkletter.com/installing-debian-linux-in-a-virtualbox-virtual-machine/">virtual machine</a> to do the trick, then start the build. Make sure you allocate lots of RAM and disk space (>8GB ram or swap needed, >10GB disk space recommended), to ensure the build works. On older machines, you may need to <a href="http://www.sysprobs.com/disable-enable-virtualization-technology-bios">enable</a> virtual machine access in the <a hr [...]
+
+
+<h1> Procedure</h1>
+<p>Having downloaded the source code, copy the <span style="font-family: monospace;">./packaging/mingw-debian-cross/</span> folder to your home directory, eg <span style="font-family: monospace;">/home/user/mingw-debian-cross/</span>. Once done, create a folder called <span style="font-family: monospace;">code</span> inside <span style="font-family: monospace;">mingw-debian-cross/</span>. This is case sensitive. Copy the <span style="font-family: monospace;">3Depict</span> folder into th [...]
+
+<p>Now run the  <span style="font-family: monospace;">bootstrap.sh</span> script to execute the cross-compilation - the process can take several hours on a standard system to execute a full build. On the first run you will be asked whether you wish to compile for 32 or 64 bit windows. Once complete, you will be given a 3Depict-VERSION-BIT.exe file that you can use under windows. </p>
+
+To get the file out of your virtual machine, we recommend using a USB key. Plug the USB key in, then select it in your virtual machine, and copy the file over. It is possible to also do this by drag and drop onto your desktop, but you need to enable the virtual machine's <a href="http://www.virtualbox.org/manual/ch04.html">guest additions</a>. This can be a tricky process in itself, so it is not recommended. Many other methods of copying the file are possible, but not discussed here.</p>
+</div></div>
+
+</body></html>
diff --git a/docs/web/compiling-linux.html b/docs/web/compiling-linux.html
new file mode 100644
index 0000000..eb1ee82
--- /dev/null
+++ b/docs/web/compiling-linux.html
@@ -0,0 +1,153 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"/>
+<link rel="stylesheet" href="style.css" type="text/css"/>
+<link rel="icon" type="image/png" href="favicon.png"/>
+
+<title>compiling.html</title></head><body>
+<div id="header">
+<h1>3Depict - Valued point cloud visualisation and analysis</h1>
+<ul id="nav">
+	<li><a href="index.html">Home</a></li>
+	<li><a href="download.html">Download</a></li>
+	<li><a href="questions.html">Questions</a></li>
+	<li><a href="documentation.html">Documentation</a></li>
+	<li><a href="contact.html">Contact</a></li>
+	<li><a href="about.html">About</a></li>
+</ul>
+</div>
+
+<div id="left">
+<div class="box">
+<h2>Get the code</h2>
+<p> <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code for the latest version of 3Depict for your platform.</p> Alternately, download the latest <a href="http://sourceforge.net/p/threedepict/code/ci/default/tree/">development version</a>.
+</div>
+<div class="box">
+<h3>Stuck on how to compile?</h3>
+Try asking for help on the <a href="https://sourceforge.net/apps/phpbb/threedepict/">forums</a>
+<p></p>
+</div>
+<center>
+<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=341003&type=2" alt="SourceForge.net Logo" border="0" height="37"/></a>
+</center>
+</div>
+<div id="content">
+<div id="right">
+
+<h1>Compiling for Linux</h1>
+
+
+<p>
+
+
+In the following instructions, <span style="text-decoration: underline; font-family: monospace;">$</span> and <span style="text-decoration: underline; font-family: monospace;">#</span> indicate to enter command at a command prompt, as either a normal user or as an <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Root_user">administrator</a>. Do not type the <span style="font-family: monospace;">$</span> or <span style="font-family: monospace;">#</span> when entering the commands.  [...]
+</p>
+<p>
+If there are any problems or flaws with the instructions, please <a href="contact.html">contact the author</a>.
+</p>
+
+<h2> Installing dependencies</h2>
+<h3>Automatic dependancy retrieval</h3>
+<p>
+An experimental script "getDeps" is supplied in the <i>packaging/deps/</i> folder. Run this script to automatically detect your platform and download and install the required dependencies.</p>
+
+<p>
+Alternately, use the following instructions:</p>
+
+
+<h3>Debian and derivatives</h3>
+Debian Linux and its derivatives (Linux Mint, Ubuntu, etc), can use the following procedure.
+To build 3Depict, you need to install the following packages:
+<ul>
+<li>build-essential</li>
+<li>libwxgtk2.8-dev</li>
+<li>libmgl-dev</li>
+<li>libxml2-dev</li>
+<li>libftgl-dev</li>
+<li>libqhull-dev</li>
+</ul>
+
+
+This can be done through the command line (below), or using the gui (synaptic package manager)<br/>
+
+<br/>
+
+<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> sudo apt-get build-dep 3depict </span><br/>
+
+
+
+<h3>Fedora/RedHat:</h3>
+
+<ul>
+<li>"Development Tools"  group package</li>
+<li>mathgl-devel</li>
+<li>libxml2-devel</li>
+<li>ftgl-devel</li>
+<li>wxgtk-devel</li>
+<li>qhull-devel</li>
+
+</ul>
+
+
+This can be done through either the command line, or through the GUI <br/>
+
+<br/>
+
+
+<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> yum groupinstall "Development Tools"</span><br/>
+
+<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> yum install mathgl-devel libxml2-devel ftgl-devel wxgtk-devel qhull-devel</span><br/>
+<br/>
+
+<h3>OpenSuse:</h3>
+<i>These instructions may be slightly out of date</i>
+<ul>
+<li>wxGTK-devel</li>
+<li>libxml2-devel</li>
+<li>ftgl-devel</li>
+<li>qhull-devel</li>
+</ul>
+
+
+This can be done either through the graphical interface (YaST) or at the command line.<br/>
+
+<br/>
+
+
+<span style="font-family: monospace;">    $ zypper install -t devel_C_C++</span><br/>
+
+<span style="font-family: monospace;">    $ zypper install wxGTK-devel libxml2-devel ftgl-devel qhull-devel</span><br/>
+
+    <br/>
+
+Unfortunately, mathgl is not available as a pre-built package for Suse.
+You must therefore download and install it manually from the mathgl
+website:<br/>
+
+<ul>
+<li><a href="http://mathgl.sourceforge.net/">http://mathgl.sourceforge.net/</a></li>
+</ul>
+
+</ul>
+
+
+<h2> Compiling</h2>
+<p>
+To compile 3Depict, ensure you have installed all the required dependencies (above), then use the following commands in the 3Depict/ directory:</p>
+
+<p>
+<span style="font-family: monospace;">    $ ./configure</span> <br/><br/> Optionally, you may use <span style="font-family: monospace;">--enable-openmp-parallel</span> or <span style="font-family: monospace;">--disable-debug-checks</span> to enable parallelism or disable debug checks respectively. <br/>
+<span style="font-family: monospace;">    $ make</span><br/>to build 3depict.<br/><br/>
+
+Once built, you can install the program with:
+<span style="font-family: monospace;">make install</span></p>
+
+
+<h2> Compiling under eclipse</h2>
+Although not officially supported, some users report being able to compile 3Depict under the eclipse IDE. You can read more about the method on the <a href="http://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=26">forums</a>.
+
+
+</div></div>
+</body></html>
diff --git a/docs/web/compiling-macosx.html b/docs/web/compiling-macosx.html
new file mode 100644
index 0000000..1db56a9
--- /dev/null
+++ b/docs/web/compiling-macosx.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+
+<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"/>
+<link rel="stylesheet" href="style.css" type="text/css"/>
+<link rel="icon" type="image/png" href="favicon.png"/>
+
+<title>compiling.html</title></head><body>
+<div id="header">
+<h1>3Depict - Valued point cloud visualisation and analysis</h1>
+<ul id="nav">
+	<li><a href="index.html">Home</a></li>
+
+	<li><a href="download.html">Download</a></li>
+	<li><a href="questions.html">Questions</a></li>
+	<li><a href="documentation.html">Documentation</a></li>
+	<li><a href="contact.html">Contact</a></li>
+	<li><a href="about.html">About</a></li>
+</ul>
+</div>
+
+<div id="left">
+<div class="box">
+<h2>Get the code</h2>
+<p> <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code for the latest version of 3Depict for your platform.</p> Alternately, download the latest <a href="http://sourceforge.net/p/threedepict/code/ci/default/tree/">development version</a>.
+</div>
+<div class="box">
+<h3>Stuck on how to compile?</h3>
+
+Try asking for help on the <a href="https://sourceforge.net/apps/phpbb/threedepict/">forums</a>
+<p></p>
+</div>
+<center>
+<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=341003&type=2" alt="SourceForge.net Logo" border="0" height="37"/></a>
+</center>
+</div>
+<div id="content">
+<div id="right">
+
+<h1> Preface </h1>
+
+Mac OSX is currently a "contributed" build platform, and thus the build systems are more rough than for other systems. Some scripts are provided to smooth the process, however these may be out of date. The developers cannot continuously build this platform, as it is against the OSX licence to run OSX on virtual machines. Cross-compilation is not readily feasible either. If you can assist in building for this platform, please <a href="contact.html">contact us</a>.
+
+
+<h1>Compiling</h1>
+<h2>Dependencies</h2>
+Mac OS does not have a proper package management system. You need XCode installed (<a href="http://developer.apple.com/mac/library/documentation/Xcode/Conceptual/XcodeCoexistence/Contents/Resources/en.lproj/Basics/Basics.html">here</a>). For the latest version of OSX for some reason this is not quite free, and you now are required to use the app store or something to get this or build gcc yourself (somehow) it appears. So we can't easily automate this procedure for you.
+
+Considering GCC (the bit we need) is completely free (GPL), it is unclear what the deal is here.
+
+Note that at time of writing the wxWidgets version provided with XCode is several years out-of-date and won't work. Please don't try to use any of the built-in libraries provided with XCode - firstly, you cannot mix and match library linkage, it simply won't work (crashes) and secondly they are all very out of date. 
+
+<br/>
+
+There is an automatic dependency grabbing script in the 3Depict source
+code under the "deps" folder. Run that (ensure you are connected to the
+Internet) to automatically download, build and install all the software
+dependencies. If it does not work, this is a bug, so let us know.<br/>
+
+<br/>
+To run the script, simply open terminal.app, navigate to the "packaging/deps" folder containing "getDeps", then type:<br/>
+<br/>
+<span style="font-family: monospace;">$ ./getDeps</span><br/>
+
+<br/>
+This will check your system for a compiler, and then will proceed to download and install the needed components in an automatic fashion. The compilation process can take several hours.<br/>
+<br/>
+
+<h2>Building and Packaging</h2>
+Due to some design decisions under OSX, programs cannot be directly run, but first must be packaged. Attempts to run programs without creating the ".app package" (actually a folder with metadata), will cause the program to function incorrectly (eg user input will be ignored).
+
+To aid compilation and packaging, use the "3package.sh" script in the "packaging/mac" folder. Execute this to build and package the program. In this way, a .app package should be built and ready for use.
+
+</div></div>
+
+</body></html>
+
diff --git a/docs/web/compiling.html b/docs/web/compiling.html
index 822623d..ecad8f9 100644
--- a/docs/web/compiling.html
+++ b/docs/web/compiling.html
@@ -4,6 +4,7 @@
 
 <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"/>
 <link rel="stylesheet" href="style.css" type="text/css"/>
+<link rel="icon" type="image/png" href="favicon.png"/>
 
 <title>compiling.html</title></head><body>
 <div id="header">
@@ -20,8 +21,8 @@
 
 <div id="left">
 <div class="box">
-<h2> Latest version: 0.0.13</h2>
-<p> <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code for the latest version of 3Depict for your platform</p>
+<h2>Get the code</h2>
+<p> <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code for the latest version of 3Depict for your platform.</p> Alternately, download the latest <a href="http://sourceforge.net/p/threedepict/code/ci/default/tree/">development version</a>.
 </div>
 <div class="box">
 <h3>Stuck on how to compile?</h3>
@@ -49,39 +50,14 @@ this is a limited and typically slow method of communication.<br/>
 
 Looking for an easier install? <a href="download.html">Check</a> to see if your platform is supported. If it is not supported, you can <a href="contact.html">contact the author</a> for other options.<br/><br/>
 <hr/>
-<h2>Getting started<br/>
-
-
-</h2>
-
-This project uses <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Autotools">autotools</a> to manage system configuration and program
-dependency information, so if you know what that means and you are
-running Linux, just do as per normal after installing dependencies
-(.<span style="font-family: monospace;">/configure && make && make install</span>). <br/>
-<br/>
-Due to a missing build environment, building under
-windows is highly complicated, and more thoroughly documented <a href="#windows">below</a>.<br/>
-<br/>
-
-
-Direct <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Software_library">Dependencies</a>: <br/>
-
-<ul>
-<li><a href="http://sourceforge.net/projects/ftgl/">ftgl</a></li>
-<li><a href="http://freetype.org/">freetype2</a></li>
-<li><a href="http://www.xmlsoft.org/">libxml2</a></li>
-<li><a href="http://mathgl.sourceforge.net/">mathgl</a></li>
-<li><a href="http://wxwidgets.org/">wxwidgets</a></li>
-<li><a href="http://www.gnu.org/software/gettext/">gettext</a></li>
-<li><a href="http://www.qhull.org/">qhull</a></li>
-</ul>
-
+<h2>Getting started</h2>
 
 There are two main stages to compiling, <br/>
 
 
 <ul>
-<li>setting up your computer to be able to build, and </li><li>actually building the program.</li>
+<li>setting up your computer to be able to build, and 
+</li><li>actually building the program.</li>
 </ul>
 
 
@@ -89,503 +65,27 @@ There are two main stages to compiling, <br/>
 In the following instructions, <span style="text-decoration: underline; font-family: monospace;">$</span> and <span style="text-decoration: underline; font-family: monospace;">#</span> indicate to enter command at a command prompt, as either a normal user or as an <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Root_user">administrator</a>. Do not type the <span style="font-family: monospace;">$</span> or <span style="font-family: monospace;">#</span> when entering the commands.  [...]
 <br/>
 
-If there are any problems or flaws with the instructions, please <a href="contact.html">contact the author</a><br/><br/>
+If there are any problems or flaws with the instructions, please <a href="contact.html">contact the author</a>
 
 <h2>Get the code</h2>
-Either <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code (<a href="https://secure.wikimedia.org/wikipedia/en/wiki/Tar.gz">.tar.gz</a> file ), or grab the <a href="http://mercurial.selenic.com">mercurial</a> repository using this clone command, or by opening the URL in your graphical mercurial client (the URL is the bit at the right)
-<br/>
-<br/>
-<span style="font-family: monospace;">$ hg clone http://threedepict.hg.sourceforge.net:8000/hgroot/threedepict/threedepict</span>
-<br/>
-<br/>
-You should then install the following packages (this requires administrative rights to your machine).:<br/>
-<br/>
-
-
-<h2>Setting up</h2>
-<h3>Debian/Ubuntu:</h3>
-<ul>
-<li>build-essential</li><li>libwxgtk2.8-dev</li><li>libmgl-dev</li><li>libxml2-dev</li><li>libftgl-dev</li><li>libqhull-dev</li>
-</ul>
-
-
-This can be done through the command line (below), or using the gui (synaptic package manager)<br/>
-
-<br/>
-
-<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> sudo apt-get build-dep 3depict </span><br/>
-
-
-<h3>Fedora/RedHat:</h3>
-
-<ul>
-<li>"Development Tools"  group package</li><li>mathgl-devel</li><li>libxml2-devel</li><li>ftgl-devel</li><li>wxgtk-devel</li><li>qhull-devel</li>
-</ul>
-
-
-This can be done through either the command line, or through the GUI <br/>
-
-<br/>
-
-
-<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> yum groupinstall "Development Tools"</span><br/>
-
-<span style="text-decoration: underline; font-family: monospace;">$</span><span style="font-family: monospace;"> yum install mathgl-devel libxml2-devel ftgl-devel wxgtk-devel qhull-devel</span><br/>
-<br/>
-
-<h3>OpenSuse:</h3>
-
-<ul>
-<li>wxGTK-devel</li><li>libxml2-devel</li><li>ftgl-devel</li><li>qhull-devel</li>
-</ul>
-
-
-
-This can be done either through the graphical interface (YaST) or at the command line.<br/>
-
-<br/>
-
-
-<span style="font-family: monospace;">    $ zypper install -t devel_C_C++</span><br/>
-
-<span style="font-family: monospace;">    $ zypper install wxGTK-devel libxml2-devel ftgl-devel qhull-devel</span><br/>
-
-    <br/>
-
-Unfortunately, mathgl is not available as a pre-built package for Suse.
-You must therefore download and install it manually from the mathgl
-website:<br/>
-
-<ul>
-<li><a href="http://mathgl.sourceforge.net/">http://mathgl.sourceforge.net/</a></li>
-</ul>
-
-<h4> Cross compiling</h4>
-There is a cross compilation script available (0.0.13) in the packaging/mingw-debian-cross/ folder of the <a href="http://threedepict.hg.sourceforge.net/hgweb/threedepict/threedepict/summary">code repository</a>. This can be used to build 3Depict for windows platforms using a Debian or Debian-like host. The cross-compilation script is experimental, but will get you most of the way to a cross compiled version.  The script will download, patch and build all the neccessary dependencies auto [...]
-
-<br/>
-
-
-<h3>Mac OS X</h3>
-
-Mac OS does not have a proper package management system. You need XCode installed (<a href="http://developer.apple.com/mac/library/documentation/Xcode/Conceptual/XcodeCoexistence/Contents/Resources/en.lproj/Basics/Basics.html">here</a>). For the latest version of Snow Leopard for some reason this is not free, and you now are required to use the app store or something to get this or build gcc yourself (somehow) it appears. Considering GCC (the bit we need) is completely free (GPL), it is  [...]
-Note that at time of writing the wxWidgets version provided with XCode is several years out-of-date and probably won't work. Please don't try to use any of the built-in libraries provided with XCode - you cannot mix and match library linkage, it simply won't work (crashes). There are some <a href="#Extra_notes_for_Mac_OSX">post-compile notes</a>, which <span style="font-weight: bold; font-style: italic;">must</span>  be followed to build a usable program.<br/>
-
-<br/>
-
-There is an automatic dependency grabbing script in the 3Depict source
-code under the "deps" folder. Run that (ensure you are connected to the
-Internet) to automatically download, build and install all the software
-dependencies. If it does not work, this is a bug, so let me know. <br/>
-<br/>
-To run the script, simply open terminal.app, navigate to the correct folder containing "getDeps", then type:<br/>
-<br/>
-<span style="font-family: monospace;">$ ./getDeps</span><br/>
-
-<br/>
-This will check your system for a compiler, and then will proceed to download and install the needed components in an automatic fashion.<br/>
-<br/>
-
-
-<h3><a name="From_Source_setup"></a>From Source (All  other platforms)</h3>
-For platforms not listed above (including windows), dependency source
-compiling is the way to go if you don't have pre-built versions
-available. Compiling from source is tricky, can fail due to version
-mismatch, can break your current computer install, and is only
-recommended for advanced users with a programming background. <br/>
-
-<br/>
-
-You must first install GCC for your platform, and be able to compile a
-basic "hello world" program. Other compilers might work, but I cannot
-tell you how to do this. If you don't know what that means, you may
-need to seek assistance from someone who does. Ask your local computer-y
-person.<br/>
-
-<br/>
-
-If your platform provides any of the following libraries in an easy to
-install fashion, use that, but don't forget to install the development
-components, if you choose this route. Otherwise,  just follow the
-below instructions.<br/>
-
-<br/>
-
-Install the development headers for your platform.  Windows needs
-MinGW/MSYS or TDM-GCC/MSYS (unless you know better), some instructions are <a href="http://wiki.wxwindows.org/HowTo:_Install_MSYS_and_MinGW_for_use_with_Eclipse_CDT#MSYS_installation">here</a>, and my notes are below.  Otherwise, you are largely <a href="https://www.google.com/">on your own</a>. Cygwin is <span style="font-style: italic;">not</span> recommended, as OpenGL may not work in the final program (without X11).  Feel free to <a href="contact.html">ask for help</a>.<br/>
-
-
-
-
-
-<h4>wxWidgets<br/>
-</h4>
-
-<ul>
-	<li>Download the latest wxWidgets source code from <a href="http://www.wxwidgets.org/">http://www.wxwidgets.org/</a></li><li>Then extract the tarball/zip/whatever</li><li>Compile this with the following console command:<ul><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> ./configure --with-opengl --enable-unicode</span></li><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> make</span></li></ul></li><l [...]
-</ul>
-
-
-<h4>LibPNG <br/>
-</h4>
-
-<ul>
-<li>Download the latest libPNG (Unless running mac) <a href="http://www.libpng.org/pub/png/libpng.html">http://www.libpng.org/pub/png/libpng.html</a><ul><li>Copy the correct makefile to the base directory</li><li>Mac OSX : move scripts/makefile.darwin  to the libpng dir, and rename it makefile</li><li>Windows: Not sure. I had to do a lot of fiddling to get this to
-work. Essentially I pulled a makefile from the msysPORT code, and then
-converted it from patch format to a usable makefile. I suggest looking
-on the interwebs for instructions.</li></ul></li><li>Other platforms: move scripts/makefile.gcc to the libpng dir and rename it makefile</li><ul><li> Compile it with<span style="font-family: monospace;"> <span style="text-decoration: underline;">$</span> make</span></li><li> Install it with<span style="font-family: monospace;"> <span style="text-decoration: underline;">#</span> make install    </span><br/>
-
-
-    </ul>
-    </li>
-</ul>
-
-<h4> Freetype</h4>
-
-<ul>
-<li>Download the latest freetype source code: <a href="http://www.freetype.org/">http://www.freetype.org/</a></li><li>Compile with</li><ul><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> ./configure<br/>
-      </span></li><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> make</span></li></ul><li> Install  (as administrator)</li><ul><li><span style="font-family: monospace;"><span style="text-decoration: underline;">#</span> make install</span></li></ul>
-</ul>
-
-
-<h4> FTGL<br/>
-</h4>
-
-<ul>
-<li>Download the latest FTGL source code from <a href="http://sourceforge.net/projects/ftgl/">http://sourceforge.net/projects/ftgl/</a></li><li>Compile with</li><ul><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> ./configure <br/>
-      </span></li><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> make</span></li></ul><li> Install  (as administrator)</li><ul><li><span style="font-family: monospace;"><span style="text-decoration: underline;">#</span> make install</span></li></ul>
-</ul>
-
-
-
-<h4>libxml2</h4>
-
-<ul>
-<li>Download the latest libxml2 <a href="http://www.xmlsoft.org/">http://www.xmlsoft.org/</a></li><li>Compile with</li><ul><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> ./configure <br/>
-</span></li><li><span style="font-family: monospace;"><span style="text-decoration: underline;">$</span> make</span></li></ul><li> Install  (as administrator)</li><ul><li><span style="font-family: monospace;"><span style="text-decoration: underline;">#</span> make install</span></li></ul>
-</ul>
-
-
-<h4>MathGL</h4>
-
-
-<ul>
-<li>Download the latest mathgl <a href="http://mathgl.sourceforge.net/">http://mathgl.sourceforge.net/</a></li><li>Compile this with:</li><ul style="font-family: monospace;"><li>$ ./configure --disable-gsl</li></ul><ul style="font-family: monospace;"><li>$ make</li></ul><li>Install with</li><ul><li style="font-family: monospace;"># make install</li></ul>
-</ul>
-
-
-
-<h2><a name="3Depict_Compilation"></a>3Depict Compilation</h2>
-
-
-Run the "configure" script (as a normal user) with:<br/>
-
-
-<br/>
-
-<span style="font-family: monospace;">$ ./configure</span><br/>
-
-<br/>
-
-This script works out some of the specifics of your system. If it
-fails, saying that it cannot locate ftgl, and you know you have the
-headers and libraries installed, simply pass the directory for ftgl
-with --with-ftgl-prefix=(wherever, for example /usr/ if ftgl is
-installed in /usr/include and /usr/libs). A full list of possible
-options (there are many) is available with:<br/>
-<br/>
-
-<span style="font-family: monospace;">$ ./configure --help</span>
-
-<br/>
-<br/>
-
-
-build the project (again normal user) with:<br/>
-
-
-<br/>
-
-<span style="font-family: monospace;">$ make</span><br/>
-
+Either <a href="https://sourceforge.net/projects/threedepict/files/">Download</a> the source code (<a href="https://secure.wikimedia.org/wikipedia/en/wiki/Tar.gz">.tar.gz</a> file), or grab the <a href="http://mercurial.selenic.com">mercurial</a> repository using this clone command, or by opening the URL in your graphical mercurial client (the URL is the bit at the right). 
 <br/>
-
-to run the program:<br/>
-
-
-<br/>
-
-<span style="font-family: monospace;">$ ./src/3Depict</span><br/>
-
 <br/>
-
-you can optionally install it (Excluding mac OS) with:<br/>
-
-<br/>
-
-<span style="font-family: monospace;"># make install</span><br/>
-
-<h3><a name="Extra_notes_for_Mac_OSX"></a>Extra notes for Mac OSX<br/>
-
-</h3>
-
-To build a .app package (required to interact with the program), you need to run <br/>
-
+<span style="font-family: monospace;">$ hg clone http://hg.code.sf.net/p/threedepict/code/ 3Depict</span>
 <br/>
 
-<span style="font-family: monospace;">$ makeMacOSXPackage</span><br/>
-
 
-<br/>
-
-You can even move this ".app" package to other computers (with the same OSX version), and it should work there. <br/>
-<br/>
 
-<h2><a href="windows"></a> Compile notes for windows </h2>
-<p><i>
-THese notes are a little outdated as of April 2013 - you may find some of the program versions have changed. Most of the notes should still be valid.  However, this is not how 3Depict is built for windows - we use the cross-compile method instead. This has been scripted and is much easier, but requires a Debian or Debian-like installation (we recommend using VirtualBox). If you still want to compile under normal windows, then read on.
-</i>
-</p>
 
-<p> Before I post the full notes, this is very, very detailed and technical. But it means I have this working, and down to a fine art. Its a rough ride.</p>
-<p>
-You will need the 7zip file manager program or winrar to be able to open tar/gz files, as windows does not support this filetype, nor recognises it in the "web search" facility. (Its a standard gzip + archive file, note to windows devs : see <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Tgz">wikipedia on tar-gz</a>)</p>
-<p>
-This worked under windows 7. It probably works elsewhere too. Maybe. I *really* recommend using ubuntu or something; then you don't have to go through all these hoops.
-</p>
-<br/>
-Files required to set up dependencies:
+<h2>Compiling for your platform</h2>
+To compile, you must first have a working compilation environment. This is diferent for each system. Follow these notes to set up your environment for your system
 <ul>
-<li>MSYS-1.0.11.exe</li>
-<li>tdm-gcc-4.5.1.exe</li>
-<li>lpng143.zip</li>
-<li>freetype-2.3.12.tar.gz</li>
-<li>gsl-1.14.tar.gz</li>
-<li>zlib-1.2.5.tar.gz</li>
-<li>libxml2-2.7.7.tar.gz</li>
-<li>ftgl-2.1.3~rc5.tar.gz</li>
-<li>mathgl-1.10.2.1.tar.gz</li>
-<li>wxMSW-2.8.11.zip</li>
+<li><a href="compiling-linux.html">Linux</a> - this is the recommended system for compiling, as it is the easiest to work with.</li>
+<li><a href="compiling-cross.html">Windows via Debian Linux</a> - this is the recommended method for building windows executables. We <b>do not</b> recommend building under windows directly, as it is very complicated.</li>
+<li><a href="compiling-macosx.html">Mac OSX</a> - Rough guide for OSX compilation.
 </ul>
 
-<br/>
-<h3>Setting up dependencies</h3>
-<ul>
-<li>
-Installed TDM-GCC-4.51 (32bit) (all defaults +openmp)
-</li>
-<li>
- Installed MSYS-1.0.11
-<ul>
-<li>
-	- Said "yes" to "have mingw installed (c:/MinGW32/)
-</li>
-</ul>
-</li>
-<li>
-Use console provided by the big blue "m(sys)" shortcut now on desktop to do most of the following
-</li>
-<li>
-Checked that<span style="font-family: monospace;">gcc --version</span> worked (should now spit out something like "gcc.exe (tdm-1) 4.5.1") 
-</li>
-</ul>
-<h4>wxWidgets</h4>
-<ul>
-<li>
-Extracted wxMSW-2.8.11.zip to C:</li>
-<li>
-ran <span style="font-family: monospace;">./configure --with-opengl --enable-unicode</span> inside c:\wxMSW-2.8.11\
-</li>
-<li>
-ran <span style="font-family: monospace;">make</span>. This will take a long time to run. (make can of course be sped up on multi-cpu systems with <span style="font-family: monospace;">make -j(#CPU)</span> (eg <span style="font-family: monospace;">make -j4</span>) to enable parallel compilation
-</li>
-<li>
- Checked that the openGL wxWidgets sample works. 
-<ul>
-<li>
-	 <span style="font-family: monospace;">cd samples/opengl</span></li>
-	<li>
-	 <span style="font-family: monospace;">make</span></li>
-	<li>
-	 Ran samples/opengl/cube/cube.exe</li>
-	<li>
-	 Copied dlls that it complained about when double clicking the icon to the exe folder.
-	(wxbase28u_gcc_custom.dll,wxmsw28u_core_gcc_custom.dll,wxmsw28u_gl_gcc_custom.dll)</li>
-	<li>
-	 Ran samples/opengl/cube/cube.exe</li>
-	<li>
-	 Saw cube. OpenGL must therefore work.
-	</li>
-	</ul>
-</li>
-<li>
- Ran <span style="font-family: monospace;">make install</span>
-</li>
-</ul>
-<h4>zlib</h4>
-<ul>
-<li>
- ran <span style="font-family: monospace;">make -f win32/Makefile.gcc</span>
-</li>
-<li>
- Copied .h to C:\MinGW32\include\
-</li>
-<li>
- Copied zlib1.dll,libz.a,libzdll.a to C:\MinGW32\lib\
-</li>
-</ul>	
-	
-<h4>libpng</h4>
-<ul>
-<li>
- depends upon zlib, so do zlib first
-</li>
-<li>
- ran <span style="font-family: monospace;">make-f scripts/makefile.gcc</span>
-</li>
-<li>
- Copied .h to  C:\MinGW32\include\
-</li>
-<li>
- Copied libpng.a to c:\MinGW32\lib\
-</li>
-</ul>
 
-<h4>libxml2</h4>
-<ul>
-<li>
- Ran<span style="font-family: monospace;"> ./configure</span>
-	<li>
-	-- Failure on libtoolT (I ignored this).
-	</li>
-	</li>
-<li>
- Ran make
-</li>
-<li>
-- Failed on testThreads.c. In that file, on line 110:
-<span style="font-family: monospace;">  tid[i]= (pthread_t)-1; </span> should be
-<span style="font-family: monospace;">
-<pre>
-	tid[i].p= NULL;
-	tid[i].x=-1;
-</pre>
-</span>
-	
-	as pthread_t is a struct under windows ( see <a href="http://sourceware.org/pthreads-win32/faq.html">Pthreads faq</a>, Q11)
-	looking in pthread.h:
-<span style="font-family: monospace;">
-<pre>
-	typedef struct {
-	    void  p;                   /* Pointer to actual object */
-	    unsigned int x;             /* Extra information - reuse count etc */
-	} ptw32_handle_t;
-</pre>
-	</li>
-<li>
- Ran <span style="font-family: monospace;">make install</span>
-</li>
-</ul>
-<h4>libfreetype</h4>
-<ul>
-<li>
- Ran <span style="font-family: monospace;">./configure</span>
-</li>
-<li>
- Ran <span style="font-family: monospace;">make</span>
-</li>
-<li>
- Ran <span style="font-family: monospace;">make install</span>
-</li>
-</ul>
-<h4>ftgl</h4>
-<ul>
-<li>
- Edited configure
- <ul>
-<li>
-	--found "-lgl"  replaced with "-lopengl32".
-	</li>
-	<li>
-	-- found "-lGLU" replaced with "-lGLU32"
-	</li>
-	<li>
-	--openGL and GLU tests are broken. in "configure" replace char glBegin() with #include <GL/gl.h> and char gluNewTess (); with #include <GL/glu.h>, then remove the "return" specification from the function call. This will allow the GL and GLU tests to succeed.
-		</li>
-	</ul>
-</li>
-<li>
- Ran <span style="font-family: monospace;">./configure</span></li>
-<li>
- <span style="font-family: monospace;">Make</span></li>
-<li>
- <span style="font-family: monospace;">make install</span> (this installs into /usr/local/, which is not preferable, really)
-	</li>
-	</ul>
-<h4>GSL</h4>
-<ul>
-<li> Ran <span style="font-family: monospace;">./configure</span></li>
-<li> Ran <span style="font-family: monospace;">make</span></li>
-<li> ran <span style="font-family: monospace;">make install</span></li>
-</ul>
-
-<h4>Mathgl</h4>
-<ul>
-<li>
-(Depends GSL, do that before this)
- Ran <span style="font-family: monospace;">./configure</span>
-</li>
-<li>
-  Ran Make
-	<ul>
-	<li>
-	This failed in the utils dir. libpng is unable to see libz for whatever reason. Does not bode well,  but it was  in the utils section, which I don't need, so I ignored it.
-		</li>
-	</ul>
-</li>
-<li>
- Entered the "mgl" directory & ran <span style="font-family: monospace;">make install</span>
-</li>
-<li>
- Entered the "include" directory & ran <span style="font-family: monospace;">make install</span>
-</li>
-</ul>
-<h4>3Depict</h4>
-<ul>
-
-<li>
- Ran <span style="font-family: monospace;"> export CFLAGS="-I/c/msys/1.0/local/include" && export LDFLAGS="-L/c/msys/1.0/local/lib" && ./configure --with-libqhull-link="-L/c/msys/1.0/local/lib/ -lqhull"  --with-libpng-link="-lpng -lz" </span>
-	<ul>
-	<li>
-		 For an explanation as to why this "export" business is needed, see <a href="http://www.mingw.org/wiki/IncludePathHOWTO">this mingw faq</a>.	</li><li>
-		-- This won't build with parallelism; you have to add <span style="font-family: monospace;">--enable-openmp-parallel </span> , however some versions of GCC do not like this, so I left it off by default.  If you get errors about <span style="font-family: monospace;">undefined __sync_compare_and_swap_4  </span>(or similar) you can either 1) Alter your optimisation level 2) rebuild with -march=i686 3) modify the files it complains from, and build only those files without paralellism (modi [...]
-		 These settings will enable slow debug checking. To turn off debug checking add  <span style="font-family: monospace;">--enable-no-debug-checks</span> after configure, as in <span style="font-family: monospace;">./configure --enable-no-debug-checks</span>. Full information is available in <span style="font-family: monospace;">./configure --help</span>.
-	</li>
-	</ul>
-</li>
-<li>
- Ran <span style="font-family: monospace;">make</span>
-</li>
-<li>
- Modified pngread.h to remove windows specific path
-</li>
-<li>
- Modified c:\msys\1.0\include\mgl\mgl_data.h to add #undef NO_GSL immediately before #ifndef NO_GSL
-</li>
-<li>
- Re-ran <span style="font-family: monospace;">make</span> -- this generates the "exe" file.
-</li>
-
-<li>
-Double clicked program
-
-<ul>
-<li>
-	-- Put missing DLL it complained about in the same dir. Kept doing this until it stopped whinging about dlls
-</li>
-</ul>
-</li>
-</ul>
 </div></div>
 
 </body></html>
diff --git a/docs/web/contact.html b/docs/web/contact.html
index cbd3254..123de14 100644
--- a/docs/web/contact.html
+++ b/docs/web/contact.html
@@ -8,6 +8,7 @@
 	<title>Contact 3Depict</title> 
 
 	<link rel="stylesheet" href="style.css" type="text/css"/>
+	<link rel="icon" type="image/png" href="favicon.png"/>
 
 </head>
 
@@ -46,7 +47,7 @@ You can post messages to the <a href="https://sourceforge.net/apps/phpbb/threede
 <h2>Email</h2>
 <form id="emf-form" enctype="multipart/form-data" method="post" action="http://www.emailmeform.com/builder/form/ff3Jr0WI55h54"><table style="text-align:left;" cellpadding="2" cellspacing="0" border="0" bgcolor="transparent"><tr><td style="" colspan="2"></td></tr><tr valign="top"><td style="" ><font face="Verdana" size="2" color="#000000"><b>Name</b></font><span style="color:red;"><small>*</small></span></td></tr><tr><td style=""><input id="element_0" name="element_0" value="" size="30" c [...]
 <p>
-If you need to attach an image, you can do so using an image upload service, such as <a href="http://imagepaste.nullnetwork.net/">Nullnetwork's image paste bin</a>, provided the images are < 1MB in size.
+If you need to attach an image, you can do so using an image upload service, such as <a href="http://imagebin.ca/">Imagebin.ca</a>.
 </p>
 </div>
 </div>
diff --git a/docs/web/documentation.html b/docs/web/documentation.html
index bb29cc4..25c4fa2 100644
--- a/docs/web/documentation.html
+++ b/docs/web/documentation.html
@@ -5,9 +5,8 @@
   <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Documentation</title>
   <meta name="description" content="Documentation for 3Depict" />
 
-  
-  
-  <link rel="stylesheet" href="style.css" type="text/css" meda="screen"></head><body>
+    	<link rel="icon" type="image/png" href="favicon.png"/>
+  	<link rel="stylesheet" href="style.css" type="text/css" meda="screen"></head><body>
 <div id="header">
 <h1>3Depict - Valued point cloud visualisation and analysis</h1>
 <ul id="nav">
@@ -42,6 +41,13 @@ PDF Manual <a href="manual.pdf">here</a>. There is an <a href="manual/manual.htm
 
 
 <h2>Screencasts</h2>
+
+New features 0.0.14 (July 2013):<br>
+<center>
+<video src="3Depict-0.0.14-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br></small>
+<small><a href="3Depict-0.0.14-screencast.ogg">download video</a></small>
+</center>
+
 <p>
 Animation and composition profiles in 3Depict 0.0.13  (Apr, 2013):<br>
 <center>
@@ -49,11 +55,6 @@ Animation and composition profiles in 3Depict 0.0.13  (Apr, 2013):<br>
 <small><a href="33Depict-0.0.13-sphere_comp_and_animate-screencast.ogg">download video</a></small>
 </center>
 
-A short demo of 3Depict 0.0.8 (Oct, 2011):<br>
-<center>
-<video src="3Depict-0.0.8-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br></small>
-<small><a href="3Depict-0.0.8-screencast.ogg">download video</a></small>
-</center>
 
 
 <center>
@@ -83,8 +84,12 @@ Some sample datasets are listed below, and whilst not very interesting can be us
 </p>
 
 <h2> Programmer's Reference</h2>
-<p> 
-3Depict has <a href="doxygen/main.html">documentation</a> regarding the program structure available. This is automatically generated using the <a href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a> "Doxyfile" in the source tarball. The documentation provides data such as call and inheritance diagrams, hyperlinked function declarations and descriptions, and provides a useful "first glance"  reference for working with the code. For a full program overview, try looking at the <a href=" [...]
+<h3> Compilation instructions</h3>
+
+For programmers, and advanced users, instructions on how to compile 3Depict from source are available <a href="compiling.html">here</a>. The procedure can be a bit tricky though.
+
+<h3> Program structure</h3>
+3Depict has <a href="doxygen/index.html">documentation</a> regarding the program structure available. This is automatically generated using the <a href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a> "Doxyfile" in the source tarball. The documentation provides data such as call and inheritance diagrams, hyperlinked function declarations and descriptions, and provides a useful "first glance"  reference for working with the code. For a full program overview, try looking at the <a href= [...]
 </p>
 
 
diff --git a/docs/web/download.html b/docs/web/download.html
index e04aae3..18f6646 100644
--- a/docs/web/download.html
+++ b/docs/web/download.html
@@ -3,9 +3,10 @@
 
     <meta name="description" content="Download 3Depict" />
 
-  
-  
-  <link rel="stylesheet" href="style.css" type="text/css" meda="screen"></head><body>
+	<link rel="icon" type="image/png" href="favicon.png"/>
+	<link rel="stylesheet" href="style.css" type="text/css" meda="screen">
+
+</head><body>
 <div id="header">
 <h1>3Depict - Valued point cloud visualisation and analysis</h1>
 <ul id="nav">
@@ -20,7 +21,7 @@
 
 <div id="left">
 <div class="box">
-	<h2> Latest version: 0.0.13</h2>
+	<h2> Latest version: 0.0.16</h2>
 </div>
 
 <div class="box">
@@ -35,7 +36,9 @@ how</p>
 <div id="content">
 <div id="right">
 <h1>Download</h1>
-<p> Remeber that 3Depict is currently in the <i>0.0.blah</i> series (early development). This is alpha software, and provided on a best-effort basis. If you find bugs in the software, please <a href="contact.html">let us know</a> and they will be fixed!</p>
+<p> Remember that 3Depict is currently in the <i>0.0.blah</i> series (early development). This is alpha software, and provided on a best-effort basis. If you find bugs in the software, please <a href="contact.html">let us know</a> and they will be fixed! Older releases are available in both source and binary (executable) form from our <a href="https://sourceforge.net/projects/threedepict/files/">files page</a>. </p>
+
+<p> Don't forget - support is available on our <a href="https://sourceforge.net/apps/phpbb/threedepict/index.php">forums</a>, or <a href="contact.html">by email!</a></p>
 
 <h2>Select your system:</h2>
 <ul>
@@ -67,10 +70,11 @@ how</p>
   
 </ul>
 <h3><a name="Mac_OS_X"></a>Mac OS X  </h3>
+<p><i>The following versions are quite old now. We are looking for help with the OSX version, please see the <a href="https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=39">forum</a> thread!</i></p>
 <ul>
-      <li>10.7 "Lion" </li>
+      <li>10.7 "Lion" (0.0.13)</li>
       <ul>
-      <li><a href="https://sourceforge.net/projects/threedepict/files/3Depict-0.0.13-mac10.7.5.pkg/download">64 bit Intel</a> <br>
+      <li><a href="https://sourceforge.net/projects/threedepict/files/3Depict-0.0.13-10.7.pkg/download">64 bit Intel</a> <br>
       </ul>
     
     </li>
@@ -78,20 +82,29 @@ how</p>
 	<ul>
 		<li><a href="https://sourceforge.net/projects/threedepict/files/3Depict-0.0.10-mac10.6.dmg/download">32 bit Intel</a> <br>
 	</ul>
-
   </li>
   
 </ul>
-<h3><a name="Windows"></a>Windows (0.0.11)</h3>
+<h3><a name="Windows"></a>Windows </h3>
+<small>how to tell if you want the 32 or 64 bit version : <a href="http://windows.microsoft.com/en-US/windows-vista/32-bit-and-64-bit-Windows-frequently-asked-questions">see here</a></small>. If you are still unsure, try the 64 bit version, then if it doesn't work, use the 32 bit one.
+
+
 <ul>
-  <li><a href="http://sourceforge.net/projects/threedepict/files/3Depict-0.0.11-win32.exe/download">32 Bit version</a> (works on 64 bit too, just slower, and can't use as much RAM). XP Users - <a href="https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=13">Note</a>
+  <li>0.0.16 :<a href="http://sourceforge.net/projects/threedepict/files/3Depict-0.0.16-win32.exe/download">32 Bit version</a> 
+  </li>
+<li>0.0.16: <a href="http://sourceforge.net/projects/threedepict/files/3Depict-0.0.16-win64.exe/download">64 Bit version</a> 
   </li>
 </ul>
+
+
+<p>
+
+</p>
 <h3><a name="Other_systems"></a>Other systems</h3>
 <ul>
   <li>Binaries (executables) not available for your system, sorry. You
-will have to <a href="compiling.html">compile from source</a>. The current compressed source archive is <a href="http://sourceforge.net/projects/threedepict/files/0.0.12/3Depict-0.0.12.tar.gz/download">3Depict 0.0.12</a>.</li> 
-   <li>Older releases are avaialable in both source and binary (excecutable) form from our <a href="https://sourceforge.net/projects/threedepict/files/">sourceforge files page</a>. </li>
+will have to <a href="compiling.html">compile from source</a>. The current compressed source archive is <a href="http://sourceforge.net/projects/threedepict/files/0.0.16/3Depict-0.0.16.tar.gz/download">3Depict 0.0.16</a>.</li> 
+  
 </ul>
 <br>
 </div>
diff --git a/docs/web/images/3Depict-icon.png b/docs/web/images/3Depict-icon.png
new file mode 100644
index 0000000..650ac31
Binary files /dev/null and b/docs/web/images/3Depict-icon.png differ
diff --git a/docs/web/images/Screenshot-thumb.png b/docs/web/images/Screenshot-thumb.png
new file mode 100644
index 0000000..c109dcc
Binary files /dev/null and b/docs/web/images/Screenshot-thumb.png differ
diff --git a/docs/web/images/cu-ppt-cluster-analysis.png b/docs/web/images/cu-ppt-cluster-analysis.png
new file mode 100644
index 0000000..7144eaa
Binary files /dev/null and b/docs/web/images/cu-ppt-cluster-analysis.png differ
diff --git a/docs/web/images/exportanimParamDialog.png b/docs/web/images/exportanimParamDialog.png
new file mode 100644
index 0000000..29e94d2
Binary files /dev/null and b/docs/web/images/exportanimParamDialog.png differ
diff --git a/docs/web/images/laser-data1.png b/docs/web/images/laser-data1.png
new file mode 100644
index 0000000..82dbb0c
Binary files /dev/null and b/docs/web/images/laser-data1.png differ
diff --git a/docs/web/images/laser-data2.png b/docs/web/images/laser-data2.png
new file mode 100644
index 0000000..b27c76f
Binary files /dev/null and b/docs/web/images/laser-data2.png differ
diff --git a/docs/web/images/resolution-example.png b/docs/web/images/resolution-example.png
new file mode 100644
index 0000000..94e2338
Binary files /dev/null and b/docs/web/images/resolution-example.png differ
diff --git a/docs/web/images/voxel-representations.png b/docs/web/images/voxel-representations.png
new file mode 100644
index 0000000..db4a452
Binary files /dev/null and b/docs/web/images/voxel-representations.png differ
diff --git a/docs/web/index.html b/docs/web/index.html
index adebc5b..465eb32 100644
--- a/docs/web/index.html
+++ b/docs/web/index.html
@@ -8,6 +8,7 @@
 	<title>3Depict Home</title> 
 
 	<link rel="stylesheet" href="style.css" type="text/css"/>
+	<link rel="icon" type="image/png" href="favicon.png"/>
 
 </head>
 
@@ -26,14 +27,18 @@
 
 <div id="left">
 <div class="box">
-<h2> Latest version: 0.0.13</h2>
+<h2> Latest version: 0.0.16</h2>
 <p><a href="download.html">Download</a> the latest version of 3Depict for your platform</p>
 </div>
 <div class="box">
 
 <b>Questions?</b> Ask on the <a href="http://sourceforge.net/apps/phpbb/threedepict/">forum</a> 
 <br/>
+<br/>
+<b>Quick Peek?</b>: See some <a href="screenshots.html">Screenshots</a>
+
 </div>
+
 <center>
 	<a href="http://sourceforge.net"><img src="http://sflogo.sourceforge.net/sflogo.php?group_id=341003&type=2" alt="SourceForge.net Logo" border="0" height="37" width="125" align="middle"/></a><br/>
 	<small><a href="http://sourceforge.net/projects/threedepict/">SF project page</a></small>
@@ -58,24 +63,25 @@ interact with and analyse point based datasets. <br/>
 <h3>
 News:
 </h3>
-
 <ul>
-	<li><i>15th Apr. 2013: </i> 3Depict 0.0.13 windows installers <a href="download.html">uploaded</a>.</li>
-	<li><i>13th Apr. 2013: </i> 3Depict 0.0.13 mac OSX 10.7 ("Lion") <a href="download.html">uploaded</a>.</li>
-	<li><i>12th Apr. 2013: </i> 3Depict 0.0.13 source code uploaded</li>
-	
-	<li>Older news <a href="news.html">here</a>
+	<li><i>24th Apr. 2014: </i> The console-only <i>Posgen</i> project, which covers atom probe data automation, has had its 0.0.1 release! <a href="http://apttools.sourceforge.net/">Check it out</a>!
+	<li><i>21th Apr. 2014: </i> 0.0.16 installers for windows 32 and 64 bit ready for <a href="download.html">download</a>!</li>
+	<li><i>17st Apr. 2014: </i> 3Depict 0.0.16 released. As previously mentioned, we have experimental LAWATAP ato file support, and have improved overall program stability and appearance. Check the complete <a href="changelog.txt">changelog</a>!</li>
+	<li><i>6th Apr. 2014</i> Source code repository has been updated for upcoming 0.0.16. You can see the upcoming features for 3Depict in the source-code repository's <a href="http://sourceforge.net/p/threedepict/code/ci/f03a128c15bc422c6ba5fc38245f77ee1248c19e/tree/ChangeLog">changelog</a>. Notably, experimental ATO file support (please submit samples!) has been added, and many plot area improvements have been made</li>
+
+	<li>Older news <a href="news.html">here</a>,</li>
 </ul>
 
 <h3>
-New features in 0.0.13: 
+Enhancements in 0.0.16: 
 </h3>
 
 <ul>
-	<li>Spherical composition profiles</li>
-	<li>1D "axial" distribution functions, for measuring inter-atomic distance profiles</li>
-	
-
+	<li>Experimental LAWATAP (.ATO) support. We need sample files to ensure this works for everyone, so please send them!</li>
+	<li>Animation is saved/restored</li>
+	<li>Filter tree interaction improved</li>
+	<li>Min-count mode for composition profiles</li>
+	<li>Automated GUI interaction checker</li>
 	<li> and more. Full details in the <a href="changelog.txt">Changelog</a></li>
 </ul>
 
@@ -146,6 +152,7 @@ of how much you have </a><br/>
 	</ul>
 
   </li>
+  <li> Most, but not all state files can be transmitted between differing 3Depict versions</li>
 </ul>
 
 </div>
diff --git a/docs/web/manual.html b/docs/web/manual.html
index ec5e9e6..ab8db9a 100644
--- a/docs/web/manual.html
+++ b/docs/web/manual.html
@@ -8,7 +8,7 @@
 	<title>3Depict Home</title> 
 
 	<link rel="stylesheet" href="style.css" type="text/css"/>
-
+	<link rel="icon" type="image/png" href="favicon.png"/>
 </head>
 <body>
 <div id="left">
diff --git a/docs/web/news.html b/docs/web/news.html
index e016dff..7791976 100644
--- a/docs/web/news.html
+++ b/docs/web/news.html
@@ -8,7 +8,7 @@
 	<title>3Depict Home</title> 
 
 	<link rel="stylesheet" href="style.css" type="text/css"/>
-
+	<link rel="icon" type="image/png" href="favicon.png"/>
 </head>
 
 <body>
@@ -30,15 +30,34 @@
 <div id="right">
 <h2> News Archive </h2>
 <p>
+<h3> 2013</h3>
+<ul>
+	<li><i>25th Jan. 2014: </i> <a href="http://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=38">Bugs</a> were introduced in the uploaded versions of 0.0.15, which caused the filter system to function incorrectly. This has been fixed, and the installers updated. If you downloaded 0.0.15 previously, please <a href="download.html">re-download</a> the latest installer (windows: 0.0.15-1).</li>
+	<li><i>1st Dec. 2013: </i> 3Depict 0.0.15 installers for windows 32 and 64 bit <a href="download.html">uploaded</a>. The current windows installers now use multiple CPUs for many filters - go faster!</li>
+	<li><i>1st Dec. 2013: </i> 3Depict 0.0.15 released! New features include a range editor, binomial randomness testing, and enhanced support for ENV and RRNG files. More details in the <a href="changelog.txt">Changelog</a>. Platform builds available soon.</li>
+
+	<li><i>29th Aug. 2013: </i> Some reports of windows versions of 0.0.14 not working for some systems, whilst 0.0.13 works. If this affects you, please <a href="https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=33">post on the forum</a>.</li>
+	<li><i>21st Jul. 2013: </i> Windows installers <a href="download.html">uploaded</a>.</li>
+	<li><i>20th Jul. 2013: </i> 3Depict 0.0.14 source code uploaded. Various platform releases to follow shortly. </li>
+
+	<li><i>6th Jul. 2013: </i> 3Depict 0.0.14's <a href="http://sourceforge.net/p/threedepict/code/ci/default/tree/">source code</a> is now ready for testing. New <a href="http://sourceforge.net/p/threedepict/code/ci/default/tree/ChangeLog">features</a> include slice voxel visualisation, improved rangefile support and performance improvements. Advanced users can <a href="compiling.html">build a copy</a>. We plan to finalise the release in ~3 weeks.</li>
+
+	<li><i>15th Apr. 2013: </i> 3Depict 0.0.13 windows installers <a href="download.html">uploaded</a>.</li>
+	<li><i>13th Apr. 2013: </i> 3Depict 0.0.13 mac OSX 10.7 ("Lion") <a href="download.html">uploaded</a>.</li>
+
+	<li><i>12th Apr. 2013: </i> 3Depict 0.0.13 source code uploaded</li>
+</ul>
+
 <h3> 2012</h3>
 <ul>
-	<li><i>24 Nov. 2012: 0.0.12 released - the source code has been uploaded, with various platform builds to follow shortly. This release focussed on a new feature - filter animation, as well as improved stability and decreased resource consumption. As usual, check the <a href="changelog.txt">Changelog</a> for more info!</i></li>
-	<li><i>29 Oct. 2012: We are finalising the current code for release of 0.0.12 in ~6 weeks. We need people to test the program, do translation and provide feedback - if you can help out, please <a href="contact.html">contact us</a>!</i></li>
-	<li><i>20 Jul. 2012: We have received unconfirmed reports that some users on Windows XP may experience startup problems with 3Depict. If this affects you, please <a href="https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=13">report it</a>.</i></li>
-	<li><i>17th Jul. 2012: Windows and Mac 10.7 installers uploaded for 3Depict 0.0.11.</i></li>
-	<li><i>16th Jul. 2012: 3Depict 0.0.11 source code uploaded. Installers for various platforms (linux,mac,windows) to follow soon.</i></li>
-	<li><i>28th Jun. 2012: 3Depict 0.0.10 mac 10.6 (snow leopard) installer uploaded.</i></li>
-	<li><i>10th Apr. 2012: 3Depict 0.0.10 mac 10.7 (lion) installer uploaded.</i></li>
+	
+	<li><i>24 Nov. 2012:</i> 0.0.12 released - the source code has been uploaded, with various platform builds to follow shortly. This release focussed on a new feature - filter animation, as well as improved stability and decreased resource consumption. As usual, check the <a href="changelog.txt">Changelog</a> for more info!</i></li>
+	<li><i>29th Oct. 2012:</i> We are finalising the current code for release of 0.0.12 in ~6 weeks. We need people to test the program, do translation and provide feedback - if you can help out, please <a href="contact.html">contact us</a>!</i></li>
+	<li><i>20th Jul. 2012:</i> We have received unconfirmed reports that some users on Windows XP may experience startup problems with 3Depict. If this affects you, please <a href="https://sourceforge.net/apps/phpbb/threedepict/viewtopic.php?f=1&t=13">report it</a>.</i></li>
+	<li><i>17th Jul. 2012:</i> Windows and Mac 10.7 installers uploaded for 3Depict 0.0.11.</i></li>
+	<li><i>16th Jul. 2012:</i> 3Depict 0.0.11 source code uploaded. Installers for various platforms (linux,mac,windows) to follow soon.</i></li>
+	<li><i>28th Jun. 2012:</i> 3Depict 0.0.10 mac 10.6 (snow leopard) installer uploaded.</i></li>
+	<li><i>10th Apr. 2012:</i> 3Depict 0.0.10 mac 10.7 (lion) installer uploaded.</i></li>
 	<li><i>1st Apr. 2012:</i> 3Depict 0.0.10 windows installer uploaded.</li>
 	<li><i>31st Mar. 2012:</i> 3Depict 0.0.10 source code uploaded. Builds for various platforms to follow. This version mostly is directed at bug fixes and improved program structure.</li>
 	<li><i>25th Mar. 2012:</i> We are close to releasing 0.0.10, and we would like to have better native language support - we have added French and Spanish using <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Translation_memory">translation memory</a>, but it still needs human review. If you can check translations in these languages - please consider doing so <a href="https://www.transifex.net/projects/p/3depict/">here</a>.</li>
diff --git a/docs/web/questions.html b/docs/web/questions.html
index d3c105b..94c3e73 100644
--- a/docs/web/questions.html
+++ b/docs/web/questions.html
@@ -8,6 +8,7 @@
 	<title>3Depict Frequent Questions</title> 
 
 	<link rel="stylesheet" href="style.css" type="text/css"/>
+	<link rel="icon" type="image/png" href="favicon.png"/>
 
 </head>
 
@@ -43,7 +44,7 @@ You can help, even without programming; Alternately, if you know how to program
   <li>Are there any instruction manuals?</li>
   <ul>
     <li>Yes, you can download one from the <a href="documentation.html">documentation
-page.</a>
+page.</a> If you are new to 3Depict, but not atom probe, you might want to read the "quick start" section in the manual.
       </li>
   </ul>
 </ul>
@@ -60,17 +61,16 @@ page.</a>
 	</ul>
   </ul>
 </ul>
+
 <ul>
-  <li>I'm running Debian/Mint/Ubuntu, and getting a crash on startup: "Floating point exception"</li>
-  <ul>
-    <li>We left some strict debugging in for some of the deb packages, which converts a minor problem into a major one, but only on some machines (we are not sure why). To solve this, you need to update to 0.0.8 or later. We have <a href="https://launchpad.net/~tehuser/+archive/ppa">set up a PPA</a> for Ubuntu users.</li>
-  </ul>
-</ul>
-<ul>
-  <li>I'm running Mac OSX, and when trying to update to the new version, I get the error "A newer version of this software already exists on this disk"</li>
+  <li>How do I cite this program?</li>
   <ul>
-    <li>This was due to us not specifying a version number in some early releases. Go to spotlight, then type "terminal", and open Terminal.app. Now cut and paste the following command into the terminal to remove the old version data. <p><span style="font-family: monospace;">sudo rm /private/var/db/receipts/net.sourceforge.threedepict.3Depict.pkg.plist /private/var/db/receipts/net.sourceforge.3Depict.pkg.plist
-</span></p> don't forget to press enter. You will be prompted for your password for this action.</li>
+    <li>We get this one more than we thought too. Just make sure the URL and the version number of the program you were using is included. Here is a bibtex entry you can modify : <br/><code> @Misc{,<br/>
+  Title                    = {3Depict - Valued point cloud visualisation and analysis},<br/>
+  Note                     = {[Online; Accessed : D-Month-YEAR ]},<br/>
+  Comment                  = {Please use \usepackageurl with latex, to display URL in citation},<br/>
+  Url                      = {http://threedepict.sourceforge.net}<br/>
+} </code> </li>
   </ul>
 </ul>
 
@@ -99,7 +99,7 @@ too.</li>
 
     </ul>
     <ul>
-      <li><a href="http://imagepaste.nullnetwork.net/">Upload a nice screenshot online</a>, then send us a link. </li>
+      <li>Upload a nice screenshot online, then send us a link. </li>
       <li>Report bugs, or </li>
     </ul>
     <ul>
@@ -151,6 +151,7 @@ computational skill and more importantly, familiarity with the code.</li>
   <ul>
 	<li>Firstly, make sure you are familiar with C++ and compiling projects with multiple source files. Then, the best thing to do is to <a href="compiling.html">compile</a> the latest source code (.tar.gz file). This is by far the easiest under Linux, then Mac, and most difficult under windows, due to dependencies. If needed, you can run a <a href="http://www.virtualbox.org">virtual machine</a>. Now, once done, you can make your changes as you like - there is a section in the manual descri [...]
   </ul>
+
 </ul>
 
 <ul>
@@ -164,7 +165,7 @@ computational skill and more importantly, familiarity with the code.</li>
   <ul>
     <li>Well,
 try to <a href="contact.html">contact the authors</a>. These questions were written in a
-speculative fashion, and are not technically "frequently asked".</li>
+speculative fashion, and are not technically "frequently asked". There are some older questions written up <a href="questions/oldquestions.html">here</a>, for which the answers are now a bit obsolete.</li>
   </ul>
 </ul>
 </div>
diff --git a/docs/web/rss.xml b/docs/web/rss.xml
index 9c0d622..9c275d8 100644
--- a/docs/web/rss.xml
+++ b/docs/web/rss.xml
@@ -6,12 +6,48 @@
 	<title>3Depict releases</title>
 	<description>3Depict release data</description>
 	<link>http://threedepict.sourceforge.net/</link>
-	<lastBuildDate>Sat, 24 Nov 2012 00:00:00 +0000 </lastBuildDate>
-	<pubDate>Fri, 12 Apr 2013 00:00:00 +0000 </pubDate>
+	<lastBuildDate>Sun, 01 Dec 2013 00:00:00 +0000 </lastBuildDate>
+	<pubDate>Sun, 01 Dec 2013 00:00:00 +0000 </pubDate>
+
+
+	<item>
+		<title>0.0.16</title>
+		<description>source,win32,win64</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.16/3Depict-0.0.16.tar.gz/download</guid>
+		
+		<pubDate>Sun, 17 Apr 2014 00:00:00 +0000 </pubDate>
+	</item>
+
+
+	<item>
+		<title>0.0.15</title>
+		<description>source,win32,win64,macosx10.7</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.15/3Depict-0.0.15.tar.gz/download</guid>
+		
+		<pubDate>Sun, 01 Dec 2013 00:00:00 +0000 </pubDate>
+	</item>
+
+	<item>
+		<title>0.0.14</title>
+		<description>win32,win64,source</description>
+		
+		
+		<link>http://threedepict.sourceforge.net/changelog.txt</link>
+		<guid>http://sourceforge.net/projects/threedepict/files/0.0.14/3Depict-0.0.14.tar.gz/download</guid>
+		
+		<pubDate>Sun, 21 Jul 2013 00:00:00 +0000 </pubDate>
+	</item>
+
 
 	<item>
 		<title>0.0.13</title>
-		<description>macosx10.7,source</description>
+		<description>win32,win64,macosx10.7,source</description>
 		
 		
 		<link>http://threedepict.sourceforge.net/changelog.txt</link>
diff --git a/docs/web/screenshots.html b/docs/web/screenshots.html
new file mode 100644
index 0000000..8f55f8e
--- /dev/null
+++ b/docs/web/screenshots.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+	<meta content="text/html; charset=utf-8" http-equiv="content-type" />
+	<meta name="description" content="Point cloud visualisation and analysis. Useful for atom probe, lidar, and more sciencey/data-ey things"/>
+
+	<title>3Depict Screenshots </title> 
+	<link rel="stylesheet" href="style.css" type="text/css"/>
+	<link rel="icon" type="image/png" href="favicon.png"/>
+</head>
+<body>
+<div id="header">
+<h1>3Depict - Valued point cloud visualisation and analysis</h1>
+<ul id="nav">
+	<li><a href="index.html">Home</a></li>
+	<li><a href="download.html">Download</a></li>
+	<li><a href="questions.html">Questions</a></li>
+	<li><a href="documentation.html">Documentation</a></li>
+	<li><a href="contact.html">Contact</a></li>
+	<li><a href="about.html">About</a></li>
+</ul>
+</div>
+
+<div id="left">
+<div class="box">
+<h2>Have a neat image?</h2>
+<p>You should <a href="contact.html">let us know</a>, so we can add it!</p>
+</div>
+</div>
+
+
+<div id="content">
+<div id="right">
+<p>
+<center>
+<h3>Cluster analysis of Cu Precipitates in Steel</h3>
+<img src="images/cu-ppt-cluster-analysis.png"/><br/>
+<small>Courtesy, Dr. P. Styman, <a href="http://www-fim.materials.ox.ac.uk">University of Oxford, Dept. Materials</a></small>
+<br/>
+<br/>
+
+<h3>"Ladybug" robotics project data visualisation</h3>
+<img src="images/laser-data1.png"/>
+<br/>
+<br/>
+<img src="images/laser-data2.png"/>
+<br/>
+<br/>
+<hr width="35%"/>
+<h3>Atom probe data analysis</h3>
+<img src="images/resolution-example.png"/>
+</div>
+</div>
+
+
+
+</center>
+</p>
+</body></html>
diff --git a/docs/web/videos.html b/docs/web/videos.html
index 1780c31..bfe8732 100644
--- a/docs/web/videos.html
+++ b/docs/web/videos.html
@@ -5,8 +5,7 @@
   <meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"><title>Documentation</title>
   <meta name="description" content="Documentation for 3Depict" />
 
-  
-  
+  <link rel="icon" type="image/png" href="favicon.png"/>  
   <link rel="stylesheet" href="style.css" type="text/css" meda="screen"></head><body>
 <div id="header">
 <h1>3Depict - Valued point cloud visualisation and analysis</h1>
@@ -23,7 +22,29 @@
 <div id="content">
 <div id="right"><br>
 
+
+A short demo of 3Depict 0.0.8 (Oct, 2011):<br>
+<center>
+<video src="3Depict-0.0.8-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br></small>
+<small><a href="3Depict-0.0.8-screencast.ogg">download video</a></small>
+</center>
+
 <p>
+New in 0.0.4 (Jan, 2011) :<br>
+<center>
+<video src="3Depict-0.0.4-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br>
+<small><a href="3Depict-0.0.4-screencast.ogg">download video</a></small>
+</center>
+
+
+
+New in 0.0.3 (Nov, 2010) :<br>
+<center>
+<video src="3Depict-0.0.3-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br>
+<small><a href="3Depict-0.0.3-screencast.ogg">download video</a></small>
+</center>
+
+
 New in 0.0.2 (Sep, 2010) :<br>
 <center>
 <video src="3Depict-0.0.2-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br>
@@ -31,6 +52,18 @@ New in 0.0.2 (Sep, 2010) :<br>
 </center>
 <p>
 
+A short demo of 3Depict 0.0.1 (Aug, 2010):<br>
+<center>
+<video src="3Depict-0.0.1-screencast.ogg" controls="controls" type='video/ogg; codecs="theora, vorbis"'></video><br><small>
+<a href="3Depict-0.0.1-screencast.ogg">download video</a>
+</center>
+
+<center>
+<br>
+<br>
+Can't see the videos above? You can download the video using the links above, we recommend the <a href="http://www.videolan.org/vlc/">VideoLan Client</a> player for playing the downloaded files. <br> If you want in-browser playback, you might need to install <a href="http://xiph.org/quicktime/">XiphQT</a> (mac, safari) or <a href="http://xiph.org/dshow/">Xiph Directshow</a> (windows, IE). Alternately, you should be able to view this without downloading any plugins  under the <a href="htt [...]
+</center>
+
 </div>
 </div>
 </body>
diff --git a/install-sh b/install-sh
old mode 100644
new mode 100755
index 0bd91ae..e69de29
--- a/install-sh
+++ b/install-sh
@@ -1 +0,0 @@
-install-sh
diff --git a/locales/de_DE/LC_MESSAGES/3Depict.mo b/locales/de_DE/LC_MESSAGES/3Depict.mo
index cf1c383..36291f1 100644
Binary files a/locales/de_DE/LC_MESSAGES/3Depict.mo and b/locales/de_DE/LC_MESSAGES/3Depict.mo differ
diff --git a/packaging/RPM/3Depict-0.0.15-manual-pdf-loc.patch b/packaging/RPM/3Depict-0.0.15-manual-pdf-loc.patch
deleted file mode 100644
index 8eb261f..0000000
--- a/packaging/RPM/3Depict-0.0.15-manual-pdf-loc.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff -r 1b997a96b779 src/gui/mainFrame.cpp
---- src/gui/mainFrame.cpp	Sat Mar 23 17:50:44 2013 +0000
-+++ src/gui/mainFrame.cpp	Sat Mar 23 17:56:36 2013 +0000
-@@ -2546,9 +2546,9 @@
- 	string s;
- 	s=locateDataFile("3Depict-manual.pdf");
- 
--	//Also Debian makes us use the lowercase "D", so check there too.
--	if(!s.size())
--		s=locateDataFile("3depict-manual.pdf");
-+	//Also Fedora has diff dir
-+	if(!wxFileExists(wxStr(s)))
-+		s="/usr/share/doc/3Depict-0.0.8/3Depict-0.0.8-manual.pdf";
- 
- 
- 	//If we found it, use the default program associated with that data file
diff --git a/packaging/RPM/3Depict-0.0.15-font-path.patch b/packaging/RPM/3Depict-0.0.17-font-path.patch
similarity index 83%
rename from packaging/RPM/3Depict-0.0.15-font-path.patch
rename to packaging/RPM/3Depict-0.0.17-font-path.patch
index 3c13891..02f52fc 100644
--- a/packaging/RPM/3Depict-0.0.15-font-path.patch
+++ b/packaging/RPM/3Depict-0.0.17-font-path.patch
@@ -1,7 +1,7 @@
-diff -r 1b997a96b779 src/wxcomponents.cpp
---- src/wx/wxcomponents.cpp	Sat Mar 23 17:50:44 2013 +0000
-+++ src/wx/wxcomponents.cpp	Sat Mar 23 17:56:14 2013 +0000
-@@ -857,16 +857,17 @@
+diff -r 7abb69436c2b src/wx/wxcomponents.cpp
+--- src/wx/wxcomponents.cpp	Sat Aug 02 05:39:24 2014 -0400
++++ src/wx/wxcomponents.cpp	Sat Aug 02 05:40:51 2014 -0400
+@@ -547,16 +547,17 @@
  	//(Oh look Ma, I'm autoconf!)
  
  	const char *dirs[] = {	".",
diff --git a/packaging/RPM/3Depict-0.0.17-manual-pdf-loc.patch b/packaging/RPM/3Depict-0.0.17-manual-pdf-loc.patch
new file mode 100644
index 0000000..31178af
--- /dev/null
+++ b/packaging/RPM/3Depict-0.0.17-manual-pdf-loc.patch
@@ -0,0 +1,16 @@
+diff -r 7abb69436c2b src/gui/mainFrame.cpp
+--- src/gui/mainFrame.cpp	Sat Aug 02 05:39:24 2014 -0400
++++ src/gui/mainFrame.cpp	Sat Aug 02 05:40:32 2014 -0400
+@@ -2840,9 +2840,9 @@
+ 	string s;
+ 	s=locateDataFile("3Depict-manual.pdf");
+ 
+-	//Also Debian makes us use the lowercase "D", so check there too.
+-	if(!s.size())
+-		s=locateDataFile("3depict-manual.pdf");
++	//Also Fedora has diff dir
++	if(!wxFileExists(s))
++		s="/usr/share/doc/3Depict-0.0.8/3Depict-0.0.8-manual.pdf";
+ 
+ 	//FIXME: under windows, currently we use "manual.pdf"
+ 	if(!s.size())
diff --git a/packaging/RPM/3Depict-0.0.17-upstream.patch b/packaging/RPM/3Depict-0.0.17-upstream.patch
new file mode 100644
index 0000000..c82d579
--- /dev/null
+++ b/packaging/RPM/3Depict-0.0.17-upstream.patch
@@ -0,0 +1,65 @@
+diff -r 7372047ee6f9 src/common/basics.cpp
+--- src/common/basics.cpp	Sun Aug 03 16:58:06 2014 -0400
++++ src/common/basics.cpp	Sun Aug 03 17:01:04 2014 -0400
+@@ -1471,6 +1471,21 @@
+ 	return 0;
+ }
+ 
++bool isNotDirectory(const char *filename)
++{
++	struct stat statbuf;
++
++	if(stat(filename,&statbuf) == -1)
++		return false;
++
++	return (statbuf.st_mode !=S_IFDIR);
++}
++
++bool rmFile(const std::string &filename)
++{
++	return remove(filename.c_str()) == 0;
++}
++
+ #ifdef DEBUG
+ bool isValidXML(const char *filename)
+ {
+@@ -1503,27 +1518,6 @@
+ 	return true;
+ }
+ 
+-#if !defined(__WIN32__) && !defined(__WIN64)
+ 	
+-bool isNotDirectory(const char *filename)
+-{
+-	struct stat statbuf;
+-
+-	if(stat(filename,&statbuf) == -1)
+-		return false;
+-
+-	return (statbuf.st_mode !=S_IFDIR);
+-}
+-
+-bool rmFile(const std::string &filename)
+-{
+-	return remove(filename.c_str()) == 0;
+-}
+-#elif defined(__WIN32) || defined(__WIN64)
+-bool rmFile(const std::string &filename)
+-{ 
+-	return DeleteFile((const wchar_t*)filename.c_str()) == 0;
+-}
+-#endif
+ 
+ #endif
+diff -r 7372047ee6f9 src/gl/tr.cpp
+--- src/gl/tr.cpp	Sun Aug 03 16:58:06 2014 -0400
++++ src/gl/tr.cpp	Sun Aug 03 17:01:04 2014 -0400
+@@ -63,7 +63,7 @@
+ #include "common/assertion.h"
+ 
+ #include <math.h>
+-
++#include <stdlib.h>
+ 
+ #ifdef WIN32
+ #include <windows.h>
diff --git a/packaging/RPM/3Depict.spec b/packaging/RPM/3Depict.spec
index 7d943cf..8d2780b 100644
--- a/packaging/RPM/3Depict.spec
+++ b/packaging/RPM/3Depict.spec
@@ -1,5 +1,5 @@
 Name:		3Depict
-Version:	0.0.16
+Version:	0.0.17
 Release:	1%{?dist}
 Summary:	Valued 3D point cloud visualization and analysis
 Group:		Applications/Engineering
@@ -36,8 +36,7 @@ BuildRequires: qhull-devel
 Patch0: %{name}-%{version}-manual-pdf-loc.patch
 #Fedora specific font dir
 Patch1: %{name}-%{version}-font-path.patch
-#Upstream patches from 0.0.15 release tarball
-Patch2: %{name}-0.0.15-upstream.patch
+
 
 %description
 This software is designed to help users visualize and analyze 3D point clouds
@@ -51,7 +50,6 @@ useful for general scalar valued point data purposes.
 
 %patch0
 %patch1
-%patch2
 
 %build
 %configure --disable-debug-checks --enable-openmp-parallel --enable-mgl2
@@ -112,7 +110,13 @@ rm -rf %{buildroot}
 
 
 %changelog
-* Sun Apr 06 2014 D Haley <mycae(a!t)gmx.com> - 0.0.16-1
+* Sat Aug 02 2014 D Haley <mycae(a!t)gmx.com> - 0.0.17-1
+- Update to 0.0.17
+
+* Fri Jun 06 2014 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 0.0.16-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Sat Apr 26 2014 D Haley <mycae(a!t)gmx.com> - 0.0.16-1
 - Update to 0.0.16
 
 * Wed Feb 12 2014 D Haley <mycae(a!t)gmx.com> - 0.0.15-4
diff --git a/packaging/debian/3depict.install b/packaging/debian/3depict.install
old mode 100644
new mode 100755
diff --git a/packaging/debian/changelog b/packaging/debian/changelog
index 2b680f4..b44a057 100644
--- a/packaging/debian/changelog
+++ b/packaging/debian/changelog
@@ -1,8 +1,20 @@
-3depict (0.0.16-1) UNRELEASED; urgency=medium
+3depict (0.0.17-1) UNRELEASED; urgency=medium
+
+  * Update to upstream 0.0.17
+
+ -- D Haley <mycae at gmx.com>  Sun, 03 Aug 2014 23:11:45 +0100
+
+3depict (0.0.16-2) unstable; urgency=medium
+
+  * Add wx 3.0 startup patch (Closes: #746609)
+
+ -- D Haley <mycae at gmx.com>  Mon, 09 Jun 2014 22:54:00 +0100
+
+3depict (0.0.16-1) unstable; urgency=medium
 
   * Update to upstream 0.0.16
 
- -- D Haley <mycae at gmx.com>  Sun, 06 Apr 2014 23:11:51 +0100
+ -- D Haley <mycae at gmx.com>  Thu, 24 Apr 2014 00:56:00 +0100
 
 3depict (0.0.15-3) unstable; urgency=medium
 
diff --git a/packaging/debian/control b/packaging/debian/control
old mode 100644
new mode 100755
index 86e3834..b770948
--- a/packaging/debian/control
+++ b/packaging/debian/control
@@ -3,7 +3,7 @@ Section: science
 Priority: optional
 Maintainer: Debian Science Maintainers <debian-science-maintainers at lists.alioth.debian.org>
 Uploaders: D Haley <mycae at gmx.com>
-Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), libgl1-mesa-dev | libgl-dev, libpng-dev | libpng15-dev, libqhull-dev, libwxgtk2.8-dev, libftgl-dev, libxml2-dev, libmgl-dev (>= 2.0)
+Build-Depends: debhelper (>= 9), dpkg-dev (>= 1.16.1~), libgl1-mesa-dev | libgl-dev, libpng-dev | libpng15-dev, libqhull-dev, libwxgtk3.0-dev, libftgl-dev, libxml2-dev, libmgl-dev (>= 2.0), automake
 Standards-Version: 3.9.5
 Homepage: http://threedepict.sourceforge.net/index.html
 Vcs-Git: git://anonscm.debian.org/debian-science/packages/3depict.git
diff --git a/packaging/debian/copyright b/packaging/debian/copyright
old mode 100644
new mode 100755
diff --git a/packaging/debian/patches/patch-caching-bug b/packaging/debian/patches/patch-caching-bug
deleted file mode 100644
index 0b845b4..0000000
--- a/packaging/debian/patches/patch-caching-bug
+++ /dev/null
@@ -1,35 +0,0 @@
-Bug fix for 0.0.15, from upstream : http://hg.code.sf.net/p/threedepict/code/rev/7fba7ef21117
---- 3depict-0.0.16.orig/src/backend/filters/ionColour.cpp
-+++ 3depict-0.0.16/src/backend/filters/ionColour.cpp
-@@ -82,7 +82,7 @@
- 	if(cacheOK)
- 	{
- 		ASSERT(filterOutputs.size());
--		propagateStreams(dataIn,getOut,STREAM_TYPE_IONS,false);
-+		propagateStreams(dataIn,getOut,getRefreshBlockMask(),true);
- 
- 		propagateCache(getOut);
- 
---- 3depict-0.0.16.orig/src/backend/filters/rangeFile.cpp
-+++ 3depict-0.0.16/src/backend/filters/rangeFile.cpp
-@@ -107,7 +107,7 @@
- 		//We don't cache anything but our modification
- 		//to the ion stream data types. so we propagate
- 		//these.
--		propagateStreams(dataIn,getOut,STREAM_TYPE_IONS,false);
-+		propagateStreams(dataIn,getOut,getRefreshBlockMask(),true);
- 			
- 		return 0;
- 	}
---- 3depict-0.0.16.orig/src/backend/filters/transform.cpp
-+++ 3depict-0.0.16/src/backend/filters/transform.cpp
-@@ -189,7 +189,8 @@
- 	//use the cached copy if we have it.
- 	if(cacheOK)
- 	{
--		propagateStreams(dataIn,getOut, STREAM_TYPE_IONS,false);
-+		//Propagate non-ion-types into output
-+		propagateStreams(dataIn,getOut, getRefreshBlockMask(),true);
- 		propagateCache(getOut);
- 		return 0;
- 	}
diff --git a/packaging/debian/patches/series b/packaging/debian/patches/series
index 90196aa..a50b6d2 100644
--- a/packaging/debian/patches/series
+++ b/packaging/debian/patches/series
@@ -1,4 +1,2 @@
 debian-desktop-naming.patch
 lowercase-textdomain.patch
-FTGL-lowercase.patch
-patch-caching-bug
diff --git a/packaging/debian/rules b/packaging/debian/rules
index 867f70e..7de271f 100755
--- a/packaging/debian/rules
+++ b/packaging/debian/rules
@@ -1,10 +1,12 @@
 #!/usr/bin/make -f
 
 %:
-	dh $@ --parallel
+	dh $@ --parallel 
 
 override_dh_auto_configure: 
-	dh_auto_configure -- --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info --enable-openmp-parallel --disable-debug-checks --with-libpng-link="-lpng" --with-libpng-flags="-L/lib" --with-ftgl-prefix="/usr" --enable-mgl2
+	LDFLAGS="$(LDFLAGS) -Wl,--as-needed" dh_auto_configure -- --prefix=/usr \
+		 --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info \
+		 --enable-openmp-parallel --disable-debug-checks --with-libpng-link="-lpng" --with-libpng-flags="-L/lib" --with-ftgl-prefix="/usr" 
 
 
 override_dh_clean:
@@ -20,6 +22,7 @@ override_dh_clean:
 
 	dh_clean 
 
+
 override_dh_auto_install: 
 	dh_auto_install
 	
@@ -27,7 +30,7 @@ override_dh_auto_install:
 	mv $(CURDIR)/debian/3depict/usr/bin/3Depict $(CURDIR)/debian/3depict/usr/bin/3depict
 
 	mkdir -p $(CURDIR)/debian/3depict/usr/share/doc/3depict/
-	echo "Copyright" `date +%Y`" D Haley <mycae at yahoo.com>" > $(CURDIR)/debian/3depict/usr/share/doc/3depict/copyright
+	echo "Copyright 2013 D Haley <mycae at yahoo.com>" > $(CURDIR)/debian/3depict/usr/share/doc/3depict/copyright
 	echo "See /usr/share/common-licenses/GPL-1 for copyright info" >> $(CURDIR)/debian/3depict/usr/share/doc/3depict/copyright
 
 	#Install files that cannot be handled by .install due to rename
diff --git a/packaging/deps/getDeps b/packaging/deps/getDeps
index 438605f..aa6866a 100755
--- a/packaging/deps/getDeps
+++ b/packaging/deps/getDeps
@@ -49,9 +49,9 @@ function setMacDeps {
 	#Dependency ID, URL and name
 	DEPIDS=( 0)
 	DEPNAMES=( mathgl)
-	DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%202.1.3/mathgl-2.1.3.1.tar.gz/download)
-	DEPFILENAMES=( mathgl-2.1.3.1.tar.gz)
-	DEPMDSUM=( 1476ea6fd32938ab221fe169025747ed)
+	DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%202.2.2/mathgl-2.2.2.1.tar.gz/download)
+	DEPFILENAMES=( mathgl-2.2.2.1.tar.gz)
+	DEPMDSUM=( cdee2784ce2f18ab9014bbd204b8589f)
 	
 }
 
@@ -100,18 +100,18 @@ function installMacPorts {
 function setSuseDeps {
 	DEPIDS=( 0)
 	DEPNAMES=( mathgl)
-	DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download)
-	DEPFILENAMES=( mathgl-1.11.2.tar.gz)
-	DEPMDSUM=( acd33e68911d9506f60d769dce23f95e)
+	DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%202.2.2/mathgl-2.2.2.1.tar.gz/download)
+	DEPFILENAMES=( mathgl-2.2.2.1.tar.gz)
+	DEPMDSUM=( cdee2784ce2f18ab9014bbd204b8589f)
 
 }
 
-function setCentOS5Deps {
+function setCentOS6Deps {
 	DEPIDS=( 0)
 	DEPNAMES=( mathgl)
-	DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%201.11.2/mathgl-1.11.2.tar.gz/download)
-	DEPFILENAMES=( mathgl-1.11.2.tar.gz)
-	DEPMDSUM=( acd33e68911d9506f60d769dce23f95e)
+	DEPURLS=( http://sourceforge.net/projects/mathgl/files/mathgl/mathgl%202.2.2/mathgl-2.2.2.1.tar.gz/download)
+	DEPFILENAMES=( mathgl-2.2.2.1.tar.gz)
+	DEPMDSUM=( cdee2784ce2f18ab9014bbd204b8589f)
 
 }
 
@@ -228,7 +228,7 @@ function handleLinuxDistro()
 			elif [ x$DISTRIBUTOR == x"Fedora" ] ; then
 				LINUXDISTRO="RedhatLike"
 			elif [ x$DISTRIBUTOR == x"CentOS" ] ; then
-				LINUXDISTRO="RedhatLike"
+				LINUXDISTRO="CentOS6"
 			elif [ x`echo $DISTRIBUTOR  | grep -i redhat` != x"" ] ; then
 				LINUXDISTRO="RedhatLike"
 			else
@@ -269,30 +269,43 @@ function handleLinuxDistro()
 		RedhatLike)
 			echo "System appears to be redhat like"
 
-			sudo yum groupinstall "Development Tools" && sudo yum install yum-utils && sudo yum-builddep 3Depict
+			sudo yum groupinstall "Development Tools" 
+			if [ $? -ne 0 ] ; then
+				echo "Yum installation failed"
+				exit 1
+			fi
 			
+			sudo yum install yum-utils 
 			if [ $? -ne 0 ] ; then
-				echo "Failed to install build dependencies"
+				echo "Yum installation failed"
+				exit 1
+			fi
+			sudo yum-builddep 3Depict
+			if [ $? -ne 0 ] ; then
+				echo "Yum installation failed"
 				exit 1
-			else
-				echo "All done."
-				exit 0
 			fi
 
 		;;
 		CentOS6)
 			echo "System appears to be CentOS6-like?"
 			
-			sudo yum groupinstall "Development Tools" && sudo yum install yum-utils && sudo yum install libxml2-devel ftgl-devel wxgtk-devel qhull-devel mathgl-devel
+			sudo yum groupinstall "Development Tools" && sudo yum install yum-utils libxml2-devel wxGTK-devel gsl-devel rpmdevtools
+			if [ $? -ne 0 ] ; then
+				echo "Yum installation failed"
+				exit 1
+			fi
+			
 
 			echo " OK, so this gets tricky. Centos doesn't ship mathgl. So we have to grab it from fedora's Git repository, and build the RPM, the install that."
 
 	
 			echo "Getting mgl dependencies"
-			sudo yum install gsl-devel libpng-devel libtool-ltdl-devel libtool swig freeglut-devel hdf-devel \
-				hdf5-static libjpeg-devel libtiff-devel fltk-devel qt4-devel wxGTK-devel giflib-devel \
-				autoconf automake libtool info texi2html texinfo-tex
-			if [ $? -eq 0 ] ; then
+			sudo yum install gsl-devel libpng-devel libtool-ltdl-devel libtool swig freeglut-devel \
+				libjpeg-devel libtiff-devel qt4-devel wxGTK-devel giflib-devel \
+				info texi2html texinfo-tex cmake libXmu-devel lua-devel python-devel
+			echo "Return code :"  $?
+			if [ $? -ne 0 ] ; then
 				echo "Yum installation failed"
 				exit 1
 			fi
@@ -300,24 +313,25 @@ function handleLinuxDistro()
 			if [ x`which git` == x"" ] ; then
 				echo "Installing git...."
 				sudo yum install git
-				if [ $? -eq 0 ] ; then
+				if [ $? -ne 0 ] ; then
 					echo "Yum git installation failed"
 					exit 1
 				fi
 			fi
+			
+			if [ ! -d mathgl ] ; then
 
-			git clone git://pkgs.fedoraproject.org/mathgl.git
-			if [ $? -eq 0 ] ; then
-				echo "git clone failed - couldn't retreive mathgl spec and patch data"
-				exit 1
-			elif [ ! -f mathgl ]  ; then
-				echo "Git clone succeded, but couldn't locate checkout dir, \"mathgl\""
-				exit 1
+				git clone git://pkgs.fedoraproject.org/mathgl.git
+				if [ $? -ne 0 ] ; then
+					echo "git clone failed - couldn't retreive mathgl spec and patch data"
+					exit 1
+				elif [ ! -d mathgl ]  ; then
+					echo "Git clone succeded, but couldn't locate checkout dir, \"mathgl\""
+					exit 1
+				fi
 			fi
 
 			cd mathgl
-			# We want this version
-			git checkout 152ad15
 
 			if [ $? -ne 0 ] ; then
 				echo  "Something went wrong when trying to check out the version of the repository we wanted"
@@ -335,33 +349,28 @@ function handleLinuxDistro()
 			cp mathgl.spec ~/rpmbuild/SPECS/
 			cp *patch ~/rpmbuild/SOURCES/
 
-			MATHGLVER=1.11.2
+			MATHGLVER=2.2.2.1
 			setCentOS6Deps			
 			pushd ~/rpmbuild/SOURCES/
 			runDownloads
 			checkHashes
-			mv sources/mathgl-${MATHGLVER}.tar..gz .
-			popd
-
-			pushd ~/rpmbuild/SPEC/
-			rpmbuild -ba mathgl.spec
-
-			if [ $? -ne 0 ] ; then
-				echo  "Runing RPMBuild failed - but we are close to getting mathgl installed, so please fix rpmbuild, and run rpmbuild -ba mathgl.spec from ~/rpmbuild/SPEC/"
-				exit 1
-			fi
+			mv sources/mathgl-${MATHGLVER}.tar.gz .
 			popd
 
-
-			ARCH=`uname -m`
-			pushd ~/rpmbuild/RPMS/${ARCH}/
-			rpm -i mathgl-${MATHGLVER}*rpm
-
-			if [ $? -ne 0 ] ; then 
-				echo "So we built the RPMs OK, but for some reason we cannot isntall them. Not sure whats going on here. Aborting."
-				exit 1
-			fi
-			popd
+			#HACK : Strip out the optional buildrequires from the spec file
+			for i in hdf-devel hdf5-static fltk-devel qtwebkit-devel  libharu-devel octave-devel openmpi-deve mpich-devel
+			do
+				sed -i "s/$i//" ~/rpmbuild/SPECS/mathgl.spec
+			done
+			
+			sed -i 's/^\s*BuildRequires:\s*$//' ~/rpmbuild/SPECS/mathgl.spec
+
+			echo "---------------- NOTICE ----------------"
+			echo " CentOS is missing most of the optional dependencies for mathgl. "
+			echo " this script cannot do the work required to install mathgl.  "
+			echo " An RPM \"Spec\" file has been left in ~/rpmbuild/SPECS/"
+			echo " go there, tweak that file and use \"rpmbuild -ba mathgl.spec\" to build it."
+			echo " This is not straightforwards - work is needed to make centos and mathgl play nice"
 			exit 0;
 		;;
 		SuseLike)
@@ -481,7 +490,7 @@ case $OS_NAME in
 		HASH_SUM=`md5 sources/$j | awk {'sub(/^.*= [ \t]*/, "", $0); print $0;'}`
 		;;
 	*)
-		HASH_SUM=`md5sum sources/$j | awk {'sub(/^.*= [ \t]*/, "", $0); print $0;'}`
+		HASH_SUM=`md5sum sources/$j | awk {'sub(/^.*= [ \t]*/, "", $0); print $0;'} | awk '{print $1}'`
 		;;
 esac
 
@@ -750,12 +759,13 @@ do
 				#patch mgl/mgl_export.cpp < ../../sources/mgl_export.patch 		
 				#After upgrade to 1.5.13, this patch required. 
 				#patch mgl/mgl_data_png.cpp < ../../sources/mgl_data_png.patch 
-				patch src/obj.cpp < ../../patches/macosx/mathgl2/diff-obj.c.patch
-				patch src/prc/writePRC.h < ../../patches/macosx/mathgl2/diff-prc-writePRC.h.patch
+				#patch src/obj.cpp < ../../patches/macosx/mathgl2/diff-obj.c.patch
+				#patch src/prc/writePRC.h < ../../patches/macosx/mathgl2/diff-prc-writePRC.h.patch
+				cmake .
+				patch ./CMakeCache.txt < ../../../../patches/0.0.17/macosx/mathgl2/CMakeCache.txt.patch
 			fi
 			#./configure --disable-gsl $PNGLIBS
 			cmake .
-			cmake .
 
 
 			if [ $? -ne 0 ] ; then
diff --git a/packaging/mac/3package.sh b/packaging/mac/3package.sh
index 4d9b529..7fee2f3 100755
--- a/packaging/mac/3package.sh
+++ b/packaging/mac/3package.sh
@@ -45,6 +45,24 @@ if [ x`grep ${INFO_PLIST} -Depict` != x"" ] ; then
 	exit 1
 fi
 
+#ensure that we have some .vfm files in here
+if [ x`find ./ -name \*.vfm` == x"" ] ; then
+	echo "No VFM files (mathgl fonts) found!"
+	exit 1 
+fi
+
+#ensure that we have some .pdf files in here
+if [ x`find ./ -name \*.pdf` == x"" ] ; then
+	echo "No PDF files (manual) found!"
+	exit 1 
+fi
+
+#ensure that some .mo (translation files) are here
+if [ x`find ./ -name \*.mo` == x"" ] ; then
+	echo "No mo files (translations) found!"
+	exit 1 
+fi
+
 #--
 
 ARCHIVE_FILENAME=`echo "${BUILT_PROGRAMS_DIR}/${PROGRAM_NAME}-${VERSION}-${MAC_OS_VER}.pkg"`
diff --git a/packaging/mac/makeMacOSXApp b/packaging/mac/makeMacOSXApp
index 054b4b8..0fe5b5d 100755
--- a/packaging/mac/makeMacOSXApp
+++ b/packaging/mac/makeMacOSXApp
@@ -34,6 +34,7 @@ if [ $1 = '--update-config=yes' ]; then
 
 	make clean
 fi
+read -p "have you changed the makefile?" yn
 
 make -j8
 
@@ -51,6 +52,7 @@ cp data/textures/tex-source/3Depict-icon.icns ./3Depict.app/Contents/Resources/3
 touch ./3Depict.app/Contents/PkgInfo
 touch ./3Depict.app/Contents/info.plist
 #copy textures
+cp ./data/* ./3Depict.app/Contents/Resources/
 cp ./data/textures/* ./3Depict.app/Contents/Resources/textures/
 cp ./data/textures/tex-source/3Depict-icon.icns ./3Depict.app/Contents/Resources
 
diff --git a/packaging/makeTarball.sh b/packaging/makeTarball.sh
index 6b3c18e..6d58c6f 100755
--- a/packaging/makeTarball.sh
+++ b/packaging/makeTarball.sh
@@ -75,6 +75,9 @@ fi
 
 #Various release-time checks
 #----
+
+echo "--------- RUNNING SANITY CHECKS -------"
+
 #Check version
 VER=`ls 3depict-*gz | sed 's/^3depict-\([0-9\.]*\).tar.gz$/\1/' `
 echo "Version is apparently :" $VER
@@ -90,8 +93,8 @@ if [ x"`grep $VER ChangeLog`" == x"" ] ; then
 	echo " WARNING: Program version not set to match between configure.ac. and ChangeLog">> $MSG_FILE
 fi
 
-if [ x"`grep PROGRAM_VERSION src/common/basics.cpp | grep $VER`" == x"" ] ; then
-	echo " WARNING: Program version not set to match between configure.ac. and basics.cpp">> $MSG_FILE
+if [ x"`grep PROGRAM_VERSION src/common/constants.cpp | grep $VER`" == x"" ] ; then
+	echo " WARNING: Program version not set to match between configure.ac. and constants.cpp">> $MSG_FILE
 fi
 
 #Check version number in deb & rpm
@@ -151,9 +154,17 @@ if [ x"$SOMEFILES" != x"" ] ; then
 fi
 
 #Check that PDF manual is built
-if [ ! -f docs/manual-latex/manual.pdf ] ; then
+PDF_FILE=docs/manual-latex/manual.pdf
+if [ ! -f  ] ; then
 	echo " WARNING : PDF manual was not found -- has it been compiled?" >> $MSG_FILE
 	echo "$FILES" >> $MSG_FILE
+else 
+	#Check PDF is actually a pdf
+	if [ x"`file $PDF_FILE | grep "PDF document" `" == x""  ] ; then
+		echo " WARNING : PDF manual found, but does not appear to be a valid PDF?" >> $MSG_FILE
+		echo "$FILES" >> $MSG_FILE
+	
+	fi
 fi
 
 #Check for outstanding mercurial changes
@@ -170,9 +181,9 @@ fi
 
 #Run licensecheck over files, if available
 if [ x`which licensecheck` != x"" ] ; then
-	LIC_CHECK_OUT=`licensecheck -r  --ignore ".*\.(sh|sci|py|tex)$" | grep -v "GPL (v3 or later)" | grep -v "GENERATED FILE" `
+	LIC_CHECK_OUT=`licensecheck -r  --ignore=".*\.(sh|sci|py|tex)$" . | grep -v "GPL (v[23] or later)" | grep -v "GENERATED FILE" | grep -v "MPL"  | grep -v "tarball/"`
 
-	if [ x$LIC_CHECK_OUT != x"" ] ; then
+	if [ x"$LIC_CHECK_OUT" != x"" ] ; then
 		echo "WARNING:" $LIC_CHECK_OUT >> $MSG_FILE
 	fi
 fi
diff --git a/packaging/mingw-debian-cross/bootstrap.sh b/packaging/mingw-debian-cross/bootstrap.sh
index 0a7acf7..1529e17 100755
--- a/packaging/mingw-debian-cross/bootstrap.sh
+++ b/packaging/mingw-debian-cross/bootstrap.sh
@@ -36,6 +36,19 @@ fi
 if [ $HOST_VAL != "x86_64-w64-mingw32" ] && [ $HOST_VAL != i686-w64-mingw32 ] ; then
 	echo "Unknown HOST_VAL"
 	exit 1
+else 
+	case $HOST_VAL in
+		x86_64-w64-mingw32)
+			BITS_VAL=64
+			;;
+		i686-w64-mingw32)
+			BITS_VAL=32
+			;;
+		*)
+			echo "Should not have got here - bug!"
+			exit 1
+			;;
+	esac
 fi
 
 #----
@@ -58,9 +71,8 @@ if [ `id -u` -eq 0 ]; then
 	echo " If you know what you are doing, you can disable this check, but be aware you _can_ break your system by doing this."
 	exit 1;
 fi
-#1) Filezilla wxwidgets patch for 64 bit support under mingw
 #2) own patch for fixing wx-config's lack of sysroot support
-PATCHES_WXWIDGETS_PRE="wxWidgets-2.8.12-mingw64-1.patch configure-wxbool-patch"
+PATCHES_WXWIDGETS_PRE=""
 PATCHES_WXWIDGETS_POST="wx-config-sysroot.patch"
 #1) Zlib no longer needs to explicitly link libc, and will fail if it tries
 PATCHES_ZLIB="zlib-no-lc.patch"
@@ -75,8 +87,7 @@ PATCHES_GETTEXT="gettext-disable-tools"    #gettext-win32-prefix
 
 PATCHES_GLEW="glew-makefile.base"
 
-#Disable broken build for "widgets" directory, which we don't need
-PATCHES_MATHGL="mathgl-disable-widgets"
+PATCHES_MATHGL=""
 
 PATCH_LIST="$PATCHES_WXWIDGETS_PRE $PATCHES_WXWIDGETS_POST $PATCHES_GSL $PATCHES_ZLIB $PATCHES_LIBPNG $PATCHES_GETTEXT $PATCHES_FTGL $PATCHES_GLEW $PATCHES_MATHGL $PATCHES_FTGL_POSTCONF"
 
@@ -123,7 +134,7 @@ function install_mingw()
 	GET_PACKAGES="";
 	for i in $MINGW_PACKAGES
 	do
-		if [ x`apt-cache pkgnames --installed $i` != x"$i" ] ; then
+		if [ x`dpkg --get-selections | grep ^$i | awk '{print $1}'  ` != x"$i" ] ; then
 			GET_PACKAGES="$GET_PACKAGES $i";
 		fi
 	done
@@ -139,7 +150,7 @@ function grabDeps()
 {
 	pushd deps 2>/dev/null
 
-	DEB_PACKAGES="expat freetype ftgl gettext gsl libpng libxml2 mathgl qhull tiff wxwidgets2.8 zlib glew"
+	DEB_PACKAGES="expat freetype ftgl gettext gsl libpng libxml2 mathgl qhull tiff wxwidgets3.0 zlib glew"
 	if [ x$DIST_NAME == x"Ubuntu" ] || [ x$DIST_NAME == x"LinuxMint" ] ; then 
 		LIBJPEGNAME="libjpeg6b"
 	else
@@ -163,6 +174,13 @@ function grabDeps()
 	if [ x"$GET_PACKAGES" != x"" ] ; then
 		apt-get source $GET_PACKAGES
 
+		if [ $? -ne 0 ] ; then
+			echo "Package retrieval failed"
+			echo "apt-get source failed... Maybe check internet connection, then try updating package database, then re-run?"
+			echo " other possibilities could include, eg, that the required package is not available in the debian archive.."
+			exit 1
+		fi
+
 		for i in $GET_PACKAGES
 		do
 			grep -v $i ../build-status > tmp
@@ -174,11 +192,7 @@ function grabDeps()
 
 		done
 	fi
-	
-	if [ $? -ne 0 ] ; then
-		echo "apt-get source failed... Maybe check internet connection, then try updating package database, then re-run?"
-		exit 1
-	fi
+
 
 	#Move debian stuff into packages folder
 	if [ x"$GET_PACKAGES" != x"" ] ; then
@@ -350,7 +364,7 @@ function build_glew()
 	fi
 
 	#Perform dynamic modification of patch
-	if [ x`grep patches/glew-makefile.base HOST_VAL` == x""   ||  x`grep patches/glew-makefile.base BASEDIR` == x"" ] ; then
+	if [ x"`grep HOST_VAL patches/glew-makefile.base`" == x""  -o   x"`grep BASEDIR patches/glew-makefile.base`" == x"" ] ; then
 		echo "patches/glew-makefile did not contain replacement keywords"
 		exit 1
 	fi
@@ -383,6 +397,10 @@ function build_glew()
 	popd >/dev/null
 	popd >/dev/null
 
+	#remove static library, as this can be incorrectly caught by linker
+	# leading to confusing messages
+	rm ${BASE}/lib/libglew*.a
+
 	echo "glew" >> $BUILD_STATUS_FILE
 }
 
@@ -596,14 +614,18 @@ function build_qhull()
 
 	make clean
 
-	./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "qhull configure failed"; exit 1; } 
+	sed -i "s/ gcc$/${HOST_VAL}-gcc/" Makefile
+	sed -i "s/ g++$/${HOST_VAL}-g++/" Makefile
 
-	make -j $NUM_PROCS || { echo "qhull build failed"; exit 1; } 
-	
+	make SO="dll" -j $NUM_PROCS 
+	find ./ -name \*dll -exec cp {} ${BASE}/bin/	
+	make SO="dll" -j $NUM_PROCS || { echo "qhull build failed"; exit 1; } 
 	make install DESTDIR="$BASE"|| { echo "qhull install failed"; exit 1; } 
 
 	popd >/dev/null
 	popd >/dev/null
+
+	ln -s ${BASE}/include/libqhull ${BASE}/include/qhull
 	
 	FIX_LA_FILE_ARG=libqhull
 	fix_la_file
@@ -729,7 +751,21 @@ function build_wx()
 
 	pushd ./bin/
 	unlink wx-config
-	ln -s `find ${BASE}/lib/wx/config/ -name \*release-2.8` wx-config
+
+
+	#Search for the wx-config file. It get installed into /lib/wx, but has
+	# unusual naming conventions
+	WX_CONFIG_FILE=`find ${BASE}/lib/wx/config/ -type f -executable -name \*release-\*`
+	if [ x$WX_CONFIG_FILE == x"" ] ; then
+		WX_CONFIG_FILE=`find ${BASE}/lib/wx/config/ -type f  -executable -name \*-unicode-\*`
+	fi
+
+	if [ x$WX_CONFIG_FILE == x"" ] ; then
+		echo "Couldn't find the wx-config script."
+		exit 1
+	fi
+
+	cp $WX_CONFIG_FILE wx-config 
 	APPLY_PATCH_ARG=$PATCHES_WXWIDGETS_POST
 	PATCH_LEVEL=0
 	applyPatches
@@ -738,7 +774,7 @@ function build_wx()
 	popd
 
 	pushd ./lib/
-	ln -s wx-2.8/wx/ wx
+	ln -s wx-3.0/wx/ wx
 	popd
 
 
@@ -766,7 +802,7 @@ function build_freetype()
 
 	pushd freetype-[0-9]*
 	make clean
-	./configure --host=$HOST_VAL --enable-shared --disable-static --prefix=/ || { echo "freetype configure failed"; exit 1; } 
+	./configure --host=$HOST_VAL --enable-shared --disable-static --without-png --prefix=/ || { echo "freetype configure failed"; exit 1; } 
 
 	make -j $NUM_PROCS || { echo "freetype build failed"; exit 1; } 
 	
@@ -882,27 +918,28 @@ function build_mathgl()
 	APPLY_PATCH_ARG=$PATCHES_MATHGL
 	applyPatches
 
-	libtoolize --copy --force
-	aclocal
-	automake --add-missing
+	#Strip invalid linker flags from cmake's link instructions
+	rm CMakeCache.txt
+	#Strip invalid linker flags from cmake's link instructions
+	find ./ -name link.txt -exec sed -i 's/-Wl,-z,relro//'  {} \;
+	cmake -DCMAKE_TOOLCHAIN_FILE=../../patches/cmake-toolchain$BITS_VAL
+	#Strip invalid linker flags from cmake's link instructions
+	find ./ -name link.txt -exec sed -i 's/-Wl,-z,relro//'  {} \;
 
-	autoreconf
-	LIBS="${LIBS} -lz" ./configure --host=$HOST_VAL --disable-gsl --disable-pthread --enable-shared --disable-static --prefix=/ || { echo "mathgl configure failed"; exit 1; } 
 
-	#RPATH disable hack
-	sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool
-	sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
+	cmake -DCMAKE_TOOLCHAIN_FILE=../../patches/cmake-toolchain$BITS_VAL
 
-	#Hack to fix mathgl's libpng dll search
-	mkdir -p $BASE/lib/.libs/
-	ln -s $BASE/lib/libpng.dll $BASE/lib/.libs/libpng.dll.a 
+	make -j $NUM_PROCS
 
-	make -j $NUM_PROCS || { echo "mathgl build failed"; exit 1; } 
-	
-	make install DESTDIR="$BASE"|| { echo "mathgl install failed"; exit 1; } 
-	
-	#DLL needs to be copied into lib manually
+	if [ x"`find ./ -name \*dll`" == x"" ] ; then
+		echo "Did cmake fail to make a DLL? Cmake rarely builds cleanly, but I should be able to find the DLL..."
+		exit 1
+	fi
+		
 	cp -p .libs/${NAME}-[0-9]*.dll $BASE/lib/ 
+	
+	cp -R include/mgl2 ${BASE}/include
+	ln -s ${BASE}/include/mgl2 ${BASE}/include/mgl
 
 	popd >/dev/null
 	popd >/dev/null
@@ -956,6 +993,12 @@ function build_ftgl()
 
 	#MAkefile refers to ECHO variable for reporting completion, which does not exist
 	sed -i 's/ECHO_C =/ECHO=echo/' Makefile
+	sed -i "s at -I//@-I${BASE}/@" Makefile
+	sed -i 's/ECHO_C =/ECHO=echo/' Makefile
+	
+	#HACK - find all -I// and -L// and replace them with something sane
+	find ./ -name Makefile -exec sed -i "s at -I//@-I${BASE}/@" {} \;
+	find ./ -name Makefile -exec sed -i "s at -L//@-L${BASE}/@" {} \;
 
 	make -j $NUM_PROCS || { echo "ftgl build failed"; exit 1; } 
 	
@@ -1058,34 +1101,66 @@ function build_3Depict()
 
 	CONF_FLAG="--host=$HOST_VAL"
 	if [ $IS_RELEASE -ne 0 ] ; then
-		CONF_FLAG="$CONF_FLAG --disable-debug-checks"
+		CONF_FLAG="$CONF_FLAG --disable-debug-checks --enable-openmp-parallel"
 	fi
 
-	CFLAGS="$CFLAGS -DUNICODE" CPPFLAGS="${CPPFLAGS} -DUNICODE" ./configure  $CONF_FLAG
+	FTGL_CFLAGS="-I${BASE}/include/freetype/" CFLAGS="$CFLAGS -DUNICODE" CPPFLAGS="${CPPFLAGS} -DUNICODE" ./configure  $CONF_FLAG
 
 	if [ $? -ne 0 ] ; then
 		echo "Failed 3Depict configure"
 		exit 1
 	fi
 
-	#HACK - strip all makefiles of -D_GLIBCXX_DEBUG
-	#	mingw & GLIBCXX_DEBG don't play nice
-	find ./ -name Makefile -exec sed -i 's/-D_GLIBCXX_DEBUG//g' {} \;
+	#sanity check that windres is activated
+	if [ x`grep HAVE_WINDRES_TRUE config.log | grep '#' ` != x"" ] ; then
+		echo "Windres appears to be commented out. Shouldn't be for windows builds"
+		exit 1
+	fi
+
+	#Check that wx's manifest matches our arch
+	MANIFEST=`find ../../include/ -name wx.manifest`
+	if [ x"$MANIFEST" == x"" ] ; then
+		echo "Didnt' find manifest!"
+		exit 1
+	fi
+	case $BITS_VAL in
+		32)
+			MANIFEST_TARG=x86
+			MANIFEST_NOT=amd64
+			;;
+		64)
+			MANIFEST_TARG=amd64
+			MANIFEST_NOT=x86
+			;;
+	esac
+
+	if [  x"`grep -i $MANIFEST_TARG $MANIFEST`" == x"" ] ; then
+		echo "Manifest arch does not match!"	
+		echo " file examined: $MANIFEST"
+		echo " Expected :" $MANIFEST_TARG 
+		exit 1
+	fi
+
+	if [  x"`grep -i $MANIFEST_NOT $MANIFEST`" != x"" ] ; then
+		echo "Manifest arch does not match!"	
+		echo " file examined: $MANIFEST"
+		echo " This should be missing, but isnt:" $MANIFEST_NOT 
+		exit 1
+	fi
 
+       #HACK - strip all makefiles of -D_GLIBCXX_DEBUG
+       #	mingw & GLIBCXX_DEBG don't play nice
+	find ./ -name Makefile -exec sed -i 's/-D_GLIBCXX_DEBUG//g' {} \;
+	#HACK - find all -I// and -L// and replace them with something sane
+	find ./ -name Makefile -exec sed -i "s at -I//@-I${BASE}/@" {} \;
+	find ./ -name Makefile -exec sed -i "s at -L//@-L${BASE}/@" {} \;
+	
 	make -j$NUM_PROCS
 	if [ $? -ne 0 ] ; then
 		echo "Failed 3Depict build"
 		exit 1
 	fi
 
-	if [ $IS_RELEASE -ne 0 ] ; then
-		#Sanity check that we are actually in debug mode
-		TEST_FLAG=`./3Depict --help  2>&1 | grep "\-\-test"`
-		if [ x"$TEST_FLAG" != x"" ] ; then
-			echo "3Depict\'s Unit tests available, but should not be, when in release mode" 
-			exit 1
-		fi
-	fi
 
 
 	#if the locales are missing, try to rebuild them
@@ -1117,10 +1192,6 @@ function make_package()
 	pushd ./code/3Depict 2> /dev/null
 
 	NSI_FILE=./windows-installer.nsi
-	if [ ! -f $NSI_FILE ] ; then
-		echo "NSI file missing whilst trying to build package"
-		exit 1;
-	fi
 
 	#copy as needed
 	# Due to debian bug : #704828, makensis cannot correctly handle symlinks,
@@ -1129,9 +1200,28 @@ function make_package()
 		cp ./packaging/mingw-debian-cross/windows-installer.nsi .
 	fi
 
+	
+	if [ ! -f $NSI_FILE ] ; then
+		echo "NSI file missing whilst trying to build package"
+		exit 1;
+	fi
+
+	#Check NSI file has PROGRAMFILES / PROGRAMFILES64 set
+	if [ x"`grep PROGRAMFILES64 $NSI_FILE`" == x"" -a $BITS_VAL == 64 ] ; then
+		echo "NSI file should contain PROGRAMFILES64 output path."
+		exit 1;
+	else
+		if [ x"`grep PROGRAMFILES64 $NSI_FILE`" != x"" -a $BITS_VAL == 32 ] ; then
+			echo "NSI file contained 64 bit install dir, but this is 32"
+			exit 1;
+		fi
+	fi
+	
+	
+	 
 
 	echo -n " Copying dll files... "
-	SYSTEM_DLLS="(ADVAPI32.dll|COMCTL32.DLL|COMDLG32.DLL|GDI32.dll|KERNEL32.dll|ole32.dll|OLEAUT32.dll|RPCRT4.dll|SHELL32.DLL|USER32.dll|WINMM.DLL|WINSPOOL.DRV|WSOCK32.DLL|GLU32.dll|OPENGL32.dll|msvcrt.dll)"
+	SYSTEM_DLLS="(ADVAPI32.dll|COMCTL32.DLL|COMDLG32.DLL|GDI32.dll|KERNEL32.dll|ole32.dll|OLEAUT32.dll|RPCRT4.dll|SHELL32.DLL|USER32.dll|WINMM.DLL|WINSPOOL.DRV|WSOCK32.DLL|GLU32.dll|OPENGL32.dll|msvcrt.dll|WS2_32.dll)"
 
 	DLL_FILES=`${HOST_VAL}-objdump -x src/3Depict.exe | grep 'DLL Name:' | awk '{print $3}' | egrep -i -v ${SYSTEM_DLLS}`
 	FOUND_DLLS=""
@@ -1152,7 +1242,7 @@ function make_package()
 		for i in $DLL_FILES
 		do
 			HAVE_DLL=0
-			for j in ${BASE}/lib/ ${BASE}/bin/ $SYS_DIR
+			for j in ${BASE}/lib/ ${BASE}/bin/ $SYS_DIR /usr/${HOST_VAL}/lib/
 			do
 				FIND_RES=`find $j -name $i | head -n 1`
 				if [ x$FIND_RES != x"" ] ; then
@@ -1185,24 +1275,23 @@ function make_package()
 		popd > /dev/null
 	fi
 
-	if [ x"`cat windows-installer.nsi | grep INSERT_DLLS_HERE`" == x"" ]  ||  [ x"`cat windows-installer.nsi | grep INSERT_UNINST_DLLS_HERE`" == x"" ] ; then
-		echo "DLL insertion/removal tokens not found. Was looking for INSERT_DLLS_HERE and INSERT_UNINST_DLLS_HERE"
-		exit 1
-	fi
-
-	
-	#Check that each file in the data/textures/ dir is listed in the NSI file
-	FILE_MISSED=0
-	for i in  data/textures/*png
+	#Check for differeent DLL types (eg 32/64)
+	DLL_FILE_OUT="";
+	for i in $FOUND_DLLS
 	do
-		FILE_GREP=`grep "data\\textures\\$i" windows-installer.nsi`
-		if [ x${FILE_GREP} == x"" ] ; then
-			echo "MISSING FILE: " $i
-			FILE_MISSED=1
+		J=`file $i | awk -F: '{print $2}' | sed 's/\s*//'`
+		if [ x"$DLL_FILE_OUT" == x"" ] ; then	
+			DLL_FILE_OUT=$j
+		else
+			if [ x"$DLL_FILE_OUT" != x"$j" ] ; then
+				echo "DLL Mismatched file info. $i"
+				exit 1
+			fi
 		fi
 	done
 
-	if [ $FILE_MISSED -ne 0 ] ; then
+	if [ x"`cat windows-installer.nsi | grep INSERT_DLLS_HERE`" == x"" ]  ||  [ x"`cat windows-installer.nsi | grep INSERT_UNINST_DLLS_HERE`" == x"" ] ; then
+		echo "DLL insertion/removal tokens not found. Was looking for INSERT_DLLS_HERE and INSERT_UNINST_DLLS_HERE"
 		exit 1
 	fi
 
@@ -1224,15 +1313,20 @@ function make_package()
 
 	makensis `basename $NSI_FILE` ||  { echo "makensis failed" ; exit 1; }
 
+	echo "-------------------"
+	VERSION=`cat $NSI_FILE | grep "define PRODUCT_VERSION " | awk '{print $3}' | sed s/\"//g | sed s/\s*$//`
 	if [ $IS_RELEASE -ne 0 ] ; then
-		VERSION=`cat $NSI_FILE | grep "define PRODUCT_VERSION " | awk '{print $3}' | sed s/\"//g | sed s/\s*$//`
+		echo "Release mode enabled:"
 		TARGET_FILE=3Depict-$VERSION-$HOST_EXT.exe
-		mv Setup.exe  $TARGET_FILE
-		echo "-------------------"
-		echo "File written to : `pwd`/$TARGET_FILE"
-		echo "-------------------"
+	else
+		echo "Release mode disabled:"
+		TARGET_FILE=3Depict-${VERSION}-${HOST_EXT}-debug.exe
 	fi
 	
+	mv Setup.exe  $TARGET_FILE
+	echo "File written to : `pwd`/$TARGET_FILE"
+	echo "-------------------"
+	
 	popd > /dev/null
 }
 
@@ -1258,7 +1352,7 @@ case ${HOST_VAL}  in
 		HOST_EXT="win64"
 	;;
 	i686-w64-mingw32)
-		MINGW_PACKAGES="gcc-mingw32"
+		MINGW_PACKAGES="gcc-mingw-w64-i686 g++-mingw-w64-i686"
 		HOST_EXT="win32"
 	;;
 	*)
@@ -1303,10 +1397,11 @@ build_expat
 build_freetype
 build_libiconv
 build_gettext 
-build_mathgl 
 build_ftgl 
 build_glew
-build_wx	# I'm not sure I've done this 100% right. Check wx-config output 
+
+build_mathgl 
+build_wx	
 
 build_3Depict
 
diff --git a/packaging/mingw-debian-cross/patches/cmake-toolchain32 b/packaging/mingw-debian-cross/patches/cmake-toolchain32
new file mode 100644
index 0000000..4fd462e
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/cmake-toolchain32
@@ -0,0 +1,25 @@
+# this one is important
+SET(CMAKE_SYSTEM_NAME Windows)
+#this one not so much
+SET(CMAKE_SYSTEM_VERSION 1)
+
+# specify the cross compiler
+#SET(CMAKE_CXX_COMPILER CXX_REPLACE)
+#SET(CMAKE_C_COMPILER   C_REPLACE)
+SET(CMAKE_C_COMPILER   i686-w64-mingw32-gcc)
+SET(CMAKE_CXX_COMPILER   i686-w64-mingw32-g++)
+SET(CMAKE_RC_COMPILER /usr/bin/i686-w64-mingw32-windres)
+# where is the target environment 
+#SET(CMAKE_FIND_ROOT_PATH  PWD_REPLACE)
+SET(CMAKE_FIND_ROOT_PATH  /home/pcuser/mingw32/)
+
+SET(ZLIB_LIBRARY -lz)
+SET(PNG_LIBRARY -lpng)
+
+set(CMAKE_SHARED_LINKER_FLAGS  " -Wl,--no-undefined -L/home/pcuser/mingw32/lib/")
+
+# search for programs in the build host directories
+#SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/packaging/mingw-debian-cross/patches/cmake-toolchain64 b/packaging/mingw-debian-cross/patches/cmake-toolchain64
new file mode 100644
index 0000000..4d7d2f4
--- /dev/null
+++ b/packaging/mingw-debian-cross/patches/cmake-toolchain64
@@ -0,0 +1,24 @@
+# this one is important
+SET(CMAKE_SYSTEM_NAME Windows)
+#this one not so much
+SET(CMAKE_SYSTEM_VERSION 1)
+
+# specify the cross compiler
+#SET(CMAKE_CXX_COMPILER CXX_REPLACE)
+#SET(CMAKE_C_COMPILER   C_REPLACE)
+SET(CMAKE_C_COMPILER   x86_64-w64-mingw32-gcc)
+SET(CMAKE_CXX_COMPILER   x86_64-w64-mingw32-g++)
+SET(CMAKE_RC_COMPILER /usr/bin/x86_64-w64-mingw32-windres)
+# where is the target environment 
+#SET(CMAKE_FIND_ROOT_PATH  PWD_REPLACE)
+SET(CMAKE_FIND_ROOT_PATH  /home/pcuser/mingw64/)
+
+SET(ZLIB_LIBRARY -lz)
+SET(PNG_LIBRARY -lpng)
+
+
+# search for programs in the build host directories
+#SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+# for libraries and headers in the target directories
+SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype b/packaging/mingw-debian-cross/patches/ftgl-mingw32-prototype
old mode 100755
new mode 100644
diff --git a/packaging/mingw-debian-cross/patches/ftgl-override-configure b/packaging/mingw-debian-cross/patches/ftgl-override-configure
old mode 100755
new mode 100644
diff --git a/packaging/mingw-debian-cross/patches/gettext-disable-tools b/packaging/mingw-debian-cross/patches/gettext-disable-tools
old mode 100755
new mode 100644
diff --git a/packaging/mingw-debian-cross/patches/gettext-win32-prefix b/packaging/mingw-debian-cross/patches/gettext-win32-prefix
old mode 100755
new mode 100644
diff --git a/packaging/mingw-debian-cross/patches/glew-makefile b/packaging/mingw-debian-cross/patches/glew-makefile
old mode 100755
new mode 100644
index bb5c626..2d4985b
--- a/packaging/mingw-debian-cross/patches/glew-makefile
+++ b/packaging/mingw-debian-cross/patches/glew-makefile
@@ -1,6 +1,7 @@
---- a/Makefile	2013-07-07 15:37:19.000000000 +0200
-+++ b/Makefile	2013-07-07 15:44:55.000000000 +0200
-@@ -28,19 +28,12 @@
+diff -r 9bbbd8b43e5b Makefile
+--- a/Makefile	Sun Jun 29 17:24:13 2014 +0100
++++ b/Makefile	Sun Jun 29 17:25:52 2014 +0100
+@@ -28,19 +28,13 @@
  ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  ## THE POSSIBILITY OF SUCH DAMAGE.
  
@@ -10,26 +11,28 @@
  SHELL = /bin/sh
 -SYSTEM ?= $(shell config/config.guess | cut -d - -f 3 | sed -e 's/[0-9\.]//g;')
 -SYSTEM.SUPPORTED = $(shell test -f config/Makefile.$(SYSTEM) && echo 1)
-+SYSTEM = i686-w64-mingw32
++SYSTEM = x86_64-w64-mingw32
  
 -ifeq ($(SYSTEM.SUPPORTED), 1)
 -include config/Makefile.$(SYSTEM)
 -else
 -$(error "Platform '$(SYSTEM)' not supported")
 -endif
--
+ 
 -GLEW_DEST ?= /usr
-+GLEW_DEST ?= /home/pcuser/mingw32
- BINDIR ?= $(GLEW_DEST)/bin
- LIBDIR ?= $(GLEW_DEST)/lib
- INCDIR ?= $(GLEW_DEST)/include/GL
---- a/config/Makefile.mingw	2013-07-07 15:43:48.000000000 +0200
-+++ b/config/Makefile.mingw	2013-07-07 15:47:32.000000000 +0200
++GLEW_DEST ?= /home/pcuser/mingw64
+ BINDIR    ?= $(GLEW_DEST)/bin
+ LIBDIR    ?= $(GLEW_DEST)/lib
+ INCDIR    ?= $(GLEW_DEST)/include/GL
+diff -r 9bbbd8b43e5b config/Makefile.mingw
+--- a/config/Makefile.mingw	Sun Jun 29 17:24:13 2014 +0100
++++ b/config/Makefile.mingw	Sun Jun 29 17:25:52 2014 +0100
 @@ -1,7 +1,4 @@
  NAME = glew32
--CC = gcc
 -# use gcc for linking, with ld it does not work
--LD = gcc
+-CC := gcc
+-LD := gcc
+ LN :=
  CFLAGS.SO = -DGLEW_BUILD
- LDFLAGS.GL = -lglu32 -lopengl32 -lgdi32 -luser32 -lkernel32
+ LDFLAGS.GL = -lopengl32 -lgdi32 -luser32 -lkernel32
  LDFLAGS.EXTRA = -L/mingw/lib
diff --git a/packaging/mingw-debian-cross/patches/glew-makefile.base b/packaging/mingw-debian-cross/patches/glew-makefile.base
index 4262a54..ae6b8d2 100644
--- a/packaging/mingw-debian-cross/patches/glew-makefile.base
+++ b/packaging/mingw-debian-cross/patches/glew-makefile.base
@@ -1,6 +1,7 @@
---- a/Makefile	2013-07-07 15:37:19.000000000 +0200
-+++ b/Makefile	2013-07-07 15:44:55.000000000 +0200
-@@ -28,19 +28,12 @@
+diff -r 9bbbd8b43e5b Makefile
+--- a/Makefile	Sun Jun 29 17:24:13 2014 +0100
++++ b/Makefile	Sun Jun 29 17:25:52 2014 +0100
+@@ -28,19 +28,13 @@
  ## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  ## THE POSSIBILITY OF SUCH DAMAGE.
  
@@ -17,19 +18,21 @@
 -else
 -$(error "Platform '$(SYSTEM)' not supported")
 -endif
--
+ 
 -GLEW_DEST ?= /usr
 +GLEW_DEST ?= BASEDIR
- BINDIR ?= $(GLEW_DEST)/bin
- LIBDIR ?= $(GLEW_DEST)/lib
- INCDIR ?= $(GLEW_DEST)/include/GL
---- a/config/Makefile.mingw	2013-07-07 15:43:48.000000000 +0200
-+++ b/config/Makefile.mingw	2013-07-07 15:47:32.000000000 +0200
+ BINDIR    ?= $(GLEW_DEST)/bin
+ LIBDIR    ?= $(GLEW_DEST)/lib
+ INCDIR    ?= $(GLEW_DEST)/include/GL
+diff -r 9bbbd8b43e5b config/Makefile.mingw
+--- a/config/Makefile.mingw	Sun Jun 29 17:24:13 2014 +0100
++++ b/config/Makefile.mingw	Sun Jun 29 17:25:52 2014 +0100
 @@ -1,7 +1,4 @@
  NAME = glew32
--CC = gcc
 -# use gcc for linking, with ld it does not work
--LD = gcc
+-CC := gcc
+-LD := gcc
+ LN :=
  CFLAGS.SO = -DGLEW_BUILD
- LDFLAGS.GL = -lglu32 -lopengl32 -lgdi32 -luser32 -lkernel32
+ LDFLAGS.GL = -lopengl32 -lgdi32 -luser32 -lkernel32
  LDFLAGS.EXTRA = -L/mingw/lib
diff --git a/packaging/mingw-debian-cross/patches/gsl-config.patch b/packaging/mingw-debian-cross/patches/gsl-config.patch
old mode 100755
new mode 100644
diff --git a/packaging/mingw-debian-cross/patches/zlib-no-lc.patch b/packaging/mingw-debian-cross/patches/zlib-no-lc.patch
old mode 100755
new mode 100644
diff --git a/packaging/mingw-debian-cross/windows-installer.nsi b/packaging/mingw-debian-cross/windows-installer.nsi
index 0d9e106..77b2fb8 100755
--- a/packaging/mingw-debian-cross/windows-installer.nsi
+++ b/packaging/mingw-debian-cross/windows-installer.nsi
@@ -2,7 +2,7 @@
 
 ; HM NIS Edit Wizard helper defines
 !define PRODUCT_NAME "3Depict"
-!define PRODUCT_VERSION "0.0.16"
+!define PRODUCT_VERSION "0.0.17"
 !define PRODUCT_PUBLISHER "D. Haley, A. Ceguerra"
 !define PRODUCT_WEB_SITE "http://threedepict.sourceforge.net"
 !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\3Depict.exe"
@@ -12,6 +12,8 @@
 SetCompressor /FINAL /SOLID lzma
 SetCompressorDictSize 64
 
+!include "x64.nsh"
+
 ; MUI 1.67 compatible ------
 !include "MUI.nsh"
 
@@ -42,7 +44,7 @@ SetCompressorDictSize 64
 
 Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
 OutFile "Setup.exe"
-InstallDir "$PROGRAMFILES\3Depict"
+InstallDir "$PROGRAMFILES64\3Depict"
 InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
 ShowInstDetails show
 ShowUnInstDetails show
@@ -55,7 +57,6 @@ Section "3Depict program" SEC01
   ;INSERT_DLLS_HERE
 
   CreateDirectory "$SMPROGRAMS\3Depict"
-  CreateDirectory "$SMPROGRAMS\3Depict\textures"
   CreateShortCut "$SMPROGRAMS\3Depict\3Depict.lnk" "$INSTDIR\3Depict.exe"
   CreateShortCut "$DESKTOP\3Depict.lnk" "$INSTDIR\3Depict.exe"
   
@@ -124,43 +125,29 @@ FunctionEnd
 
 Section Uninstall
   Delete "$INSTDIR\${PRODUCT_NAME}.url"
-  Delete "$INSTDIR\textures\uninst.exe"
+  Delete "$INSTDIR\uninst.exe"  
   
-  Delete "$INSTDIR\textures\animProgress0.png"
-  Delete "$INSTDIR\textures\animProgress1.png"
-  Delete "$INSTDIR\textures\animProgress2.png"
-  Delete "$INSTDIR\textures\scroll_wheel_mouse.png"
-  Delete "$INSTDIR\textures\rotateArrow.png"
-  Delete "$INSTDIR\textures\Right_clicked_mouse.png"
-  Delete "$INSTDIR\textures\Right-arrow.png"
-  Delete "$INSTDIR\textures\middle_clicked_mouse.png"
-  Delete "$INSTDIR\textures\Left_clicked_mouse.png"
-  Delete "$INSTDIR\textures\Left-Right-arrow.png"
-  Delete "$INSTDIR\textures\keyboard-tab.png"
-  Delete "$INSTDIR\textures\keyboard-shift.png"
-  Delete "$INSTDIR\textures\keyboard-ctrl.png"
-  Delete "$INSTDIR\textures\keyboard-command.png"
-  Delete "$INSTDIR\textures\keyboard-alt.png"
-  Delete "$INSTDIR\textures\enlarge.png"
+  RMDir /r "$INSTDIR\textures"
+  RMDir "$INSTDIR\textures"
+  RMDir /r "$INSTDIR\locales"
+  RMDir "$INSTDIR\locales"
   
-  Delete "3Depict.xpm"
-  Delete "atomic-mass-table.dtd"
-  Delete "naturalAbundance.xml"
-  Delete "startup-tips.txt"
+  Delete "$INSTDIR\3Depict.xpm"
+  Delete "$INSTDIR\atomic-mass-table.dtd"
+  Delete "$INSTDIR\naturalAbundance.xml"
+  Delete "$INSTDIR\startup-tips.txt"
  
   Delete "$INSTDIR\3Depict.exe"
 
   Delete "$INSTDIR\manual.pdf"
-  RMDir /r "$INSTDIR\locales\*.*"
-  RMDir "$INSTDIR\locales"
 
   ;This is a token that should be replaced with the DLLS to uninstall
   ;INSERT_UNINST_DLLS_HERE
 
-  Delete "$INSTDIR\uninst.exe"  
  
   Delete "$SMPROGRAMS\3Depict\Uninstall.lnk"
   Delete "$SMPROGRAMS\3Depict\Website.lnk"
+  Delete "$SMPROGRAMS\3Depict\manual.pdf"
   Delete "$DESKTOP\3Depict.lnk"
   Delete "$SMPROGRAMS\3Depict\3Depict.lnk"
   RMDir "$SMPROGRAMS\3Depict"
diff --git a/src/3Depict.cpp b/src/3Depict.cpp
index 1c66435..a1df700 100644
--- a/src/3Depict.cpp
+++ b/src/3Depict.cpp
@@ -42,17 +42,18 @@ private:
 	MainWindowFrame* MainFrame ;
 	wxArrayString commandLineFiles;
 	wxLocale* usrLocale;
-	//long language;
-
-	//void initLanguageSupport();
+	long language;
 
+	void initLanguageSupport();
+	//Don't load the main window, as debugging was in progress
+	bool dontLoad;
 
 public:
 
     threeDepictApp() ;
-    ~threeDepictApp() { if(usrLocale) delete usrLocale;}
     bool OnInit();
     virtual void OnInitCmdLine(wxCmdLineParser& parser);
+    virtual int OnExit();
     virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
 		 
     int FilterEvent(wxEvent &event);
@@ -70,27 +71,14 @@ public:
 //Command line parameter table
 static const wxCmdLineEntryDesc g_cmdLineDesc [] =
 {
-#if wxCHECK_VERSION(2,9,0) 
 	{ wxCMD_LINE_SWITCH, ("h"), ("help"), ("displays this message"),
 		wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
 	{ wxCMD_LINE_PARAM,  NULL, NULL, ("inputfile"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE},
-#else
-	{ wxCMD_LINE_SWITCH, wxT("h"), wxT("help"), wxNTRANS("displays this message"),
-		wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
-	{ wxCMD_LINE_PARAM,  NULL, NULL, wxNTRANS("inputfile"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE},
-#endif
 	//Unit testing system
 #ifdef DEBUG
-#if wxCHECK_VERSION(2,9,0) 
 	{ wxCMD_LINE_SWITCH, ("t"), ("test"), ("Run debug unit tests, returns nonzero on test failure, zero on success.\n\t\t"
 		       "XML files may be passed to run , instead of default tests"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_SWITCH},
-#else
-	{ wxCMD_LINE_SWITCH, wxT("t"), wxT("test"), 
-	wxNTRANS("Run debug unit tests, returns nonzero on test failure, zero on success.\n\t\t" 
-			"XML files may be passed to run, instead of default tests"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_SWITCH},
-#endif
 #endif
-
   { wxCMD_LINE_NONE,NULL,NULL,NULL,wxCMD_LINE_VAL_NONE,0 }
 
 };
@@ -118,22 +106,31 @@ IMPLEMENT_APP(threeDepictApp)
 threeDepictApp::threeDepictApp()
 {
        	MainFrame=0;usrLocale=0;
+	dontLoad=false;
 #ifndef DEBUG
-#if wxCHECK_VERSION(2,9,0)
 	//Wx 2.9 and up now has assertions auto-enabled. 
 	//Disable for release builds
 	wxSetAssertHandler(NULL);
 #endif
-#endif
 }
 
+int threeDepictApp::OnExit()
+{
+	if(usrLocale) 	
+		delete usrLocale;
+	
+	//libxml2 by default seems to leak memory, unless you call this function
+	xmlCleanupParser();
+
+	return wxApp::OnExit();
+}
 
-/*void threeDepictApp::initLanguageSupport()
+void threeDepictApp::initLanguageSupport()
 {
 	language =  wxLANGUAGE_DEFAULT;
 
 	// load language if possible, fall back to English otherwise
-	if(false)// (wxLocale::IsAvailable(language))
+	if(wxLocale::IsAvailable(language))
 	{
 		//Wx 2.9 and above are now unicode, so locale encoding
 		//conversion is deprecated.
@@ -152,7 +149,7 @@ threeDepictApp::threeDepictApp()
 		usrLocale->AddCatalogLookupPathPrefix(paths->GetResourcesDir());
 		usrLocale->AddCatalogLookupPathPrefix ( wxT ( "locales" ) );
 #endif
-		usrLocale->AddCatalog(wxCStr(PROGRAM_NAME));
+		usrLocale->AddCatalog((PROGRAM_NAME));
 
 
 
@@ -210,7 +207,7 @@ threeDepictApp::threeDepictApp()
 		language = wxLANGUAGE_ENGLISH;
 	}
 }
-*/
+
 //Catching key events globally.
 int threeDepictApp::FilterEvent(wxEvent& event)
 {
@@ -283,9 +280,9 @@ void threeDepictApp::OnInitCmdLine(wxCmdLineParser& parser)
 {
 	wxString name,version,preamble;
 
-	name=wxCStr(PROGRAM_NAME);
+	name=(PROGRAM_NAME);
 	name=name+ wxT(" ");
-	version=wxCStr(PROGRAM_VERSION);
+	version=(PROGRAM_VERSION);
 	version+=wxT("\n");
 
 	preamble=wxT("Copyright (C) 2013  3Depict team\n");
@@ -318,7 +315,7 @@ bool threeDepictApp::OnCmdLineParsed(wxCmdLineParser& parser)
 				if( !f.FileExists() )
 				{
 					cerr << "Unable to locate file:" << strFile << endl;
-					continue;
+					return false;
 				}
 
 				cerr << "Loading :" << strFile << endl ;
@@ -328,7 +325,7 @@ bool threeDepictApp::OnCmdLineParsed(wxCmdLineParser& parser)
 				if(!visControl.loadState(strFile.c_str(),cerr,false,true))
 				{
 					cerr << "Error loading state file:" << endl;
-					exit(1);
+					return false;
 				}
 
 				//Run a refresh over the filter tree as a test
@@ -343,7 +340,7 @@ bool threeDepictApp::OnCmdLineParsed(wxCmdLineParser& parser)
 				if(!testFilterTree(f))
 				{
 					cerr << "Failed loading :" << strFile << " , aborting" << endl;
-					exit(1);
+					return false;
 				}
 				}
 
@@ -352,8 +349,8 @@ bool threeDepictApp::OnCmdLineParsed(wxCmdLineParser& parser)
 			}
 			
 			 
-			cerr << "Test XML File(s) Loaded OK" << endl;	
-			exit(0);
+			cerr << "Test XML File(s) Loaded OK" << endl;
+			dontLoad=true;	
 		}
 		else
 		{
@@ -361,29 +358,30 @@ bool threeDepictApp::OnCmdLineParsed(wxCmdLineParser& parser)
 			if(!runUnitTests()) 
 			{
 				cerr << "Unit tests failed" <<endl;
-				exit(1);
+				return false;
 			}
 			else
 			{
 				cerr << "Unit tests succeeded!" <<endl;
-				exit(0);
+				dontLoad=true;
 			}
 		}
 	}
+	else
 #endif
-
-	for(unsigned int ui=0;ui<parser.GetParamCount();ui++)
 	{
-		wxFileName f;
-		f.Assign(parser.GetParam(ui));
+		for(unsigned int ui=0;ui<parser.GetParamCount();ui++)
+		{
+			wxFileName f;
+			f.Assign(parser.GetParam(ui));
 
-		if( f.FileExists() )
-			commandLineFiles.Add(f.GetFullPath());
-		else
-			std::cerr << TRANS("File : ") << stlStr(f.GetFullPath()) << TRANS(" does not exist. Skipping") << std::endl;
+			if( f.FileExists() )
+				commandLineFiles.Add(f.GetFullPath());
+			else
+				std::cerr << TRANS("File : ") << stlStr(f.GetFullPath()) << TRANS(" does not exist. Skipping") << std::endl;
 
+		}
 	}
-
 	return true;
 }
 
@@ -411,13 +409,25 @@ void threeDepictApp::MacReopenFile(const wxString &filename)
 bool threeDepictApp::OnInit()
 {
 
-    //initLanguageSupport();
+    initLanguageSupport();
 	
 
     //Set the gettext language
     //Register signal handler for backtraces
     if (!wxApp::OnInit())
-    	return false; 
+    	return false;
+
+    //if we ran the debug code, don't load the main window
+    if(dontLoad)
+    {
+	OnExit();
+	//FIXME: This causes wx to shutdown incorrectly, but gives us the return code
+	// - I can't seem to simultaneously set the return code and 
+	// abort the init.
+	exit(0);
+	
+	return false;
+    }
 
     //Need to seed random number generator for entire program
     srand (time(NULL));
@@ -429,10 +439,6 @@ bool threeDepictApp::OnInit()
     wxInitAllImageHandlers();
     MainFrame = new MainWindowFrame(NULL, ID_MAIN_WINDOW, wxEmptyString,wxDefaultPosition,wxDefaultSize);
 
-    if(!MainFrame->initOK())
-	    return false;
-  
- 
     SetTopWindow(MainFrame);
 
 #if defined(DEBUG) && defined(__linux__)
@@ -457,11 +463,17 @@ bool threeDepictApp::OnInit()
 
 
     MainFrame->Show();
-    
+   
+    MainFrame->checkShowTips();
+    MainFrame->checkReloadAutosave();
+
+
     if(commandLineFiles.GetCount())
     	MainFrame->SetCommandLineFiles(commandLineFiles);
 
     MainFrame->fixSplitterWindow();
+
+    MainFrame->finaliseStartup();
     return true;
 }
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 9ca6bb9..68011aa 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,7 @@
 MSYS_PATH=/c/msys/1.0/local/include/
 
 %.rc.o: 
-	$(WX_RESCOMP) $^ -o $@
+	$(WX_RESCOMP) $^ -o $@ 3Depict.rc
 
 3Depict_LDFLAGS=$(LDFLAGS) $(FT_LDFLAGS) $(GSL_LIBS) $(MGL_LIBS)
 
@@ -20,9 +20,11 @@ MSYS_PATH=/c/msys/1.0/local/include/
 bin_PROGRAMS= 3Depict
 
 #------- Common header files for all sub-modules
-COMMON_SOURCE_FILES = common/pngread.c common/stringFuncs.cpp common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp common/assertion.cpp
+COMMON_SOURCE_FILES = common/pngread.c common/stringFuncs.cpp common/constants.cpp common/xmlHelper.cpp\
+			 common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp common/assertion.cpp
 COMMON_HEADER_FILES = common/pngread.h common/stringFuncs.h  common/constants.h  common/xmlHelper.h common/colourmap.h \
-		      	common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h
+		      	common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h \
+			common/array2D.h
 
 #-----------
 
@@ -36,7 +38,7 @@ FILTER_FILES = backend/filters/allFilter.cpp backend/filters/filterCommon.cpp \
 		backend/filters/compositionProfile.cpp backend/filters/spatialAnalysis.cpp \
 		backend/filters/clusterAnalysis.cpp backend/filters/ionInfo.cpp \
 		backend/filters/annotation.cpp backend/filters/geometryHelpers.cpp \
-		backend/filters/algorithms/binomial.cpp 
+		backend/filters/algorithms/binomial.cpp  
 
 FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h \
 		backend/filters/dataLoad.h backend/filters/ionDownsample.h \
@@ -46,7 +48,7 @@ FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h
 		backend/filters/compositionProfile.h backend/filters/spatialAnalysis.h \
 		backend/filters/clusterAnalysis.h backend/filters/ionInfo.h \
 		backend/filters/annotation.h backend/filters/geometryHelpers.h \
-		backend/filters/algorithms/binomial.h
+		backend/filters/algorithms/binomial.h 
 
 BACKEND_SOURCE_FILES = backend/animator.cpp backend/filtertreeAnalyse.cpp backend/filtertree.cpp \
 		     	backend/APT/ionhit.cpp backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp backend/APT/abundanceParser.cpp \
@@ -94,8 +96,8 @@ DIALOG_HEADER_FILES = gui/dialogs/ExportPos.h gui/dialogs/ExportRngDialog.h gui/
 GUI_SOURCE_FILES=gui/mainFrame.cpp gui/mathglPane.cpp gui/cropPanel.cpp gui/glPane.cpp  $(DIALOG_SOURCE_FILES)
 GUI_HEADER_FILES=gui/mainFrame.h gui/mathglPane.h gui/cropPanel.h gui/art.h gui/glPane.h $(DIALOG_HEADER_FILES)
 
-BASE_SOURCE_FILES=   3Depict.cpp testing/testing.cpp wx/wxcommon.cpp  wx/wxcomponents.cpp winconsole.cpp 
-BASE_HEADER_FILES=   testing/testing.h  wx/wxcommon.h  wx/wxcomponents.h   winconsole.h
+BASE_SOURCE_FILES=   3Depict.cpp testing/testing.cpp wx/wxcommon.cpp  wx/wxcomponents.cpp winconsole.cpp  wx/propertyGridUpdater.cpp
+BASE_HEADER_FILES=   testing/testing.h  wx/wxcommon.h  wx/wxcomponents.h   winconsole.h wx/propertyGridUpdater.h
 
 TEST_SOURCE_FILES = testing/mglTesting.cpp
 TEST_HEADER_FILES = testing/mglTesting.h
diff --git a/src/Makefile.in b/src/Makefile.in
index 0fc9cfb..54a2a60 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -100,7 +100,8 @@ am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
 am__3Depict_SOURCES_DIST = 3Depict.cpp testing/testing.cpp \
 	wx/wxcommon.cpp wx/wxcomponents.cpp winconsole.cpp \
-	testing/testing.h wx/wxcommon.h wx/wxcomponents.h winconsole.h \
+	wx/propertyGridUpdater.cpp testing/testing.h wx/wxcommon.h \
+	wx/wxcomponents.h winconsole.h wx/propertyGridUpdater.h \
 	gui/mainFrame.cpp gui/mathglPane.cpp gui/cropPanel.cpp \
 	gui/glPane.cpp gui/dialogs/ExportPos.cpp \
 	gui/dialogs/ExportRngDialog.cpp gui/dialogs/prefDialog.cpp \
@@ -166,19 +167,20 @@ am__3Depict_SOURCES_DIST = 3Depict.cpp testing/testing.cpp \
 	gl/textures.cpp gl/select.cpp gl/cameras.cpp gl/isoSurface.cpp \
 	gl/tr.cpp gl/scene.h gl/drawables.h gl/effect.h gl/textures.h \
 	gl/select.h gl/cameras.h gl/isoSurface.h gl/tr.h gl/glDebug.h \
-	common/pngread.c common/stringFuncs.cpp common/xmlHelper.cpp \
-	common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp \
-	common/basics.cpp common/assertion.cpp common/pngread.h \
-	common/stringFuncs.h common/constants.h common/xmlHelper.h \
-	common/colourmap.h common/mathfuncs.h common/basics.h \
-	common/translation.h common/endianTest.h common/assertion.h \
-	common/voxels.h testing/mglTesting.cpp testing/mglTesting.h \
-	3Depict.rc
+	common/pngread.c common/stringFuncs.cpp common/constants.cpp \
+	common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp \
+	common/mathfuncs.cpp common/basics.cpp common/assertion.cpp \
+	common/pngread.h common/stringFuncs.h common/constants.h \
+	common/xmlHelper.h common/colourmap.h common/mathfuncs.h \
+	common/basics.h common/translation.h common/endianTest.h \
+	common/assertion.h common/voxels.h common/array2D.h \
+	testing/mglTesting.cpp testing/mglTesting.h 3Depict.rc
 am__dirstamp = $(am__leading_dot)dirstamp
 am__objects_1 = 3Depict-3Depict.$(OBJEXT) \
 	testing/3Depict-testing.$(OBJEXT) \
 	wx/3Depict-wxcommon.$(OBJEXT) \
-	wx/3Depict-wxcomponents.$(OBJEXT) 3Depict-winconsole.$(OBJEXT)
+	wx/3Depict-wxcomponents.$(OBJEXT) 3Depict-winconsole.$(OBJEXT) \
+	wx/3Depict-propertyGridUpdater.$(OBJEXT)
 am__objects_2 =
 am__objects_3 = gui/dialogs/3Depict-ExportPos.$(OBJEXT) \
 	gui/dialogs/3Depict-ExportRngDialog.$(OBJEXT) \
@@ -237,6 +239,7 @@ am__objects_8 = gl/3Depict-scene.$(OBJEXT) \
 	gl/3Depict-tr.$(OBJEXT)
 am__objects_9 = common/3Depict-pngread.$(OBJEXT) \
 	common/3Depict-stringFuncs.$(OBJEXT) \
+	common/3Depict-constants.$(OBJEXT) \
 	common/3Depict-xmlHelper.$(OBJEXT) \
 	common/3Depict-colourmap.$(OBJEXT) \
 	common/3Depict-voxels.$(OBJEXT) \
@@ -481,9 +484,12 @@ MSYS_PATH = /c/msys/1.0/local/include/
 	$(GLU_LIBS) $(QHULL_LIBS) $(PNG_LIBS) $(am__append_2)
 
 #------- Common header files for all sub-modules
-COMMON_SOURCE_FILES = common/pngread.c common/stringFuncs.cpp common/xmlHelper.cpp common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp common/assertion.cpp
+COMMON_SOURCE_FILES = common/pngread.c common/stringFuncs.cpp common/constants.cpp common/xmlHelper.cpp\
+			 common/colourmap.cpp common/voxels.cpp common/mathfuncs.cpp common/basics.cpp common/assertion.cpp
+
 COMMON_HEADER_FILES = common/pngread.h common/stringFuncs.h  common/constants.h  common/xmlHelper.h common/colourmap.h \
-		      	common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h
+		      	common/mathfuncs.h common/basics.h common/translation.h common/endianTest.h common/assertion.h common/voxels.h \
+			common/array2D.h
 
 
 #-----------
@@ -498,7 +504,7 @@ FILTER_FILES = backend/filters/allFilter.cpp backend/filters/filterCommon.cpp \
 		backend/filters/compositionProfile.cpp backend/filters/spatialAnalysis.cpp \
 		backend/filters/clusterAnalysis.cpp backend/filters/ionInfo.cpp \
 		backend/filters/annotation.cpp backend/filters/geometryHelpers.cpp \
-		backend/filters/algorithms/binomial.cpp 
+		backend/filters/algorithms/binomial.cpp  
 
 FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h \
 		backend/filters/dataLoad.h backend/filters/ionDownsample.h \
@@ -508,7 +514,7 @@ FILTER_HEADER_FILES = backend/filters/allFilter.h backend/filters/filterCommon.h
 		backend/filters/compositionProfile.h backend/filters/spatialAnalysis.h \
 		backend/filters/clusterAnalysis.h backend/filters/ionInfo.h \
 		backend/filters/annotation.h backend/filters/geometryHelpers.h \
-		backend/filters/algorithms/binomial.h
+		backend/filters/algorithms/binomial.h 
 
 BACKEND_SOURCE_FILES = backend/animator.cpp backend/filtertreeAnalyse.cpp backend/filtertree.cpp \
 		     	backend/APT/ionhit.cpp backend/APT/APTFileIO.cpp backend/APT/APTRanges.cpp backend/APT/abundanceParser.cpp \
@@ -553,8 +559,8 @@ DIALOG_HEADER_FILES = gui/dialogs/ExportPos.h gui/dialogs/ExportRngDialog.h gui/
 
 GUI_SOURCE_FILES = gui/mainFrame.cpp gui/mathglPane.cpp gui/cropPanel.cpp gui/glPane.cpp  $(DIALOG_SOURCE_FILES)
 GUI_HEADER_FILES = gui/mainFrame.h gui/mathglPane.h gui/cropPanel.h gui/art.h gui/glPane.h $(DIALOG_HEADER_FILES)
-BASE_SOURCE_FILES = 3Depict.cpp testing/testing.cpp wx/wxcommon.cpp  wx/wxcomponents.cpp winconsole.cpp 
-BASE_HEADER_FILES = testing/testing.h  wx/wxcommon.h  wx/wxcomponents.h   winconsole.h
+BASE_SOURCE_FILES = 3Depict.cpp testing/testing.cpp wx/wxcommon.cpp  wx/wxcomponents.cpp winconsole.cpp  wx/propertyGridUpdater.cpp
+BASE_HEADER_FILES = testing/testing.h  wx/wxcommon.h  wx/wxcomponents.h   winconsole.h wx/propertyGridUpdater.h
 TEST_SOURCE_FILES = testing/mglTesting.cpp
 TEST_HEADER_FILES = testing/mglTesting.h
 #-----------
@@ -661,6 +667,8 @@ wx/3Depict-wxcommon.$(OBJEXT): wx/$(am__dirstamp) \
 	wx/$(DEPDIR)/$(am__dirstamp)
 wx/3Depict-wxcomponents.$(OBJEXT): wx/$(am__dirstamp) \
 	wx/$(DEPDIR)/$(am__dirstamp)
+wx/3Depict-propertyGridUpdater.$(OBJEXT): wx/$(am__dirstamp) \
+	wx/$(DEPDIR)/$(am__dirstamp)
 gui/$(am__dirstamp):
 	@$(MKDIR_P) gui
 	@: > gui/$(am__dirstamp)
@@ -868,6 +876,8 @@ common/3Depict-pngread.$(OBJEXT): common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
 common/3Depict-stringFuncs.$(OBJEXT): common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
+common/3Depict-constants.$(OBJEXT): common/$(am__dirstamp) \
+	common/$(DEPDIR)/$(am__dirstamp)
 common/3Depict-xmlHelper.$(OBJEXT): common/$(am__dirstamp) \
 	common/$(DEPDIR)/$(am__dirstamp)
 common/3Depict-colourmap.$(OBJEXT): common/$(am__dirstamp) \
@@ -943,6 +953,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/3Depict-assertion.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/3Depict-basics.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/3Depict-colourmap.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/3Depict-constants.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/3Depict-mathfuncs.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/3Depict-pngread.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at common/$(DEPDIR)/3Depict-stringFuncs.Po at am__quote@
@@ -974,6 +985,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote at gui/dialogs/animateSubDialogs/$(DEPDIR)/3Depict-stringKeyFrameDialog.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at testing/$(DEPDIR)/3Depict-mglTesting.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at testing/$(DEPDIR)/3Depict-testing.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at wx/$(DEPDIR)/3Depict-propertyGridUpdater.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at wx/$(DEPDIR)/3Depict-wxcommon.Po at am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote at wx/$(DEPDIR)/3Depict-wxcomponents.Po at am__quote@
 
@@ -1093,6 +1105,20 @@ wx/3Depict-wxcomponents.obj: wx/wxcomponents.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o 3Depict-winconsole.obj `if test -f 'winconsole.cpp'; then $(CYGPATH_W) 'winconsole.cpp'; else $(CYGPATH_W) '$(srcdir)/winconsole.cpp'; fi`
 
+wx/3Depict-propertyGridUpdater.o: wx/propertyGridUpdater.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT wx/3Depict-propertyGridUpdater.o -MD -MP -MF wx/$(DEPDIR)/3Depict-propertyGridUpdater.Tpo -c -o wx/3Depict-propertyGridUpdater.o `test -f 'wx/propertyGridUpdater.cpp' || echo '$(srcdir)/'`wx/propertyGridUpdater.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) wx/$(DEPDIR)/3Depict-propertyGridUpdater.Tpo wx/$(DEPDIR)/3Depict-propertyGridUpdater.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='wx/propertyGridUpdater.cpp' object='wx/3Depict-propertyGridUpdater.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o wx/3Depict-propertyGridUpdater.o `test -f 'wx/propertyGridUpdater.cpp' || echo '$(srcdir)/'`wx/propertyGridUpdater.cpp
+
+wx/3Depict-propertyGridUpdater.obj: wx/propertyGridUpdater.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT wx/3Depict-propertyGridUpdater.obj -MD -MP -MF wx/$(DEPDIR)/3Depict-propertyGridUpdater.Tpo -c -o wx/3Depict-propertyGridUpdater.obj `if test -f 'wx/propertyGridUpdater.cpp'; then $(CYGPATH_W) 'wx/propertyGridUpdater.cpp'; else $(CYGPATH_W) '$(srcdir)/wx/propertyGridUpdater.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) wx/$(DEPDIR)/3Depict-propertyGridUpdater.Tpo wx/$(DEPDIR)/3Depict-propertyGridUpdater.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='wx/propertyGridUpdater.cpp' object='wx/3Depict-propertyGridUpdater.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o wx/3Depict-propertyGridUpdater.obj `if test -f 'wx/propertyGridUpdater.cpp'; then $(CYGPATH_W) 'wx/propertyGridUpdater.cpp'; else $(CYGPATH_W) '$(srcdir)/wx/propertyGridUpdater.cpp'; fi`
+
 gui/3Depict-mainFrame.o: gui/mainFrame.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT gui/3Depict-mainFrame.o -MD -MP -MF gui/$(DEPDIR)/3Depict-mainFrame.Tpo -c -o gui/3Depict-mainFrame.o `test -f 'gui/mainFrame.cpp' || echo '$(srcdir)/'`gui/mainFrame.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) gui/$(DEPDIR)/3Depict-mainFrame.Tpo gui/$(DEPDIR)/3Depict-mainFrame.Po
@@ -1919,6 +1945,20 @@ common/3Depict-stringFuncs.obj: common/stringFuncs.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o common/3Depict-stringFuncs.obj `if test -f 'common/stringFuncs.cpp'; then $(CYGPATH_W) 'common/stringFuncs.cpp'; else $(CYGPATH_W) '$(srcdir)/common/stringFuncs.cpp'; fi`
 
+common/3Depict-constants.o: common/constants.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT common/3Depict-constants.o -MD -MP -MF common/$(DEPDIR)/3Depict-constants.Tpo -c -o common/3Depict-constants.o `test -f 'common/constants.cpp' || echo '$(srcdir)/'`common/constants.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/3Depict-constants.Tpo common/$(DEPDIR)/3Depict-constants.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='common/constants.cpp' object='common/3Depict-constants.o' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o common/3Depict-constants.o `test -f 'common/constants.cpp' || echo '$(srcdir)/'`common/constants.cpp
+
+common/3Depict-constants.obj: common/constants.cpp
+ at am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT common/3Depict-constants.obj -MD -MP -MF common/$(DEPDIR)/3Depict-constants.Tpo -c -o common/3Depict-constants.obj `if test -f 'common/constants.cpp'; then $(CYGPATH_W) 'common/constants.cpp'; else $(CYGPATH_W) '$(srcdir)/common/constants.cpp'; fi`
+ at am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/3Depict-constants.Tpo common/$(DEPDIR)/3Depict-constants.Po
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='common/constants.cpp' object='common/3Depict-constants.obj' libtool=no @AMDEPBACKSLASH@
+ at AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+ at am__fastdepCXX_FALSE@	$(AM_V_CXX at am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -c -o common/3Depict-constants.obj `if test -f 'common/constants.cpp'; then $(CYGPATH_W) 'common/constants.cpp'; else $(CYGPATH_W) '$(srcdir)/common/constants.cpp'; fi`
+
 common/3Depict-xmlHelper.o: common/xmlHelper.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(3Depict_CXXFLAGS) $(CXXFLAGS) -MT common/3Depict-xmlHelper.o -MD -MP -MF common/$(DEPDIR)/3Depict-xmlHelper.Tpo -c -o common/3Depict-xmlHelper.o `test -f 'common/xmlHelper.cpp' || echo '$(srcdir)/'`common/xmlHelper.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) common/$(DEPDIR)/3Depict-xmlHelper.Tpo common/$(DEPDIR)/3Depict-xmlHelper.Po
@@ -2245,7 +2285,7 @@ uninstall-am: uninstall-binPROGRAMS
 
 
 %.rc.o: 
-	$(WX_RESCOMP) $^ -o $@
+	$(WX_RESCOMP) $^ -o $@ 3Depict.rc
 
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/src/backend/APT/APTFileIO.cpp b/src/backend/APT/APTFileIO.cpp
index d37984e..c3b7cad 100644
--- a/src/backend/APT/APTFileIO.cpp
+++ b/src/backend/APT/APTFileIO.cpp
@@ -22,6 +22,8 @@
 #include "../../common/stringFuncs.h"
 #include "../../common/translation.h"
 
+
+
 #include <cstring>
 #include <new>
 
@@ -35,7 +37,18 @@ using std::make_pair;
 
 const size_t PROGRESS_REDUCE=5000;
 
+
 //---------
+const char *TEXT_LOAD_ERR_STRINGS[] = { "",
+					NTRANS("Error opening file"),
+					NTRANS("Only found header, no data"),
+					NTRANS("Unable to reopen file after first scan"),
+					NTRANS("Error whilst reading file contents"),
+					NTRANS("Unexpected file format"),
+					NTRANS("Unexpected file format"),
+					NTRANS("Insufficient memory to continue"),
+					};
+
 const char *POS_ERR_STRINGS[] = { "",
        				NTRANS("Memory allocation failure on POS load"),
 				NTRANS("Error opening pos file"),
@@ -43,6 +56,7 @@ const char *POS_ERR_STRINGS[] = { "",
 				NTRANS("Pos file size appears to have non-integer number of entries"),
 				NTRANS("Error reading from pos file (after open)"),
 				NTRANS("Error - Found NaN in pos file"),
+				NTRANS("Error - Found Inf in pos file"),
 				NTRANS("Pos load aborted by interrupt.")
 };
 //---------
@@ -56,7 +70,6 @@ enum
 	TEXT_ERR_REOPEN,
 	TEXT_ERR_READ_CONTENTS,
 	TEXT_ERR_FORMAT,
-	TEXT_ERR_NUM_FIELDS,
 	TEXT_ERR_ALLOC_FAIL,
 	TEXT_ERR_ENUM_END //not an error, just end of enum
 };
@@ -95,10 +108,11 @@ const char *LAWATAP_ATO_ERR_STRINGS[] = { "",
 				};
 //---------
 
-unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumcols, unsigned int index[], vector<IonHit> &posIons,const char *posFile, size_t limitCount,
+unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumcols, const unsigned int index[], vector<IonHit> &posIons,const char *posFile, size_t limitCount,
 	       	unsigned int &progress, bool (*callback)(bool),bool strongSampling)
 {
 
+
 	//Function is only defined for 4 columns here.
 	ASSERT(outputnumcols == 4);
 	//buffersize must be a power of two and at least outputnumcols*sizeof(float)
@@ -187,9 +201,10 @@ unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumc
 	}
 
 
-	//sort again	
-	GreaterWithCallback<size_t> g(callback,PROGRESS_REDUCE);
-	std::sort(ionsToLoad.begin(),ionsToLoad.end(),g);
+	//sort again
+	//NOTE: I tried to use a functor here to get progress
+	// It was not stable with parallel sort	
+	std::sort(ionsToLoad.begin(),ionsToLoad.end());
 
 	unsigned int curProg = PROGRESS_REDUCE;	
 
@@ -228,7 +243,14 @@ unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumc
 			delete[] buffer2;
 			return POS_NAN_LOAD_ERROR;	
 		}
-			
+	
+		if(posIons[ui].hasInf())
+		{
+			delete[] buffer;
+			delete[] buffer2;
+			return POS_INF_LOAD_ERROR;	
+		}
+		
 		pointCount++;
 		if(!curProg--)
 		{
@@ -253,7 +275,7 @@ unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumc
 }
 
 unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int outputnumcols, 
-		unsigned int index[], vector<IonHit> &posIons,const char *posFile, 
+		const unsigned int index[], vector<IonHit> &posIons,const char *posFile, 
 			unsigned int &progress, bool (*callback)(bool))
 {
 	ASSERT(outputnumcols==4); //Due to ionHit.setHit
@@ -369,6 +391,14 @@ unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int output
 					delete[] buffer2;
 					return POS_NAN_LOAD_ERROR;	
 				}
+
+				if(hit.hasInf())
+				{
+					delete[] buffer;
+					delete[] buffer2;
+					return POS_INF_LOAD_ERROR;	
+				}
+
 				posIons[ionP] = hit;
 				ionP++;
 				
@@ -408,7 +438,6 @@ unsigned int limitLoadTextFile(unsigned int maxCols,
 			vector<vector<float> > &data,const char *textFile, const char *delim, const size_t limitCount,
 				unsigned int &progress, bool (*callback)(bool),bool strongRandom)
 {
-
 	ASSERT(maxCols);
 	ASSERT(textFile);
 
@@ -575,11 +604,11 @@ unsigned int limitLoadTextFile(unsigned int maxCols,
 		return TEXT_ERR_ALLOC_FAIL;
 	}
 
+	(*callback)(true);
 
 	//Sort the data such that we are going to
 	//always jump forwards in the file; better disk access and whatnot.
-	GreaterWithCallback<size_t> g(callback,PROGRESS_REDUCE);
-	std::sort(dataToLoad.begin(),dataToLoad.end(),g);
+	std::sort(dataToLoad.begin(),dataToLoad.end());
 
 	//OK, so we have  a list of newlines
 	//that we can use as entry points for random seek.
diff --git a/src/backend/APT/APTFileIO.h b/src/backend/APT/APTFileIO.h
index b2b00c2..e743b9c 100644
--- a/src/backend/APT/APTFileIO.h
+++ b/src/backend/APT/APTFileIO.h
@@ -39,6 +39,8 @@ extern const char *ION_TEXT_ERR_STRINGS[];
 
 extern const char *LAWATAP_ATO_ERR_STRINGS[];
 
+extern const char *TEXT_LOAD_ERR_STRINGS[];
+
 //!Errors that can be encountered when openning pos files
 enum posErrors
 {
@@ -48,6 +50,7 @@ enum posErrors
 	POS_SIZE_MODULUS_ERR,	
 	POS_READ_FAIL,
 	POS_NAN_LOAD_ERROR,
+	POS_INF_LOAD_ERROR,
 	POS_ABORT_FAIL,
 	POS_ERR_FINAL // Not actually an error, but tells us where the end of the num is.
 };
@@ -62,11 +65,11 @@ enum posErrors
  * */
 //!Load a pos file into a T of IonHits
 unsigned int GenericLoadFloatFile(unsigned int inputnumcols, unsigned int outputnumcols, 
-		unsigned int index[], vector<IonHit> &posIons,const char *posFile, 
+		const unsigned int index[], vector<IonHit> &posIons,const char *posFile, 
 				unsigned int &progress, bool (*callback)(bool));
 
 
-unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumcols, unsigned int index[], 
+unsigned int LimitLoadPosFile(unsigned int inputnumcols, unsigned int outputnumcols, const unsigned int index[], 
 			vector<IonHit> &posIons,const char *posFile, size_t limitCount,
 					       	unsigned int &progress, bool (*callback)(bool),bool strongRandom);
 
diff --git a/src/backend/APT/APTRanges.cpp b/src/backend/APT/APTRanges.cpp
index 9f45a8d..c8b06eb 100644
--- a/src/backend/APT/APTRanges.cpp
+++ b/src/backend/APT/APTRanges.cpp
@@ -40,7 +40,8 @@ using std::accumulate;
 
 //Arbitrary maximum range file line size
 const size_t MAX_LINE_SIZE = 16536;
-
+//Arbitrary maximum range file size, in bytes
+const size_t MAX_RANGEFILE_SIZE = 20*1024*1024;
 const char *rangeErrStrings[] = 
 {
 	"",
@@ -62,6 +63,7 @@ const char *rangeErrStrings[] =
 	NTRANS("Range file appears to be inconsistent (eg, overlapping ranges)"),
 	NTRANS("No ion name mapping found  for multiple ion."),
 	NTRANS("Polyatomic extension range matches multiple masses in first section"),
+	NTRANS("Range file is exceedingly large. Refusing to open"),
 };
 
 const char *RANGE_EXTS[] = { "rng",
@@ -470,17 +472,16 @@ unsigned int RangeFile::write(std::ostream &f, size_t format) const
 
 			for(size_t ui=0;ui<ranges.size();ui++)
 			{
+				ColourRGBA tmpRgba;
+				tmpRgba.fromRGBf(colours[ui]);
 				std::string colString;
-				genColString((unsigned char)colours[ui].red*255,
-					(unsigned char)colours[ui].green*255,
-					(unsigned char)colours[ui].blue*255,colString);
-
+				colString = tmpRgba.rgbString();
 				//strip leading #
 				colString=colString.substr(1);
 				ASSERT(colString.size() == 6);
 
 				//FIXME: This is incomplete. we need to break the species apart into its 
-				// compponents, then decide to use the Element:count notation, or the Name:species notation
+				// components, then decide to use the Element:count notation, or the Name:species notation
 				string strName;
 				strName=ionNames[ionIDs[ui]].first;
 				if(elementSet.find(strName) != elementSet.end())
@@ -492,6 +493,8 @@ unsigned int RangeFile::write(std::ostream &f, size_t format) const
 				}
 				else
 				{
+					//Difference is we have to use the "Name" parameter if not in set
+					
 					f << "Range" << ui+1 <<"=" 
 					<< ranges[ui].first << " " << ranges[ui].second <<
 					" " << "Name:" << strName << ":1" << 
@@ -531,6 +534,12 @@ void RangeFile::clear()
 
 unsigned int RangeFile::open(const char *rangeFilename, unsigned int fileFormat)
 {
+	size_t fileSize;
+	getFilesize(rangeFilename,fileSize);
+
+	if(fileSize > MAX_RANGEFILE_SIZE)
+		return RANGE_ERR_FILESIZE;
+
 	FILE *fpRange;
 	fpRange=fopen(rangeFilename,"r");
 	if (fpRange== NULL) 
@@ -594,10 +603,17 @@ unsigned int RangeFile::open(const char *rangeFilename, unsigned int fileFormat)
 
 bool RangeFile::openGuessFormat(const char *rangeFilename)
 {
-	unsigned int assumedFileFormat;
-
 
+	//Check the filesize before attempting to guess the format
+	size_t fileSize;
+	getFilesize(rangeFilename,fileSize);
+	if(fileSize > MAX_RANGEFILE_SIZE)
+	{
+		errState=RANGE_ERR_FILESIZE;
+		return false;
+	}
 	//Try to auto-detect the filetype
+	unsigned int assumedFileFormat;
 	assumedFileFormat=detectFileType(rangeFilename);
 
 	if(assumedFileFormat < RANGE_FORMAT_END_OF_ENUM)
@@ -1715,8 +1731,9 @@ unsigned int RangeFile::openENV(FILE *fpRange)
 	//There should be more data following the range information.
 	// if not, this is not really an env file
 	if(feof(fpRange))
+	{
 		return RANGE_ERR_FORMAT;
-
+	}	
 
 	return 0;
 }
@@ -1829,10 +1846,10 @@ unsigned int RangeFile::openRRNG(FILE *fpRange)
 					basicIonNames.push_back(split[1]);
 
 					if (basicIonNames.size()  > numBasicIons)
-				{
-					delete[] inBuffer;
-					return RANGE_ERR_FORMAT;
-				}
+					{
+						delete[] inBuffer;
+						return RANGE_ERR_FORMAT;
+					}
 				}
 				else
 				{
@@ -1996,13 +2013,16 @@ unsigned int RangeFile::openRRNG(FILE *fpRange)
 							//which requires a leading #,
 							//in lowercase
 							value = string("#") + lowercase(value);
-							unsigned char r,g,b,a;
-
-							parseColString(value,r,g,b,a);
+							ColourRGBA tmpRgba;
+							if(!tmpRgba.parse(value))
+							{
+								delete[] inBuffer;
+								return RANGE_ERR_FORMAT;
+							}
 
-							col.red = (float)r/255.0f;
-							col.green=(float)g/255.0f;
-							col.blue=(float)b/255.0f;
+							col.red = (float)tmpRgba.r()/255.0f;
+							col.green=(float)tmpRgba.g()/255.0f;
+							col.blue=(float)tmpRgba.b()/255.0f;
 						}
 						else
 						{
diff --git a/src/backend/APT/APTRanges.h b/src/backend/APT/APTRanges.h
index 35b8946..a08ba92 100644
--- a/src/backend/APT/APTRanges.h
+++ b/src/backend/APT/APTRanges.h
@@ -24,6 +24,7 @@
 
 
 #include "backend/APT/ionhit.h"
+#include "common/basics.h"
 
 enum{	
 	RANGE_ERR_OPEN =1, 
@@ -44,16 +45,10 @@ enum{
 	RANGE_ERR_DATA_INCONSISTENT,
 	RANGE_ERR_DATA_NOMAPPED_IONNAME,
 	RANGE_ERR_NONUNIQUE_POLYATOMIC,
+	RANGE_ERR_FILESIZE,
 	RANGE_ERR_ENUM_END
 };
 
-//!Data holder for colour as float
-typedef struct RGBf
-{
-	float red;
-	float green;
-	float blue;
-} RGBf;
 
 //Number of elements stored in the table
 const unsigned int NUM_ELEMENTS=119;
@@ -64,6 +59,7 @@ enum{ RANGE_FORMAT_ORNL,
 	RANGE_FORMAT_RRNG,
 	RANGE_FORMAT_END_OF_ENUM //not a format, just end of enumueration.
 };
+
 //!Data storage and retrieval class for various range files
 class RangeFile
 {
@@ -132,7 +128,7 @@ class RangeFile
 		RangeFile();
 
 		const RangeFile& operator=(const RangeFile &other);
-		//!Open a specified range file
+		//!Open a specified range file, returns zero on success, nonzero on failure
 		unsigned int open(const char *rangeFile, unsigned int format=RANGE_FORMAT_ORNL);	
 		//!Open a specified range file - returns true on success
 		bool openGuessFormat(const char *rangeFile);
diff --git a/src/backend/APT/abundanceParser.cpp b/src/backend/APT/abundanceParser.cpp
index 49f5aac..fba3917 100644
--- a/src/backend/APT/abundanceParser.cpp
+++ b/src/backend/APT/abundanceParser.cpp
@@ -353,3 +353,76 @@ void AbundanceData::getSymbolIndices(const vector<string> &symbols,vector<size_t
 		indices[ui]=symbolIndex(symbols[ui].c_str());
 }
 
+
+#ifdef DEBUG
+
+#include <set>
+
+using std::set;
+
+void AbundanceData::checkErrors() const
+{
+	//Ensure all isotopes sum to 1-ish
+	// Rounding errors limit our correctness here.
+	for(size_t ui=0;ui<isotopeData.size();ui++)
+	{
+		if(!isotopeData[ui].size())
+			continue;
+
+		float sum;
+		sum=0.0f;
+		for(size_t uj=0; uj<isotopeData[ui].size();uj++)
+		{
+			sum+=isotopeData[ui][uj].abundance;
+		}
+
+		ASSERT(fabs(sum -1.0f) < 0.000001);
+
+	}
+
+
+	//Ensure Ti has 5 isotopes (original data file was missing)
+	ASSERT(isotopeData[symbolIndex("Ti")].size() == 5);
+
+	//Enusre all isotopes are uniquely numbered
+	// - loop over each atom
+	for(size_t ui=0;ui<isotopeData.size();ui++)
+	{
+		//now ovre each isotope
+		std::set<size_t> uniqNums;
+		uniqNums.clear();
+		for(size_t uj=0; uj<isotopeData[ui].size();uj++)
+		{
+			ASSERT(uniqNums.find(isotopeData[ui][uj].massNumber) == uniqNums.end());
+			uniqNums.insert(isotopeData[ui][uj].massNumber);
+			
+		}
+	}
+}
+
+bool AbundanceData::runUnitTests(const char *tableFile)
+{
+	AbundanceData massTable;
+	TEST(massTable.open(tableFile) == 0,"load table");
+	//FIXME: Getting the isotope dis
+
+	size_t ironIndex=massTable.symbolIndex("Fe");
+	TEST(ironIndex != (size_t)-1,"symbol lookup");
+
+	//Generate the mass peak dist for iron
+	vector<size_t> elements;
+	vector<size_t> concentrations;
+	elements.push_back(ironIndex);
+	concentrations.push_back(1);
+
+	std::vector<std::pair<float,float> > massDist;
+	massTable.generateIsotopeDist(elements,concentrations,massDist);
+
+	TEST(massDist.size() == 4, "Iron has 4 isotopes");
+
+	massTable.checkErrors();
+
+	return true;	
+
+}
+#endif
diff --git a/src/backend/APT/abundanceParser.h b/src/backend/APT/abundanceParser.h
index 0eb2289..8111c15 100644
--- a/src/backend/APT/abundanceParser.h
+++ b/src/backend/APT/abundanceParser.h
@@ -50,7 +50,7 @@ class AbundanceData
 {
 	enum
 	{
-		ABUNDANCE_ERR_BAD_DOC,
+		ABUNDANCE_ERR_BAD_DOC=1,
 		ABUNDANCE_ERR_NO_CONTEXT,
 		ABUNDANCE_ERROR_BAD_VALUE,
 		ABUNDANCE_ERROR_FAILED_VALIDATION,
@@ -68,6 +68,9 @@ class AbundanceData
 	// this is esentially a lookup (isotope # -> atom #)
 	std::vector<size_t> atomicNumber;
 
+	//Check the abundance table for inconsistenceis
+	void checkErrors() const; 
+
 	public:
 		//!Attempt to open the abundance data file, return 0 on success
 		size_t open(const char *file, bool strict=false);	
@@ -94,6 +97,11 @@ class AbundanceData
 		void generateSingleAtomDist(size_t atomIdx, unsigned int repeatCount, std::vector<std::pair<float,float> > &massDist,size_t solutionCharge=1) const;
 
 		const ISOTOPE_DATA &isotope(size_t elementIdx, size_t isotopeIdx) const;
+
+#ifdef DEBUG
+		//Run the unit esting code
+		static bool runUnitTests(const char *tableFile);
+#endif
 };
 
 #endif
diff --git a/src/backend/APT/ionhit.cpp b/src/backend/APT/ionhit.cpp
index dcd2e59..f45f890 100644
--- a/src/backend/APT/ionhit.cpp
+++ b/src/backend/APT/ionhit.cpp
@@ -176,6 +176,12 @@ bool IonHit::hasNaN()
 				std::isnan(pos[1]) || std::isnan(pos[2]));
 }
 
+bool IonHit::hasInf()
+{
+	return (std::isinf(massToCharge) || std::isinf(pos[0]) || 
+				std::isinf(pos[1]) || std::isinf(pos[2]));
+}
+
 void IonHit::getCentroid(const std::vector<IonHit> &points,Point3D &centroid)
 {
 	centroid=Point3D(0,0,0);
diff --git a/src/backend/APT/ionhit.h b/src/backend/APT/ionhit.h
index e90947a..e8cc552 100644
--- a/src/backend/APT/ionhit.h
+++ b/src/backend/APT/ionhit.h
@@ -50,6 +50,8 @@ class IonHit
 		inline const Point3D &getPosRef() const {return pos;};
 		//returns true if any of the 4 data pts are NaN
 		bool hasNaN();
+		//returns true if any of the 4 data pts are +-inf
+		bool hasInf();
 
 #ifdef __LITTLE_ENDIAN__		
 		void switchEndian();
diff --git a/src/backend/animator.cpp b/src/backend/animator.cpp
index e69ce06..cde1f99 100644
--- a/src/backend/animator.cpp
+++ b/src/backend/animator.cpp
@@ -536,29 +536,11 @@ std::string InterpData::getInterpolatedData(const vector<pair<size_t,
 
 			//Parse the colour start and end strings
 			//---------
-			float colStart[4]; 
-			float colEnd[4];
+			ColourRGBA tmpCol[2];
 
-			unsigned char r,g,b,alpha;
-			ASSERT(parseColString(keyData[0].second,r,g,b,alpha));
-			ASSERT(parseColString(keyData[1].second,r,g,b,alpha));
-
-			parseColString(keyData[0].second,r,g,b,alpha);
-			alpha=255;
-
-			colStart[0] = r/255.0f;
-			colStart[1] = g/255.0f;
-			colStart[2] = b/255.0f;
-			colStart[3] = alpha/255.0f;
-
-
-			parseColString(keyData[1].second,r,g,b,alpha);
-
-
-			colEnd[0] = r/255.0f;
-			colEnd[1] = g/255.0f;
-			colEnd[2] = b/255.0f;
-			colEnd[3] = alpha/255.0f;
+			
+			tmpCol[0].parse(keyData[0].second);
+			tmpCol[1].parse(keyData[1].second);
 		
 			//---------
 			
@@ -576,23 +558,11 @@ std::string InterpData::getInterpolatedData(const vector<pair<size_t,
 			}
 		
 			//interpolate the colour value
-			unsigned char colInterp[4];
-			for(size_t ui=0; ui<4;ui++)
-			{
-				float tmp;
-				tmp=(interpLinearRamp(startF,endF,frame,
-							colStart[ui],colEnd[ui])*255.0f);
-
-				tmp = std::min(tmp,255.0f);
-				tmp=std::max(tmp,0.0f);
-
-				colInterp[ui] = (unsigned char)tmp;
-			}
-
-			std::string s;
-			genColString(colInterp[0],colInterp[1],colInterp[2],
-					colInterp[3],s);
-			return s;
+			ColourRGBAf interpCol;
+			float delta;
+			delta = (frame - startF )/ (endF - startF);
+			interpCol=tmpCol[0].toRGBAf().interpolate(delta,tmpCol[1].toRGBAf());
+			return interpCol.toColourRGBA().rgbaString();
 		}
 		case INTERP_LIST:
 		{
diff --git a/src/backend/configFile.cpp b/src/backend/configFile.cpp
index 1bdea7e..b962cdc 100644
--- a/src/backend/configFile.cpp
+++ b/src/backend/configFile.cpp
@@ -521,7 +521,7 @@ nodeptrEndJump:
 
 bool ConfigFile::createConfigDir()
 {
-	wxString filePath = wxStr(getConfigDir());
+	wxString filePath = (getConfigDir());
 
 	//Create the folder if it does not exist
 	if(!wxDirExists(filePath))
@@ -540,14 +540,8 @@ bool ConfigFile::createConfigDir()
 
 std::string ConfigFile::getConfigDir() 
 {
-#if wxCHECK_VERSION(2,9,0)
  	wxStandardPaths &paths = wxStandardPaths::Get();
-	wxString filePath = paths.GetDocumentsDir()+wxCStr("/.")+wxCStr(PROGRAM_NAME);
-#else
-	wxStandardPaths *paths = new wxStandardPaths;
-	wxString filePath = paths->GetDocumentsDir()+wxCStr("/.")+wxCStr(PROGRAM_NAME);
-	delete paths;
-#endif
+	wxString filePath = paths.GetDocumentsDir()+("/.")+(PROGRAM_NAME);
 	return stlStr(filePath);
 }
 
diff --git a/src/backend/filter.cpp b/src/backend/filter.cpp
index fc58788..8f0f15b 100644
--- a/src/backend/filter.cpp
+++ b/src/backend/filter.cpp
@@ -17,6 +17,7 @@
 */
 
 #include "filter.h"
+#include "plot.h"
 
 #include "common/stringFuncs.h"
 #include "common/translation.h"
@@ -42,6 +43,7 @@ bool Filter::strongRandom= false;
 
 const char *STREAM_NAMES[] = { NTRANS("Ion"),
 				NTRANS("Plot"),
+				NTRANS("2D Plot"),
 				NTRANS("Draw"),
 				NTRANS("Range"),
 				NTRANS("Voxel")};
@@ -64,60 +66,89 @@ const char *FILTER_NAMES[] = { "posload",
 				"annotation"
 				};
 
-void updateFilterPropertyGrid(wxCustomPropGrid *g, const Filter *f)
+size_t numElements(const vector<const FilterStreamData *> &v, unsigned int mask)
 {
+	size_t nE=0;
+	for(unsigned int ui=0;ui<v.size();ui++)
+	{
+		if((v[ui]->getStreamType() & mask))
+			nE+=v[ui]->getNumBasicObjects();
+	}
+
+	return nE;
+}
+
 
-	ASSERT(f);
-	ASSERT(g);
+template<>
+bool Filter::applyPropertyNow(bool &prop, const std::string &val, bool &needUp)
+{
+	needUp=false;
+	bool tmp;
+	if(!boolStrDec(val,tmp))
+		return false;
 	
-	FilterPropGroup p;
-	f->getProperties(p);
-#ifdef DEBUG
-	//If debugging, test self consistency
-	p.checkConsistent();
-#endif	
-	g->clearKeys();
-	g->setNumGroups(p.numGroups());
+	//return true, as technically, we did something OK
+	// but erasing the cache, and re-setting the value is pointless
+	if(tmp == prop)
+		return true;
+	
+	prop=tmp;
+	clearCache();
+
+	needUp=true;
+	return true;	
+}
+
+template<>
+bool Filter::applyPropertyNow(Point3D &prop, const std::string &val, bool &needUp)
+{
+	needUp=false;
 
+	Point3D newPt;	
+	if(!newPt.parse(val))
+		return false;
 	
-	//Create the keys to add to the grid
-	for(size_t ui=0;ui<p.numGroups();ui++)
-	{
-		vector<FilterProperty> propGrouping;
-		p.getGroup(ui,propGrouping);
+	//return true, as technically, we did something OK
+	// but erasing the cache, and re-setting the value is pointless
+	if(newPt== prop)
+		return true;
+	
+	prop=newPt;
+	clearCache();
+	needUp=true;
+	return true;	
+}
 
-		for(size_t uj=0;uj<propGrouping.size();uj++)
-		{
-			g->addKey(propGrouping[uj].name,ui,
-				propGrouping[uj].key,
-				propGrouping[uj].type,
-				propGrouping[uj].data,
-				propGrouping[uj].helpText);
-		}
+template<>
+bool Filter::applyPropertyNow(std::string &prop, const std::string &val, bool &needUp)
+{
+	needUp=false;
 
-		//Set the name that is to be displayed for this grouping
-		// of properties
-		std::string title;
-		p.getGroupTitle(ui,title);
-		g->setGroupName(ui,title);
-	}
+	//return true, as it is technically ok that we did this
+	if(val == prop)
+		return true;
 	
-	//Let the property grid layout what it needs to
-	g->propertyLayout();
+	prop=val;
+	clearCache();
+	needUp=true;
+	return true;	
 }
 
-size_t numElements(const vector<const FilterStreamData *> &v, unsigned int mask)
+void Filter::cacheAsNeeded(FilterStreamData *stream)
 {
-	size_t nE=0;
-	for(unsigned int ui=0;ui<v.size();ui++)
+	if(cache)
 	{
-		if((v[ui]->getStreamType() & mask))
-			nE+=v[ui]->getNumBasicObjects();
+		stream->cached=1;
+		filterOutputs.push_back(stream);
+		cacheOK=true;
+	}	
+	else
+	{
+		stream->cached=0;
 	}
-
-	return nE;
 }
 
+
 #ifdef DEBUG
 bool FilterProperty::checkSelfConsistent() const
 {	
@@ -143,8 +174,8 @@ bool FilterProperty::checkSelfConsistent() const
 		}
 		case PROPERTY_TYPE_COLOUR:
 		{
-			unsigned char r,g,b,a;
-			if(!parseColString(data,r,g,b,a))
+			ColourRGBA rgba;
+			if(!rgba.parse(data))
 				return false;
 
 			break;
@@ -225,6 +256,16 @@ void FilterPropGroup::getGroup(size_t targetGroup, vector<FilterProperty> &vec)
 #endif
 }
 
+bool FilterPropGroup::hasGroup(size_t targetGroup) const
+{
+	for(size_t ui=0;ui<keyGroupings.size();ui++)
+	{
+		if(keyGroupings[ui].second==targetGroup)
+			return true;
+	}
+
+	return false;
+}
 void FilterPropGroup::getGroupTitle(size_t group, std::string &s) const
 {
 	ASSERT(group < groupNames.size());
@@ -282,6 +323,12 @@ void FilterPropGroup::checkConsistent() const
 	//Check that the group names are the same as the number of groups
 	ASSERT(groupNames.size() ==groupCount);
 
+
+	//check that each group ahas a name
+	for(size_t ui=0;ui<groupNames.size(); ui++)
+	{
+		ASSERT(!groupNames[ui].empty())
+	}
 }
 #endif
 
@@ -320,7 +367,7 @@ void DrawStreamData::checkSelfConsistent() const
 #endif
 
 PlotStreamData::PlotStreamData() :  r(1.0f),g(0.0f),b(0.0f),a(1.0f),
-	plotStyle(PLOT_TRACE_LINES), logarithmic(false) , useDataLabelAsYDescriptor(true), 
+	plotStyle(PLOT_LINE_LINES), logarithmic(false) , useDataLabelAsYDescriptor(true), 
 	index((unsigned int)-1)
 {
 	streamType=STREAM_TYPE_PLOT;
@@ -422,7 +469,7 @@ void PlotStreamData::checkSelfConsistent() const
 	ASSERT(!(regionID.size() && !regionParent));
 
 	//Must have valid trace style
-	ASSERT(plotStyle<PLOT_TRACE_ENDOFENUM);
+	ASSERT(plotStyle<PLOT_TYPE_ENUM_END);
 	//Must have valid error bar style
 	ASSERT(errDat.mode<PLOT_ERROR_ENDOFENUM);
 
@@ -433,7 +480,36 @@ void PlotStreamData::checkSelfConsistent() const
 }
 #endif
 
+Plot2DStreamData::Plot2DStreamData()
+{
+	streamType=STREAM_TYPE_PLOT2D;
+}
+
+size_t Plot2DStreamData::getNumBasicObjects() const
+{
+	if(xyData.size())
+		return xyData.size();
+	else if (scatterData.size())
+		return scatterData.size();
+	else
+		ASSERT(false);
+
+	return 0;
+}
+
 #ifdef DEBUG
+
+void Plot2DStreamData::checkSelfConsistent() const
+{
+	//only using scatter or xy, not both
+	ASSERT(!(xyData.empty() && scatterData.empty()));
+
+	//no intensity without data
+	if(scatterData.empty())
+		ASSERT(scatterIntensity.empty());
+
+	ASSERT(plotType < PLOT_TYPE_ENUM_END);
+}
 void RangeStreamData::checkSelfConsistent() const
 {
 	if(!rangeFile)
@@ -450,6 +526,10 @@ FilterStreamData::FilterStreamData() : parent(0),cached((unsigned int)-1)
 {
 }
 
+FilterStreamData::FilterStreamData(const Filter  *theParent) : parent(theParent),cached((unsigned int)-1)
+{
+}
+
 IonStreamData::IonStreamData() : representationType(ION_REPRESENT_POINTS), 
 	r(1.0f), g(0.0f), b(0.0f), a(1.0f), 
 	ionSize(2.0f), valueType("Mass-to-Charge (amu/e)")
@@ -457,6 +537,14 @@ IonStreamData::IonStreamData() : representationType(ION_REPRESENT_POINTS),
 	streamType=STREAM_TYPE_IONS;
 }
 
+IonStreamData::IonStreamData(const Filter *f) : FilterStreamData(f), representationType(ION_REPRESENT_POINTS), 
+	r(1.0f), g(0.0f), b(0.0f), a(1.0f), 
+	ionSize(2.0f), valueType("Mass-to-Charge (amu/e)")
+{
+	streamType=STREAM_TYPE_IONS;
+}
+
+
 void IonStreamData::clear()
 {
 	data.clear();
@@ -505,11 +593,22 @@ VoxelStreamData::VoxelStreamData() : representationType(VOXEL_REPRESENT_POINTCLO
 	streamType=STREAM_TYPE_VOXEL;
 }
 
+VoxelStreamData::VoxelStreamData(const Filter *f) : FilterStreamData(f), representationType(VOXEL_REPRESENT_POINTCLOUD),
+	r(1.0f),g(0.0f),b(0.0f),a(0.3f), splatSize(2.0f),isoLevel(0.5f)
+{
+	streamType=STREAM_TYPE_VOXEL;
+}
+
 RangeStreamData::RangeStreamData() : rangeFile(0)
 {
 	streamType = STREAM_TYPE_RANGE;
 }
 
+RangeStreamData::RangeStreamData(const Filter *f) : FilterStreamData(f), rangeFile(0)
+{
+	streamType = STREAM_TYPE_RANGE;
+}
+
 bool RangeStreamData::save(const char *filename, size_t format) const
 {
 	return !rangeFile->write(filename,format);
@@ -517,6 +616,7 @@ bool RangeStreamData::save(const char *filename, size_t format) const
 
 Filter::Filter() : cache(true), cacheOK(false)
 {
+	COMPILE_ASSERT( THREEDEP_ARRAYSIZE(STREAM_NAMES) == NUM_STREAM_TYPES);
 	for(unsigned int ui=0;ui<NUM_STREAM_TYPES;ui++)
 		numStreamsLastRefresh[ui]=0;
 }
@@ -597,7 +697,7 @@ void Filter::propagateCache(vector<const FilterStreamData *> &getOut) const
 }
 
 void Filter::propagateStreams(const vector<const FilterStreamData *> &dataIn,
-		vector<const FilterStreamData *> &dataOut,size_t mask,bool invertMask) const
+		vector<const FilterStreamData *> &dataOut,size_t mask,bool invertMask)
 {
 	//Propagate any inputs that we don't normally block
 	if(invertMask)
diff --git a/src/backend/filter.h b/src/backend/filter.h
index bdc09cc..81eb9cc 100644
--- a/src/backend/filter.h
+++ b/src/backend/filter.h
@@ -33,6 +33,8 @@ class RangeFileFilter;
 #include "gl/drawables.h"
 
 #include "common/voxels.h"
+#include "common/stringFuncs.h"
+#include "common/array2D.h"
 
 //ifdef inclusion as there is some kind of symbol clash...
 #ifdef ATTRIBUTE_PRINTF
@@ -45,6 +47,7 @@ class RangeFileFilter;
 #endif
 
 
+#include <wx/propgrid/propgrid.h>
 
 const unsigned int NUM_CALLBACK=50000;
 
@@ -79,15 +82,16 @@ extern const char *FILTER_NAMES[];
 //the number of stream types that we can have.
 //Current bitmask using functions are
 //	VisController::safeDeleteFilterList
-const unsigned int NUM_STREAM_TYPES=5;
+const unsigned int NUM_STREAM_TYPES=6;
 const unsigned int STREAMTYPE_MASK_ALL= ((1<<(NUM_STREAM_TYPES)) -1 ) & 0x000000FF;
 enum
 {
 	STREAM_TYPE_IONS=1,
 	STREAM_TYPE_PLOT=2,
-	STREAM_TYPE_DRAW=4,
-	STREAM_TYPE_RANGE=8,
-	STREAM_TYPE_VOXEL=16
+	STREAM_TYPE_PLOT2D=4,
+	STREAM_TYPE_DRAW=8,
+	STREAM_TYPE_RANGE=16,
+	STREAM_TYPE_VOXEL=32
 };
 
 
@@ -147,14 +151,10 @@ enum
 //---
 //
 
-//Forward dec.
-class wxCustomPropGrid;
-
 //!Return the number of elements in a vector of filter data - i.e. the sum of the number of objects within each stream. Only masked streams (STREAM_TYPE_*) will be counted
 size_t numElements(const vector<const FilterStreamData *> &vm, unsigned int mask=STREAMTYPE_MASK_ALL);
 
 
-void updateFilterPropertyGrid(wxCustomPropGrid *g, const Filter *f);
 
 //!Abstract base class for data types that can propagate through filter system
 class FilterStreamData
@@ -171,6 +171,7 @@ class FilterStreamData
 		unsigned int cached;
 
 		FilterStreamData();
+		FilterStreamData(const Filter *);
 		virtual ~FilterStreamData() {}; 
 		virtual size_t getNumBasicObjects() const =0;
 		//!Returns an integer unique to the class to identify type (yes rttid...)
@@ -197,6 +198,9 @@ class FilterProperty
 	size_t key;
 	//!Property data
 	std::string data;
+	//!Secondary property data
+	//	- eg for file, contains wildcard mask for filename
+	std::string dataSecondary;
 	//!name of property
 	std::string name;
 
@@ -243,6 +247,9 @@ class FilterPropGroup
 
 		//!Grab all properties from the specified group
 		void getGroup(size_t group, vector<FilterProperty> &groupVec) const;
+		
+		//Confirm a particular group exists
+		bool hasGroup(size_t group) const;
 		//!Get the nth key
 		const FilterProperty &getNthProp(size_t nthProp) const { return properties[nthProp];};
 
@@ -257,6 +264,7 @@ class IonStreamData : public FilterStreamData
 {
 public:
 	IonStreamData();
+	IonStreamData(const Filter *f);
 	void clear();
 
 	//Sample the data vector to the specified fraction
@@ -285,6 +293,7 @@ class VoxelStreamData : public FilterStreamData
 {
 public:
 	VoxelStreamData();
+	VoxelStreamData( const Filter *f);
 	size_t getNumBasicObjects() const { return data.getSize();};
 	void clear();
 	
@@ -302,6 +311,7 @@ class PlotStreamData : public FilterStreamData
 {
 	public:
 		PlotStreamData();
+		PlotStreamData(const Filter *f);
 
 		bool save(const char *filename) const; 
 
@@ -360,6 +370,43 @@ class PlotStreamData : public FilterStreamData
 
 };
 
+//!2D Plotting data
+class Plot2DStreamData : public FilterStreamData
+{
+	public:
+		Plot2DStreamData();
+		Plot2DStreamData(const Filter *f);
+
+		//erase plot contents	
+		void clear() {xyData.clear();};
+			
+		size_t getNumBasicObjects() const; 
+		//title for data
+		std::string dataLabel;
+		//Label for X, Y axes
+		std::string xLabel,yLabel;
+
+		unsigned int plotType;
+
+		//!Structured XY data pairs for plotting curve
+		Array2D<float> xyData;
+		//Only rqeuired for xy plots
+		float xMin,xMax,yMin,yMax;
+		
+		//!Unstructured XY points
+		vector<pair<float,float> > scatterData;
+		//optional intensity data for scatter plots
+		vector<float> scatterIntensity;
+	
+
+		//!Parent filter index
+		unsigned int index;
+
+#ifdef DEBUG
+		void checkSelfConsistent() const;
+#endif
+};
+
 //!Drawable objects, for 3D decoration. 
 class DrawStreamData: public FilterStreamData
 {
@@ -368,6 +415,7 @@ class DrawStreamData: public FilterStreamData
 		vector<DrawableObj *> drawables;
 		//!constructor
 		DrawStreamData(){ streamType=STREAM_TYPE_DRAW;};
+		DrawStreamData(const Filter *f){ streamType=STREAM_TYPE_DRAW;};
 		//!Destructor
 		~DrawStreamData();
 		//!Returns 0, as this does not store basic object types -- i.e. is not for data storage per se.
@@ -397,6 +445,7 @@ class RangeStreamData :  public FilterStreamData
 		
 		//!constructor
 		RangeStreamData();
+		RangeStreamData(const Filter *f);
 		//!Destructor
 		~RangeStreamData() {};
 		//!save the range data to a file
@@ -443,12 +492,23 @@ class Filter
 				bool (*callback)(bool),size_t totalDataSize=(size_t)-1);
 
 		//!Propagate the given input data to an output vector
-		void propagateStreams(const vector<const FilterStreamData *> &dataIn,
-				vector<const FilterStreamData *> &dataOut,size_t mask=STREAMTYPE_MASK_ALL,bool invertMask=false) const;
+		static void propagateStreams(const vector<const FilterStreamData *> &dataIn,
+				vector<const FilterStreamData *> &dataOut,size_t mask=STREAMTYPE_MASK_ALL,bool invertMask=false) ;
 
 		//!Propagate the cache into output
 		void propagateCache(vector<const FilterStreamData *> &dataOut) const;
 
+		//Set a property, without any checking of the new value 
+		// -clears cache on change
+		// - and skipping if no actual change between old and new prop
+		// returns true if change applied OK.
+		template<class T>	
+		bool applyPropertyNow(T &oldProp,const std::string &newVal, bool &needUp);
+	
+
+		//place a stream object into the filter cache, if required
+		// does not place object into filter output - you need to do that yourself
+		void cacheAsNeeded(FilterStreamData *s); 
 	public:	
 		Filter() ;
 		virtual ~Filter();
@@ -605,6 +665,41 @@ class Filter
 
 };
 
+//Template specialisations & def for  applyPropertyNow
+//--
+template<>
+bool Filter::applyPropertyNow(Point3D &prop, const std::string &val, bool &needUp);
+
+template<>
+bool Filter::applyPropertyNow(bool &prop, const std::string &val, bool &needUp);
+
+template<>
+bool Filter::applyPropertyNow(std::string &prop, const std::string &val, bool &needUp);
+
+template<class T>
+bool Filter::applyPropertyNow(T &prop, const std::string &val, bool &needUp)
+{
+	// no update initially needed
+	needUp=false;
+
+	//convert to type T
+	std::string s;
+	s=stripWhite(val);
+	T tmp;
+	if(stream_cast(tmp,s))
+		return false;
+	
+	//return true, as it is technically ok that we assign to self.
+	// needUp however stays false, as the property is the same.
+	if(tmp == prop)
+		return true;
+	
+	prop=tmp;
+	clearCache();
+	needUp=true;
+	return true;	
+}
+//--
 
 //!Class that tracks the progress of scene updates
 class ProgressData
diff --git a/src/backend/filters/algorithms/K3DTree-mk2.cpp b/src/backend/filters/algorithms/K3DTree-mk2.cpp
index 61fa062..84ca087 100644
--- a/src/backend/filters/algorithms/K3DTree-mk2.cpp
+++ b/src/backend/filters/algorithms/K3DTree-mk2.cpp
@@ -106,7 +106,7 @@ size_t K3DTreeMk2::size() const
 	return indexedPoints.size();
 }
 
-bool K3DTreeMk2::build()
+bool K3DTreeMk2::build(bool wantCallback)
 {
 
 	const size_t PROGRESS_REDUCE=5000;
@@ -263,7 +263,7 @@ bool K3DTreeMk2::build()
 			}
 		}	
 
-		if(!(numSeen%PROGRESS_REDUCE) && progress)
+		if(wantCallback && !(numSeen%PROGRESS_REDUCE) && progress)
 		{
 			*progress= (unsigned int)((float)numSeen/(float)nodes.size()*100.0f);
 
@@ -377,8 +377,10 @@ void K3DTreeMk2::dump(std::ostream &strm,  size_t depth, size_t offset) const
 }
 
 size_t K3DTreeMk2::findNearestUntagged(const Point3D &searchPt,
-				const BoundCube &domainCube, bool shouldTag)
+				const BoundCube &domainCube, bool shouldTag, size_t pseudoRoot)
 {
+	//Tree must be built!
+	ASSERT(treeRoot < nodes.size() && maxDepth <=nodes.size())
 	enum { NODE_FIRST_VISIT, //First visit is when you descend the tree
 		NODE_SECOND_VISIT, //Second visit is when you come back from ->Left()
 		NODE_THIRD_VISIT // Third visit is when you come back from ->Right()
@@ -410,10 +412,16 @@ size_t K3DTreeMk2::findNearestUntagged(const Point3D &searchPt,
 	stackTop=0;
 
 	//Start at median of array, which is top of tree,
-	//by definition
-	curNode=treeRoot;
+	//by definition, unless an alternative entry point is given
+	size_t startNode;
+	if(pseudoRoot==(size_t) -1)
+		startNode=treeRoot;
+	else
+		startNode=pseudoRoot;
 
-	//check root node	
+	curNode=startNode;
+
+	//check start node	
 	if(!nodes[curNode].tagged)
 	{
 		float tmpDistSqr;
@@ -611,7 +619,7 @@ size_t K3DTreeMk2::findNearestUntagged(const Point3D &searchPt,
 		
 
 	//Keep going until we meet the root nde for the third time (one left, one right, one finish)	
-	}while(!(curNode== treeRoot &&  visit== NODE_THIRD_VISIT));
+	}while(!(curNode== startNode &&  visit== NODE_THIRD_VISIT));
 
 	if(bestPoint != (size_t) -1)
 		nodes[bestPoint].tagged|=shouldTag;
@@ -621,19 +629,20 @@ size_t K3DTreeMk2::findNearestUntagged(const Point3D &searchPt,
 
 
 void K3DTreeMk2::getTreesInSphere(const Point3D &pt, float sqrDist, const BoundCube &domainCube,
-					vector<pair<size_t,size_t> > &contigousBlocks ) const
+					vector<pair<size_t,size_t> > &contiguousBlocks ) const
 {
 	using std::queue;
 	using std::pair;
 	using std::make_pair;
 
+	if(treeRoot == (size_t) -1)
+		return;
+	
 	queue<int> nodeQueue;
 	queue<int> axisQueue;
 	queue<BoundCube> boundQueue;
 
 	queue<pair<int,int> > limitQueue;
-	if(treeRoot == (size_t) -1)
-		return;
 
 
 	nodeQueue.push(treeRoot);
@@ -662,7 +671,7 @@ void K3DTreeMk2::getTreesInSphere(const Point3D &pt, float sqrDist, const BoundC
 		{
 			//We are? Interesting. We must be a contiguous block from our lower
 			//to upper limits
-			contigousBlocks.push_back(limitQueue.front());
+			contiguousBlocks.push_back(limitQueue.front());
 		}
 		else if(tmpCube.intersects(pt,sqrDist))
 		{
@@ -716,6 +725,64 @@ void K3DTreeMk2::getTreesInSphere(const Point3D &pt, float sqrDist, const BoundC
 
 }
 
+size_t K3DTreeMk2::getBoxInTree(const BoundCube &box) const
+{
+	ASSERT(treeRoot !=(size_t)-1);
+
+	BoundCube curB;
+	curB=treeBounds;
+	int curNode=treeRoot;
+	int curAxis=0;	
+
+	//user-supplied box can overlap tree area (and thus not contain the box, by loop test)
+	// intersect the box with the tree bounds, such that it fits
+	BoundCube subBox;
+	subBox = curB.makeUnion(box);
+
+	//If our box-to-find fits inside the current bounds,
+	// keep refining our search area
+	while(curB.contains(subBox))
+	{
+		//Check for the tree's split axis
+		float axisPosition;
+		axisPosition=  indexedPoints[curNode].first[curAxis];
+		switch(box.segmentTriple(curAxis,axisPosition))
+		{
+			//query axis is below box - move lower bound up, by searching right child
+			case 0:
+			{
+				curB.setBound(curAxis, 0,axisPosition);
+				if(nodes[curNode].childRight == (size_t) -1)
+					return curNode;
+				curNode=nodes[curNode].childRight;
+				break;
+			}
+			//intersects
+			case 1:
+				//Nothing we can do any more - return current node as new pseudo-root
+				return curNode; 
+			//query axis is above target box - move upper bound down, and refine along left child
+			case 2:
+			{
+				curB.setBound(curAxis,1,axisPosition);
+				if(nodes[curNode].childLeft == (size_t) -1)
+					return curNode;
+				curNode=nodes[curNode].childLeft;
+				break;
+			}
+			default:
+				ASSERT(false);
+				
+		}
+	
+		curAxis++;
+		curAxis%=3;
+	}
+
+	
+	return curNode;
+}
+
 size_t K3DTreeMk2::tagCount() const
 {
 	size_t count=0;
@@ -742,3 +809,57 @@ void K3DTreeMk2::clearAllTags()
 	for(size_t ui=0;ui<nodes.size();ui++)
 		nodes[ui].tagged=false;
 }
+
+
+#ifdef DEBUG
+
+
+
+bool K3DMk2Tests()
+{
+	vector<Point3D> pts;
+
+	K3DTreeMk2 tree;
+	
+	//First test with single point
+	//--
+	pts.push_back(Point3D(0,0,0));
+	tree.resetPts(pts,false);
+
+	//build, but do not give progress
+	tree.build(false);
+	
+	Point3D searchPt=Point3D(1,0,0);
+	BoundCube dummyCube;
+	tree.getBoundCube(dummyCube);
+
+	size_t resultIdx;
+	
+	resultIdx=tree.findNearestUntagged(searchPt,dummyCube,false);
+	//Only one point to find - should find it
+	TEST(resultIdx == 0,"K3D Mk2, single point test");
+
+	//Get the contiguous nodes
+	BoundCube testBox;
+	testBox.setBounds(Point3D(-2,-2,-2),Point3D(2,2,2));
+
+	TEST(tree.getBoxInTree(testBox) == 0,"subtree test");
+	//---
+
+	//Now, try adding more points
+	//---
+	pts.push_back(Point3D(1,1,1));
+	pts.push_back(Point3D(1.1,0.9,0.95));
+	
+	tree.resetPts(pts,false);
+	tree.build(false);
+	
+	testBox.setBounds(Point3D(1.05,0.5,0.5),Point3D(1.5,1.5,1.5));
+	TEST(tree.getBoxInTree(testBox)==2,"subtree test pt2");
+	//---
+
+	return true;
+
+}
+
+#endif
diff --git a/src/backend/filters/algorithms/K3DTree-mk2.h b/src/backend/filters/algorithms/K3DTree-mk2.h
index 94f3038..1379ae7 100644
--- a/src/backend/filters/algorithms/K3DTree-mk2.h
+++ b/src/backend/filters/algorithms/K3DTree-mk2.h
@@ -103,7 +103,7 @@ class K3DTreeMk2
 		 *  previously set by "resetPts". returns false if callback returns
 		 *  false;
 		 */	
-		bool build();
+		bool build(bool wantCallback=true);
 
 		void getBoundCube(BoundCube &b);
 
@@ -114,9 +114,11 @@ class K3DTreeMk2
 
 
 		//Find the nearest "untagged" point's internal index.
-		//Mark the found point as "tagged" in the tree. Returns -1 on failure (no untagged points) 
+		//Mark the found point as "tagged" in the tree. Returns -1 on failure (no untagged points)
+		// optionaly, a sub-root branch of the tree can be specified, eg based upon range query,
+		// in order to speed up search
 		size_t findNearestUntagged(const Point3D &queryPt,
-						const BoundCube &b, bool tag=true);
+						const BoundCube &b, bool tag=true,size_t pseudoRoot=(size_t)-1);
 
 	
 		//!Get the contigous node IDs for a subset of points in the tree that are contained
@@ -128,6 +130,11 @@ class K3DTreeMk2
 		void getTreesInSphere(const Point3D &pt, float sqrDist, const BoundCube &domainCube,
 					std::vector<std::pair<size_t,size_t> > &contigousBlocks ) const;
 
+		//!Get the smallest contigous bounds that will contain a box.
+		// - new sub-tree root is returned. 
+		// function may only be called if tree is initalised
+		size_t getBoxInTree(const BoundCube &box) const;
+
 		//Obtain a point from its internal index
 		const Point3D *getPt(size_t index) const ;
 
@@ -157,4 +164,10 @@ class K3DTreeMk2
 		void clearAllTags();
 };
 
+
+#ifdef DEBUG
+//KD tree internal unit tests
+// - return true on OK, false on fail
+bool K3DMk2Tests();
+#endif
 #endif
diff --git a/src/backend/filters/allFilter.h b/src/backend/filters/allFilter.h
index ed8a140..68f356f 100644
--- a/src/backend/filters/allFilter.h
+++ b/src/backend/filters/allFilter.h
@@ -33,7 +33,6 @@
 #include "ionInfo.h"
 #include "annotation.h"
 
-
 //!Returns true if the string is a valid filter name
 bool isValidFilterName(const std::string &s);
 
diff --git a/src/backend/filters/annotation.cpp b/src/backend/filters/annotation.cpp
index 8563a4a..6f0d4b6 100644
--- a/src/backend/filters/annotation.cpp
+++ b/src/backend/filters/annotation.cpp
@@ -76,7 +76,7 @@ const char *annotationModeStrings[] =
 AnnotateFilter::AnnotateFilter() : annotationMode(ANNOTATION_TEXT),
 	position(Point3D(0,0,0)), target(Point3D(1,0,0)), upVec(Point3D(0,0,1)),
 	acrossVec(Point3D(0,1,0)), textSize(1.0f), annotateSize(1.0f),
-	sphereMarkerSize(1.5f),r(0),g(0),b(1),a(1),active(true),showAngleText(true), 
+	sphereMarkerSize(1.5f),rgba(0,0,1), active(true),showAngleText(true), 
 	reflexAngle(true), angleFormatPreDecimal(0),angleFormatPostDecimal(0),
 	linearFixedTicks(true),linearMeasureTicks(10),linearMeasureSpacing(10.0f),
 	fontSizeLinearMeasure(5)
@@ -93,9 +93,6 @@ AnnotateFilter::AnnotateFilter() : annotationMode(ANNOTATION_TEXT),
 	annotateSize=1;
 	sphereMarkerSize=1.5;
 	
-	//Set the colour to default blue
-	r=g=0;b=a=1.0;
-
 	active=true;
 	showAngleText=true;
 
@@ -129,11 +126,7 @@ Filter *AnnotateFilter::cloneUncached() const
 	p->annotateSize=annotateSize;
 	p->sphereMarkerSize=sphereMarkerSize;
 
-	p->r=r;
-	p->g=g;
-	p->b=b;
-	p->a=a;
-
+	p->rgba=rgba;
 	p->active=active;
 	p->showAngleText=showAngleText;
 
@@ -185,7 +178,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		dt->setString(annotateText);
 		dt->setOrigin(position);
 		dt->setUp(upVec);
-		dt->setColour(r,g,b,a);
+		dt->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 		dt->setTextDir(acrossVec);
 		dt->setSize((unsigned int)textSize);
 
@@ -215,7 +208,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		dv->setOrigin(position);
 		dv->setVector(target-position);
 		dv->setArrowSize(annotateSize);
-		dv->setColour(r,g,b,a);	
+		dv->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());	
 		dv->setLineSize(lineSize);
 	
 		dv->canSelect=true;
@@ -253,7 +246,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 			dS=new DrawSphere;
 			dS->setOrigin(anglePos[ui]);
 			dS->setRadius(sphereMarkerSize);
-			dS->setColour(r,g,b,a);
+			dS->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 
 			dS->canSelect=true;
 			dS->wantsLight=true;
@@ -283,14 +276,14 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		dv=new DrawVector;
 		dv->setOrigin(anglePos[0]);
 		dv->setVector(anglePos[1]-anglePos[0]);
-		dv->setColour(r,g,b,a);
+		dv->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 		dv->setDrawArrow(false);
 		d->drawables.push_back(dv);
 
 		dv=new DrawVector;
 		dv->setOrigin(anglePos[0]);
 		dv->setVector(anglePos[2]-anglePos[0]);
-		dv->setColour(r,g,b,a);
+		dv->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 		dv->setDrawArrow(false);
 		d->drawables.push_back(dv);
 
@@ -376,7 +369,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 			//Use user-specifications for colour,
 			//size and orientation
 			dt->setUp(upVec);
-			dt->setColour(r,g,b,a);
+			dt->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 			dt->setTextDir(acrossVec);
 			dt->setSize((unsigned int)textSize);
 		
@@ -391,7 +384,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 		dv = new DrawVector;
 
 		dv->setOrigin(position);
-		dv->setColour(r,g,b,a);
+		dv->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 		dv->setVector(target-position);
 		dv->setDrawArrow(false);
 
@@ -424,7 +417,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 				//Create the tick that will be added to the drawables
 				dT = new DrawGLText(getDefaultFontFile().c_str(),FTGL_POLYGON);
 					
-				dT->setColour(r,g,b,a);
+				dT->setColour(rgba.r(),rgba.g()	,rgba.b(),rgba.a());
 				dT->setOrigin(measureNormal*tickSpacings[ui] + position);
 				dT->setUp(upVec);	
 				dT->setTextDir(acrossVec);
@@ -446,7 +439,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 			dS = new DrawSphere;
 			dS->setRadius(sphereMarkerSize);
 			dS->setOrigin(position);
-			dS->setColour(r,g,b,a);
+			dS->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 
 			dS->canSelect=true;
 			dS->wantsLight=true;
@@ -479,7 +472,7 @@ unsigned int AnnotateFilter::refresh(const std::vector<const FilterStreamData *>
 			
 			dS->setRadius(sphereMarkerSize);
 			dS->setOrigin(target);
-			dS->setColour(r,g,b,a);
+			dS->setColour(rgba.r(),rgba.g(),rgba.b(),rgba.a());
 
 			dS->canSelect=true;
 			dS->wantsLight=true;
@@ -550,6 +543,7 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 	p.helpText=TRANS("Type or style of annotation");
 	p.type=PROPERTY_TYPE_CHOICE;
 	propertyList.addProperty(p,curGroup);
+	propertyList.setGroupTitle(curGroup,TRANS("Mode"));
 	curGroup++;
 
 	switch(annotationMode)
@@ -617,6 +611,8 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 			p.key=KEY_TARGET;
 			p.helpText=TRANS("3D Position to which arrow points");
 			propertyList.addProperty(p,curGroup);
+			
+			propertyList.setGroupTitle(curGroup,TRANS("Positioning"));
 
 			curGroup++;
 
@@ -667,6 +663,7 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 			p.helpText=TRANS("Text of annotation");
 			propertyList.addProperty(p,curGroup);
 			
+			propertyList.setGroupTitle(curGroup,TRANS("Options"));
 			curGroup++;
 
 			stream_cast(tmpStr,textSize);
@@ -725,6 +722,7 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 			p.helpText=TRANS("Location of second non-central vertex");
 			propertyList.addProperty(p,curGroup);
 			
+			propertyList.setGroupTitle(curGroup,TRANS("Positioning"));
 			curGroup++;
 			
 			stream_cast(tmpStr,acrossVec);
@@ -746,7 +744,7 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 
 			p.key=KEY_REFLEXIVE;
 			p.name=TRANS("Reflexive");
-			p.data=reflexAngle? "1":"0";
+			p.data=boolStrEnc(reflexAngle);
 			p.type=PROPERTY_TYPE_BOOL;
 			p.helpText=TRANS("Measure interor (enabled) or exterior angle (disabled)");
 			propertyList.addProperty(p,curGroup);
@@ -754,7 +752,7 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 			
 
 			p.name=TRANS("Show Angle");
-			p.data=showAngleText? "1":"0";
+			p.data=boolStrEnc(showAngleText);
 			p.type=PROPERTY_TYPE_BOOL;
 			p.key=KEY_ANGLE_TEXT_VISIBLE;
 			p.helpText=TRANS("Display angle text (when enabled)");
@@ -848,11 +846,8 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 			p.helpText=TRANS("Relative size of annotation text");
 			propertyList.addProperty(p,curGroup);
 			
-			
-			if(linearFixedTicks)
-				tmpStr="1";
-			else
-				tmpStr="0";
+		
+			tmpStr=boolStrEnc(linearFixedTicks);
 			p.key=KEY_LINEAR_FIXED_TICKS;
 			p.name=TRANS("Fixed ticks");
 			p.data=tmpStr;
@@ -897,15 +892,13 @@ void AnnotateFilter::getProperties(FilterPropGroup &propertyList) const
 	}
 
 
-	genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0),
-		(unsigned char)(b*255),(unsigned char)(a*255),tmpStr);
 	p.key=KEY_COLOUR;
 	p.name=TRANS("Colour");
-	p.data=tmpStr;
+	p.data=rgba.toColourRGBA().rgbString();
 	p.type=PROPERTY_TYPE_COLOUR;
 	p.helpText=TRANS("Colour for ruler and ticks");
 	propertyList.addProperty(p,curGroup);
-
+	propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 }
 
 bool AnnotateFilter::setProperty(  unsigned int key,
@@ -916,23 +909,8 @@ bool AnnotateFilter::setProperty(  unsigned int key,
 	{
 		case KEY_ENABLE:
 		{
-			bool tmpV;
-			
-			if( value == "1")
-				tmpV=true;
-			else if(value == "0")
-				tmpV=false;
-			else
-			{
-				ASSERT(false);
+			if(!applyPropertyNow(active,value,needUpdate))
 				return false;
-			}
-
-			if(tmpV!=active)
-			{
-				active=tmpV;
-				needUpdate=true;
-			}
 			break;
 		}
 		case KEY_MODE:
@@ -1031,109 +1009,53 @@ bool AnnotateFilter::setProperty(  unsigned int key,
 		}
 		case KEY_POSITION:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(position,value,needUpdate))
 				return false;
-
-			if(!(position == newPt))
-			{
-				position=newPt;
-				needUpdate=true;
-			}
-
 			break;	
 		}
 		case KEY_TARGET:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(target,value,needUpdate))
 				return false;
-
-			if(!(target== newPt))
-			{
-				target=newPt;
-				needUpdate=true;
-			}
-
 			break;	
 		}
 		case KEY_ANGLE_POS_ZERO:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(anglePos[0],value,needUpdate))
 				return false;
-
-			if(!(anglePos[0]== newPt))
-			{
-				anglePos[0]=newPt;
-				needUpdate=true;
-			}
 			break;
 		}
 		case KEY_ANGLE_POS_ONE:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(anglePos[1],value,needUpdate))
 				return false;
-
-			if(!(anglePos[1]== newPt))
-			{
-				anglePos[1]=newPt;
-				needUpdate=true;
-			}
 			break;
 		}
 		case KEY_ANGLE_POS_TWO:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(anglePos[2],value,needUpdate))
 				return false;
-
-			if(!(anglePos[2]== newPt))
-			{
-				anglePos[2]=newPt;
-				needUpdate=true;
-			}
 			break;
 		}
 		case KEY_ARROW_SIZE:
 		{
-			float tmp;
-			if(stream_cast(tmp,value))
+			if(!applyPropertyNow(annotateSize,value,needUpdate))
 				return false;
-
-			if(tmp!=annotateSize)
-			{
-				annotateSize=tmp;
-				needUpdate=true;
-			}
-		
 			break;	
 		}
 		case KEY_ANNOTATE_TEXT:
 		{
-			if(value!=annotateText)
-			{
-				needUpdate=true;
-				annotateText=value;
-			}
-
+			if(!applyPropertyNow(annotateText,value,needUpdate))
+				return false;
 			break;
 		}
 		case KEY_COLOUR:
 		{
-			unsigned char newR,newG,newB,newA;
-
-			parseColString(value,newR,newG,newB,newA);
-
-			if(newB != b || newR != r ||
-				newG !=g || newA != a)
+			ColourRGBA tmpRgba;
+			tmpRgba.parse(value);
+			if(tmpRgba != rgba)
 			{
-				r=(float)newR/255.0;
-				g=(float)newG/255.0;
-				b=(float)newB/255.0;
-				a=(float)newA/255.0;
-
+				rgba = tmpRgba.toRGBAf();
 				needUpdate=true;
 			}
 			else
@@ -1155,41 +1077,20 @@ bool AnnotateFilter::setProperty(  unsigned int key,
 		}
 		case KEY_REFLEXIVE:
 		{
-			bool tmp;
-			tmp=(value=="1");
-
-			if(tmp==reflexAngle)
+			if(!applyPropertyNow(reflexAngle,value,needUpdate))
 				return false;
-			
-			reflexAngle=tmp;
-
-			needUpdate=true;
 			break;
 		}
 		case KEY_SPHERE_ANGLE_SIZE:
 		{
-			float tmp;
-			stream_cast(tmp,value);
-
-			if(tmp == sphereMarkerSize)
+			if(!applyPropertyNow(sphereMarkerSize,value,needUpdate))
 				return false;
-
-			sphereMarkerSize=tmp;
-			needUpdate=true;
-
 			break;
 		}
 		case KEY_ANGLE_TEXT_VISIBLE:
 		{
-			bool tmp;
-			tmp=(value=="1");
-			
-			if(tmp == showAngleText)
+			if(!applyPropertyNow(showAngleText,value,needUpdate))
 				return false;
-
-			showAngleText=tmp;
-			needUpdate=true;
-
 			break;
 		}
 
@@ -1230,60 +1131,26 @@ bool AnnotateFilter::setProperty(  unsigned int key,
 
 		case KEY_LINEAR_FONTSIZE:
 		{
-			unsigned int tmp;
-			stream_cast(tmp,value);
-
-			if(tmp == fontSizeLinearMeasure)
+			if(!applyPropertyNow(fontSizeLinearMeasure,value,needUpdate))
 				return false;
-
-			fontSizeLinearMeasure=tmp;
-			needUpdate=true;
 			break;
 		}
 		case KEY_LINEAR_FIXED_TICKS:
 		{
-			bool tmpTicks;
-
-			if(value == "0")
-				tmpTicks=false;
-			else if(value =="1")
-				tmpTicks=true;
-			else
-				return false;
-
-			if(tmpTicks == linearFixedTicks)
+			if(!applyPropertyNow(linearFixedTicks,value,needUpdate))
 				return false;
-
-			needUpdate=true;
-			linearFixedTicks=tmpTicks;
 			break;
-
 		}
 		case KEY_LINEAR_NUMTICKS:
 		{
-			unsigned int tmp;
-			if(stream_cast(tmp,value))
+			if(!applyPropertyNow(linearMeasureTicks,value,needUpdate))
 				return false;
-
-			if(tmp == linearMeasureTicks)
-				return false;
-
-			linearMeasureTicks=tmp;
-			needUpdate=true;
-
 			break;
 		}
 		case KEY_LINEAR_TICKSPACING:
 		{
-			float tmp;
-			stream_cast(tmp,value);
-
-			if(tmp == linearMeasureSpacing)
+			if(!applyPropertyNow(linearMeasureSpacing,value,needUpdate))
 				return false;
-
-			linearMeasureSpacing=tmp;
-			needUpdate=true;
-
 			break;
 		}
 		case KEY_LINESIZE:
@@ -1339,10 +1206,7 @@ bool AnnotateFilter::writeState(std::ostream &f,unsigned int format, unsigned in
 			//DEPRECATE: rename this element. It has been repurposed.
 			f << tabs(depth+1) << "<sphereanglesize value=\""<<sphereMarkerSize<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<linesize value=\""<<lineSize<< "\"/>"  << endl;
-			std::string colourString;
-			genColString((unsigned char)(r*255),(unsigned char)(g*255),
-				(unsigned char)(b*255),(unsigned char)(a*255),colourString);
-			f << tabs(depth+1) << "<colour value=\""<<colourString<< "\"/>"  << endl;
+			f << tabs(depth+1) << "<colour value=\""<< rgba.toColourRGBA().rgbaString() << "\"/>"  << endl;
 
 			f << tabs(depth+1) << "<active value=\""<<(active? "1" : "0")<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<showangletext value=\""<<(showAngleText ? "1" : "0")<< "\"/>"  << endl;
@@ -1462,41 +1326,36 @@ bool AnnotateFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFile
 		return false;
 	if(lineSize<0.0f)
 		return false;
+
+	//TODO: we have a standardised parsexmlColour func, use it
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"colour","value"))
 		return false;
 	
-	unsigned char rc,gc,bc,ac;
-	if(!parseColString(tmpStr,rc,gc,bc,ac))
+	ColourRGBA tmpRgba;
+
+	if(!tmpRgba.parse(tmpStr))
 		return false;
-	r=(float)(rc)/255.0f;
-	g=(float)(gc)/255.0f;
-	b=(float)(bc)/255.0f;
-	a=(float)(ac)/255.0f;
 
+	rgba=tmpRgba.toRGBAf();
 
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"active","value"))
 		return false;
 
-	if(!(tmpStr=="0" || tmpStr=="1"))
+	if(!boolStrDec(tmpStr,active))
 		return false;
 
-	active = (tmpStr=="1");
-
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"showangletext","value"))
 		return false;
 
-	if(!(tmpStr=="0" || tmpStr=="1"))
+	if(!boolStrDec(tmpStr,showAngleText))
 		return false;
 
-	showAngleText = (tmpStr=="1");
-
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"reflexangle","value"))
 		return false;
 
-	if(!(tmpStr=="0" || tmpStr=="1"))
+	if(!boolStrDec(tmpStr,reflexAngle))
 		return false;
 
-	reflexAngle = (tmpStr=="1");
 
 	if(!XMLGetNextElemAttrib(nodePtr,angleFormatPreDecimal,"angleformat","predecimal"))
 		return false;
diff --git a/src/backend/filters/annotation.h b/src/backend/filters/annotation.h
index dbed5dc..ce99959 100644
--- a/src/backend/filters/annotation.h
+++ b/src/backend/filters/annotation.h
@@ -48,7 +48,7 @@ class AnnotateFilter : public Filter
 		float textSize,annotateSize,sphereMarkerSize,lineSize;
 
 		//Annotation colour
-		float r,g,b,a;
+		ColourRGBAf rgba;
 
 		//Disable/enable annotation
 		bool active;
diff --git a/src/backend/filters/boundingBox.cpp b/src/backend/filters/boundingBox.cpp
index e729479..4180090 100644
--- a/src/backend/filters/boundingBox.cpp
+++ b/src/backend/filters/boundingBox.cpp
@@ -62,8 +62,7 @@ const char *BOUND_STYLE[] =
 
 
 BoundingBoxFilter::BoundingBoxFilter() : isVisible(true), boundStyle(BOUND_STYLE_TICKS),
-	fixedNumTicks(true), fontSize(5), rLine(0.0f), gLine(0.0f), bLine(1.0f), aLine(1.0f),
-	lineWidth(2.0f), threeDText(true)
+	fixedNumTicks(true), fontSize(5), lineColour(0,0,1.0f), lineWidth(2.0f), threeDText(true)
 {
 	for(unsigned int ui=0;ui<3;ui++)
 	{
@@ -71,7 +70,6 @@ BoundingBoxFilter::BoundingBoxFilter() : isVisible(true), boundStyle(BOUND_STYLE
 		tickSpacing[ui]=5.0f;
 	}
 
-
 	cacheOK=false;
 	cache=false; 
 }
@@ -90,10 +88,6 @@ Filter *BoundingBoxFilter::cloneUncached() const
 	p->boundStyle=boundStyle;
 
 
-	p->rLine=rLine;
-	p->gLine=gLine;
-	p->bLine=bLine;
-	p->aLine=aLine;
 	p->threeDText=threeDText;	
 
 	p->lineWidth=lineWidth;
@@ -119,7 +113,7 @@ void BoundingBoxFilter::drawTicks(const BoundCube &bTotal, DrawStreamData *d) co
 	//Add the rectangle drawable
 	DrawRectPrism *dP = new DrawRectPrism;
 	dP->setAxisAligned(bTotal);
-	dP->setColour(rLine,gLine,bLine,aLine);
+	dP->setColour(lineColour.r(),lineColour.g(),lineColour.b(),lineColour.a());
 	dP->setLineWidth(lineWidth);
 	d->drawables.push_back(dP);
 
@@ -185,7 +179,8 @@ void BoundingBoxFilter::drawTicks(const BoundCube &bTotal, DrawStreamData *d) co
 			dV->setDrawArrow(false);
 			dV->setOrigin(tickPosition);
 			dV->setVector(tickVector);
-			dV->setColour(rLine,gLine,bLine,aLine);
+			dV->setColour(lineColour.r(),lineColour.g(),
+					lineColour.b(), lineColour.a());
 
 			d->drawables.push_back(dV);
 	
@@ -206,7 +201,8 @@ void BoundingBoxFilter::drawTicks(const BoundCube &bTotal, DrawStreamData *d) co
 				dT->setString(buffer);
 				dT->setSize(fontSize);
 				
-				dT->setColour(rLine,gLine,bLine,aLine);
+				dT->setColour(lineColour.r(),lineColour.g(),
+						lineColour.b(),lineColour.a());
 				dT->setOrigin(tickPosition + tickVector*2);	
 				dT->setUp(Point3D(0,0,1));	
 				dT->setTextDir(textVector);
@@ -226,7 +222,8 @@ void BoundingBoxFilter::drawTicks(const BoundCube &bTotal, DrawStreamData *d) co
 	//Handle "0" text value
 	dT->setString("0");
 	
-	dT->setColour(rLine,gLine,bLine,aLine);
+	dT->setColour(lineColour.r(),lineColour.g(),
+		lineColour.b(),lineColour.a());
 	dT->setSize(fontSize);
 	dT->setOrigin(tickOrigin+ Point3D(-1,-1,-1));
 	dT->setAlignment(DRAWTEXT_ALIGN_RIGHT);
@@ -241,7 +238,8 @@ void BoundingBoxFilter::drawDimension(const BoundCube &bTotal, DrawStreamData *d
 	//Add the rectangle drawable
 	DrawRectPrism *dP = new DrawRectPrism;
 	dP->setAxisAligned(bTotal);
-	dP->setColour(rLine,gLine,bLine,aLine);
+	dP->setColour(lineColour.r(),lineColour.g(),
+				lineColour.b(),lineColour.a());
 	dP->setLineWidth(lineWidth);
 	d->drawables.push_back(dP);
 
@@ -288,7 +286,8 @@ void BoundingBoxFilter::drawDimension(const BoundCube &bTotal, DrawStreamData *d
 		DrawVector *dV;
 		dV= new DrawVector;
 
-		dV->setColour(rLine,gLine,bLine,aLine);	
+		dV->setColour(lineColour.r(),lineColour.g(),
+				lineColour.b(),lineColour.a());	
 		dV->wantsLight=true;
 		
 		dV->setArrowSize(maxLen*ARROW_SCALE_FACTOR);
@@ -325,7 +324,8 @@ void BoundingBoxFilter::drawDimension(const BoundCube &bTotal, DrawStreamData *d
 		dT->setString(buffer);
 		dT->setSize(fontSize);
 
-		dT->setColour(rLine,gLine,bLine,aLine);
+		dT->setColour(lineColour.r(),lineColour.g(),
+				lineColour.b(),lineColour.a());
 		dT->setOrigin(centrePt[ui]);	
 		switch(ui)
 		{
@@ -488,7 +488,8 @@ unsigned int BoundingBoxFilter::refresh(const std::vector<const FilterStreamData
 				//Add the rectangle drawable
 				DrawRectPrism *dP = new DrawRectPrism;
 				dP->setAxisAligned(bTotal);
-				dP->setColour(rLine,gLine,bLine,aLine);
+				dP->setColour(lineColour.r(),lineColour.g(),
+						lineColour.b(),lineColour.a());
 				dP->setLineWidth(lineWidth);
 				d->drawables.push_back(dP);
 				break;
@@ -540,11 +541,12 @@ void BoundingBoxFilter::getProperties(FilterPropGroup &propertyList) const
 		p.helpText=TRANS("Box display mode");
 		p.key=KEY_STYLE;
 		propertyList.addProperty(p,curGroup);
+		propertyList.setGroupTitle(curGroup,TRANS("Display mode"));
+		curGroup++;
 
 		
 		if(boundStyle == BOUND_STYLE_TICKS)
 		{
-			curGroup++;
 
 			//Properties are X Y and Z counts on ticks
 			stream_cast(tmpStr,fixedNumTicks);
@@ -612,14 +614,11 @@ void BoundingBoxFilter::getProperties(FilterPropGroup &propertyList) const
 
 		}
 
-		//Box Line properties 
-		curGroup++;
 
 		//Colour
-		genColString((unsigned char)(rLine*255.0),(unsigned char)(gLine*255.0),
-			(unsigned char)(bLine*255),(unsigned char)(aLine*255),tmpStr);
+
 		p.name=TRANS("Box Colour");
-		p.data= tmpStr;
+		p.data= lineColour.toColourRGBA().rgbString();
 		p.key=KEY_LINECOLOUR;
 		p.type=PROPERTY_TYPE_COLOUR;
 		p.helpText=TRANS("Colour of the bounding box");
@@ -645,8 +644,8 @@ void BoundingBoxFilter::getProperties(FilterPropGroup &propertyList) const
 			p.helpText=TRANS("Relative size for text");
 			propertyList.addProperty(p,curGroup);
 		}
-		propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 	}
+	propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 }
 
 bool BoundingBoxFilter::setProperty(  unsigned int key,
@@ -658,18 +657,8 @@ bool BoundingBoxFilter::setProperty(  unsigned int key,
 	{
 		case KEY_VISIBLE:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(isVisible,value,needUpdate))
 				return false;
-
-			bool lastVal=isVisible;
-			isVisible=(stripped == "1");
-			
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=isVisible)
-				needUpdate=true;
 			break;
 		}	
 		case KEY_STYLE:
@@ -700,18 +689,8 @@ bool BoundingBoxFilter::setProperty(  unsigned int key,
 		}	
 		case KEY_FIXEDOUT:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(fixedNumTicks,value,needUpdate))
 				return false;
-
-			bool lastVal=fixedNumTicks;
-			fixedNumTicks=(stripped=="1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=fixedNumTicks)
-				needUpdate=true;
 			break;
 		}	
 		case KEY_COUNT_X:
@@ -733,18 +712,15 @@ bool BoundingBoxFilter::setProperty(  unsigned int key,
 		}
 		case KEY_LINECOLOUR:
 		{
-			unsigned char newR,newG,newB,newA;
+			ColourRGBA newLineColour;
+			if(!newLineColour.parse(value))
+				return false;
 
-			parseColString(value,newR,newG,newB,newA);
 
-			if(newB != bLine || newR != rLine ||
-				newG !=gLine || newA != aLine)
+			if(lineColour.toColourRGBA() != newLineColour) 
 				needUpdate=true;
+			lineColour=newLineColour.toRGBAf();
 
-			rLine=newR/255.0;
-			gLine=newG/255.0;
-			bLine=newB/255.0;
-			aLine=newA/255.0;
 			needUpdate=true;
 			break;
 		}
@@ -779,12 +755,8 @@ bool BoundingBoxFilter::setProperty(  unsigned int key,
 		}
 		case KEY_FONTSIZE:
 		{
-			unsigned int newCount;
-			if(stream_cast(newCount,value))
+			if(!applyPropertyNow(fontSize,value,needUpdate))
 				return false;
-
-			fontSize=newCount;
-			needUpdate=true;
 			break;
 		}
 		default:
@@ -824,8 +796,8 @@ bool BoundingBoxFilter::writeState(std::ostream &f,unsigned int format, unsigned
 				<< tickSpacing[1] << "\" z=\""<< tickSpacing[2] <<"\"/>"  << endl;
 			f << tabs(depth+1) << "<linewidth value=\"" << lineWidth << "\"/>"<<endl;
 			f << tabs(depth+1) << "<fontsize value=\"" << fontSize << "\"/>"<<endl;
-			f << tabs(depth+1) << "<colour r=\"" <<  rLine<< "\" g=\"" << gLine << "\" b=\"" <<bLine  
-								<< "\" a=\"" << aLine << "\"/>" <<endl;
+			f << tabs(depth+1) << "<colour r=\"" <<  lineColour.r()<< "\" g=\"" << lineColour.g() << "\" b=\"" <<lineColour.b()  
+								<< "\" a=\"" << lineColour.a() << "\"/>" <<endl;
 			f << tabs(depth) << "</" <<trueName()<< ">" << endl;
 			break;
 		}
@@ -862,11 +834,7 @@ bool BoundingBoxFilter::readState(xmlNodePtr &nodePtr, const std::string &stateF
 		return false;
 	tmpStr=(char *)xmlString;
 
-	if(tmpStr == "0")
-		isVisible=false;
-	else if(tmpStr == "1")
-		isVisible=true;
-	else
+	if(!boolStrDec(tmpStr,isVisible))
 		return false;
 
 	xmlFree(xmlString);
@@ -899,11 +867,7 @@ bool BoundingBoxFilter::readState(xmlNodePtr &nodePtr, const std::string &stateF
 		return false;
 	tmpStr=(char *)xmlString;
 
-	if(tmpStr == "0")
-		fixedNumTicks=false;
-	else if(tmpStr == "1")
-		fixedNumTicks=true;
-	else
+	if(!boolStrDec(tmpStr,fixedNumTicks))
 		return false;
 
 	xmlFree(xmlString);
@@ -1029,8 +993,10 @@ bool BoundingBoxFilter::readState(xmlNodePtr &nodePtr, const std::string &stateF
 	if(XMLHelpFwdToElem(nodePtr,"colour"))
 		return false;
 
-	if(!parseXMLColour(nodePtr,rLine,gLine,bLine,aLine))
+	ColourRGBAf tmpCol;
+	if(!parseXMLColour(nodePtr,tmpCol))
 		return false;
+	lineColour=tmpCol;
 	//====
 
 	return true;	
diff --git a/src/backend/filters/boundingBox.h b/src/backend/filters/boundingBox.h
index 3eece80..d70f13e 100644
--- a/src/backend/filters/boundingBox.h
+++ b/src/backend/filters/boundingBox.h
@@ -40,7 +40,7 @@ class BoundingBoxFilter : public Filter
 		unsigned int fontSize;
 
 		//!Line colour
-		float rLine,gLine,bLine,aLine;
+		ColourRGBAf lineColour;
 		//!Line width 
 		float lineWidth;
 		//!Use 3D text?
diff --git a/src/backend/filters/clusterAnalysis.cpp b/src/backend/filters/clusterAnalysis.cpp
index a33c6ef..476056c 100644
--- a/src/backend/filters/clusterAnalysis.cpp
+++ b/src/backend/filters/clusterAnalysis.cpp
@@ -24,9 +24,9 @@
 
 #include <queue>
 
-#include <gsl/gsl_linalg.h>
 
 #include "algorithms/K3DTree-mk2.h"
+#include "backend/plot.h"
 
 
 enum
@@ -44,6 +44,7 @@ enum
 	KEY_WANT_LOGSIZEDIST,
 	KEY_WANT_COMPOSITIONDIST,
 	KEY_WANT_CLUSTERMORPHOLOGY,
+	KEY_WANT_CLUSTERID,
 	KEY_NORMALISE_COMPOSITION,
 	KEY_CROP_SIZE,
 	KEY_SIZE_COUNT_BULK,
@@ -57,7 +58,8 @@ enum
 {
 	ABORT_ERR=1,
 	NOCORE_ERR,
-	NOBULK_ERR
+	NOBULK_ERR,
+	CLUSTER_ERR_ENUM_END
 };
 
 enum 
@@ -171,7 +173,7 @@ void makeCompositionTable(const IonStreamData *i ,const RangeFile *r,
 // provide the transformation vectors, so singular values only provide
 // scalar information separate from the original input basis. The first value
 // does *not* correspond to the "x" direction of your input, for example.
-void computeSingularValues(float *data, size_t numRows, size_t numCols,
+/*void computeSingularValues(float *data, size_t numRows, size_t numCols,
 				vector<float> &resultValues, vector<Point3D> &resultVectors)
 {
 
@@ -225,7 +227,7 @@ void computeSingularValues(float *data, size_t numRows, size_t numCols,
 	gsl_matrix_free(newSpace);
 	gsl_matrix_free(m);
 }
-
+*/
 
 void ClusterAnalysisFilter::checkIonEnabled(bool &core, bool &bulk) const
 {
@@ -263,7 +265,7 @@ void ClusterAnalysisFilter::buildRangeEnabledMap(const RangeStreamData *r,
 ClusterAnalysisFilter::ClusterAnalysisFilter() : algorithm(CLUSTER_LINK_ERODE),
 	enableCoreClassify(false), coreDist(0.0f), coreKNN(1), linkDist(0.5f), 
 	enableBulkLink(false), bulkLink(1), enableErosion(false), dErosion(0.25),
-	wantCropSize(false), nMin(0),nMax(std::numeric_limits<size_t>::max()),
+	wantClusterID(false), wantCropSize(false), nMin(0),nMax(std::numeric_limits<size_t>::max()),
 	wantClusterSizeDist(false),logClusterSize(false),
 	wantClusterComposition(true),normaliseComposition(true),
 	wantClusterMorphology(false), haveRangeParent(false)
@@ -301,6 +303,7 @@ Filter *ClusterAnalysisFilter::cloneUncached() const
 	
 	p->wantClusterComposition=wantClusterComposition;
 	p->normaliseComposition = normaliseComposition;
+	p->wantClusterMorphology= wantClusterMorphology;
 
 	p->haveRangeParent=false; //lets assume not, and this will be reset at ::initFilter time
 
@@ -441,6 +444,9 @@ void ClusterAnalysisFilter::initFilter(const std::vector<const FilterStreamData
 unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStreamData *> &dataIn,
 	std::vector<const FilterStreamData *> &getOut, ProgressData &progress, bool (*callback)(bool))
 {
+	// - cluster ID alters the mass, so we can't use this analysis
+	// at the same time
+	ASSERT(!(wantClusterID && wantClusterComposition));
 	//By default, copy inputs to output, unless it is an ion or range stream type.
 	for(unsigned int ui=0;ui<dataIn.size();ui++)
 	{
@@ -566,7 +572,7 @@ unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStream
 		return 0;
 
 	//we can't have bulk, but no core...
-	ASSERT(!(haveBulk && !haveCore));
+ASSERT(!(haveBulk && !haveCore));
 
 	//-------------
 
@@ -632,6 +638,7 @@ unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStream
 		}
 	}
 
+/*
 	if(wantClusterMorphology)
 	{
 		//Compute the singular values for each cluster
@@ -680,7 +687,7 @@ unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStream
 		p->parent=this;
 
 		p->plotMode=PLOT_MODE_1D;
-		p->plotStyle=PLOT_TRACE_POINTS;
+		p->plotStyle=PLOT_LINE_POINTS;
 		p->dataLabel=TRANS("Morphology Plot");
 		p->xLabel=TRANS("\\lambda_1:\\lambda_2 ratio");
 		p->yLabel=TRANS("\\lambda_2:\\lambda_3 ratio");
@@ -770,7 +777,7 @@ unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStream
 
 		getOut.push_back(singularVectorDraw);
 	}
-
+*/
 	//Construct the output clustered data.
 	IonStreamData *i = new IonStreamData;
 	i->parent =this;	
@@ -793,6 +800,26 @@ unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStream
 		totalSize+=clusteredCore[ui].size();
 	i->data.resize(totalSize);
 	
+	if(wantClusterID)
+	{
+
+		#pragma omp parallel
+		{
+		#pragma omp for
+		for(size_t ui=0;ui<clusteredCore.size();ui++)
+		{
+			for(size_t uj=0;uj<clusteredCore[ui].size();uj++)
+				clusteredCore[ui][uj].setMassToCharge(ui);
+		}
+	
+		#pragma omp for
+		for(size_t ui=0;ui<clusteredBulk.size();ui++)
+		{
+			for(size_t uj=0;uj<clusteredBulk[ui].size();uj++)
+				clusteredBulk[ui][uj].setMassToCharge(ui);
+		}
+		}
+	}
 
 	//copy across the core and bulk ions
 	//into the output
@@ -805,6 +832,7 @@ unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStream
 			copyPos++;
 		}
 	}
+
 	clusteredCore.clear();
 
 	for(size_t ui=0;ui<clusteredBulk.size();ui++)
@@ -823,19 +851,12 @@ unsigned int ClusterAnalysisFilter::refresh(const std::vector<const FilterStream
 	i->b=0.5f;	
 	i->a=1.0f;	
 
-	//Save the ion stream data.
-	if(cache)
-	{
-		i->cached=1;
-		filterOutputs.push_back(i);
-		cacheOK=true;
-	}
-	else
-		i->cached=0;
+	cacheAsNeeded(i);
 
 	getOut.push_back(i);
 
 
+	//Run cluster composition if it is wanted.
 	if(wantClusterComposition)
 	{
 		ASSERT(r);
@@ -892,23 +913,28 @@ void ClusterAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 {
 	FilterProperty p;
 	size_t curGroup=0;
-
 	string tmpStr;
-	vector<pair<unsigned int,string> > choices;
-	tmpStr=TRANS("Core Link + Erode");
-	choices.push_back(make_pair((unsigned int)CLUSTER_LINK_ERODE,tmpStr));
-	
-	tmpStr= choiceString(choices,algorithm);
-	p.name=TRANS("Algorithm");
-	p.data=tmpStr;
-	choices.clear();
-	p.type=PROPERTY_TYPE_CHOICE;
-	p.helpText=TRANS("Cluster algorithm mode");
-	p.key=KEY_CLUSTERANALYSIS_ALGORITHM;
-	propertyList.addProperty(p,curGroup);
-	
-	curGroup++;
-	
+
+	//Don't show options if there is only one algorithm
+	if(CLUSTER_ALGORITHM_ENUM_END > 1)
+	{
+		vector<pair<unsigned int,string> > choices;
+		tmpStr=TRANS("Core Link + Erode");
+		choices.push_back(make_pair((unsigned int)CLUSTER_LINK_ERODE,tmpStr));
+		
+		tmpStr= choiceString(choices,algorithm);
+		p.name=TRANS("Algorithm");
+		p.data=tmpStr;
+		choices.clear();
+		p.type=PROPERTY_TYPE_CHOICE;
+		p.helpText=TRANS("Cluster algorithm mode");
+		p.key=KEY_CLUSTERANALYSIS_ALGORITHM;
+		propertyList.addProperty(p,curGroup);
+		
+		propertyList.setGroupTitle(curGroup,TRANS("Algorithm"));
+		curGroup++;
+	}
+
 	if(algorithm == CLUSTER_LINK_ERODE)
 	
 	{
@@ -1041,26 +1067,38 @@ void ClusterAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 	p.key=KEY_WANT_CLUSTERMORPHOLOGY;
 	propertyList.addProperty(p,curGroup);
 	*/
-	tmpStr=boolStrEnc(wantClusterComposition);
-	p.name=TRANS("Chemistry Dist.");
+
+
+	tmpStr=boolStrEnc(wantClusterID);
+	p.name=TRANS("Cluster Id");
 	p.data=tmpStr;
 	p.type=PROPERTY_TYPE_BOOL;
-	p.helpText=TRANS("Create a plot showing chemistry for each cluster size");
-	p.key=KEY_WANT_COMPOSITIONDIST;
+	p.helpText=TRANS("Assign cluster output a unique per-cluster value (id).");
+	p.key=KEY_WANT_CLUSTERID;
 	propertyList.addProperty(p,curGroup);
-	
-	if(wantClusterComposition)
-	{	
-		tmpStr=boolStrEnc(normaliseComposition);
-		p.name=TRANS("Normalise");
+
+	if(!wantClusterID)
+	{
+		tmpStr=boolStrEnc(wantClusterComposition);
+		p.name=TRANS("Chemistry Dist.");
 		p.data=tmpStr;
 		p.type=PROPERTY_TYPE_BOOL;
-		p.helpText=TRANS("Convert cluster counts to composition");
-		p.key=KEY_NORMALISE_COMPOSITION;
+		p.helpText=TRANS("Create a plot showing chemistry for each cluster size");
+		p.key=KEY_WANT_COMPOSITIONDIST;
 		propertyList.addProperty(p,curGroup);
+		
+		if(wantClusterComposition)
+		{	
+			tmpStr=boolStrEnc(normaliseComposition);
+			p.name=TRANS("Normalise");
+			p.data=tmpStr;
+			p.type=PROPERTY_TYPE_BOOL;
+			p.helpText=TRANS("Convert cluster counts to composition");
+			p.key=KEY_NORMALISE_COMPOSITION;
+			propertyList.addProperty(p,curGroup);
+		}
 	}
 
-
 	propertyList.setGroupTitle(curGroup,TRANS("Postprocess"));
 	
 	curGroup++;
@@ -1133,18 +1171,8 @@ bool ClusterAnalysisFilter::setProperty(unsigned int key,
 		}
 		case KEY_CORECLASSIFY_ENABLE:
 		{
-			string stripped=stripWhite(value);
-		
-			bool newVal;
-			if(!boolStrDec(stripped,newVal))
+			if(!applyPropertyNow(enableCoreClassify,value,needUpdate))
 				return false;
-
-			if(newVal!=enableCoreClassify)
-			{
-				enableCoreClassify=newVal;
-				clearCache(); 
-				needUpdate=true;
-			}
 			break;
 		}
 		case KEY_CORECLASSIFYDIST:
@@ -1194,18 +1222,8 @@ bool ClusterAnalysisFilter::setProperty(unsigned int key,
 		}	
 		case KEY_BULKLINK_ENABLE:
 		{
-			string stripped=stripWhite(value);
-		
-			bool newVal;
-			if(!boolStrDec(stripped,newVal))
+			if(!applyPropertyNow(enableBulkLink,value,needUpdate))
 				return false;
-
-			if(newVal!=enableBulkLink)
-			{
-				enableBulkLink=newVal;
-				clearCache(); 
-				needUpdate=true;
-			}
 			break;
 		}
 		case KEY_BULKLINK:
@@ -1225,18 +1243,8 @@ bool ClusterAnalysisFilter::setProperty(unsigned int key,
 		}	
 		case KEY_ERODE_ENABLE:
 		{
-			string stripped=stripWhite(value);
-		
-			bool newVal;
-			if(!boolStrDec(stripped,newVal))
+			if(!applyPropertyNow(enableErosion,value,needUpdate))
 				return false;
-
-			if(newVal!=enableErosion)
-			{
-				enableErosion=newVal;
-				clearCache(); 
-				needUpdate=true;
-			}
 			break;
 		}
 		case KEY_ERODEDIST:
@@ -1418,27 +1426,17 @@ bool ClusterAnalysisFilter::setProperty(unsigned int key,
 				needUpdate=true;
 				clearCache();
 			}
+
+			//composition analysis is mutually
+			// exclsive with ID
+			wantClusterID=false;
 			
 			break;
 		}
 		case KEY_CROP_SIZE:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(wantCropSize,value,needUpdate))
 				return false;
-
-			bool lastVal=wantCropSize;
-			wantCropSize=(stripped == "1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=wantCropSize)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			
 			break;
 		}
 		case KEY_CROP_NMIN:
@@ -1476,21 +1474,17 @@ bool ClusterAnalysisFilter::setProperty(unsigned int key,
 		}	
 		case KEY_WANT_CLUSTERMORPHOLOGY:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(wantClusterMorphology,value,needUpdate))
+				return false;
+			break;
+		}
+		case KEY_WANT_CLUSTERID:
+		{
+			if(!applyPropertyNow(wantClusterID,value,needUpdate))
 				return false;
 
-			bool lastVal=wantClusterMorphology;
-			wantClusterMorphology=(stripped=="1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=wantClusterMorphology)
-			{
-				needUpdate=true;
-				clearCache();
-			}
+			//composition & id are mutually exclusive
+			wantClusterComposition=false;
 			
 			break;
 		}
@@ -1575,17 +1569,18 @@ bool ClusterAnalysisFilter::writeState(std::ostream &f,unsigned int format,
 			f << tabs(depth+1) << "<derosion value=\""<<dErosion<< "\" enabled=\"" << boolStrEnc(enableErosion) << "\"/>"  << endl;
 			
 			//Cropping control
-			f << tabs(depth+1) << "<wantcropsize value=\""<<wantCropSize<< "\"/>"  << endl;
+			f << tabs(depth+1) << "<wantcropsize value=\""<<boolStrEnc(wantCropSize)<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<nmin value=\""<<nMin<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<nmax value=\""<<nMax<< "\"/>"  << endl;
 			
 			//Postprocessing
-			f << tabs(depth+1) << "<wantclustersizedist value=\""<<wantClusterSizeDist<< "\" logarithmic=\"" << 
+			f << tabs(depth+1) << "<wantclustersizedist value=\""<<boolStrEnc(wantClusterSizeDist)<< "\" logarithmic=\"" << 
 					logClusterSize << "\"/>"  << endl;
-			f << tabs(depth+1) << "<wantclustercomposition value=\"" <<wantClusterComposition<< "\" normalise=\"" << 
+			f << tabs(depth+1) << "<wantclustercomposition value=\"" <<boolStrEnc(wantClusterComposition)<< "\" normalise=\"" << 
 					normaliseComposition<< "\"/>"  << endl;
 			
-			f << tabs(depth+1) << "<wantclustermorphology value=\"" <<wantClusterMorphology	<< "\"/>"  << endl;
+			f << tabs(depth+1) << "<wantclustermorphology value=\"" <<boolStrEnc(wantClusterMorphology)	<< "\"/>"  << endl;
+			f << tabs(depth+1) << "<wantclusterid value=\"" <<boolStrEnc(wantClusterID)<< "\"/>"  << endl;
 
 
 			f << tabs(depth+1) << "<enabledions>"  << endl;
@@ -1721,6 +1716,17 @@ bool ClusterAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &pa
 	nodePtr=tmpPtr;
 	if(!XMLGetNextElemAttrib(nodePtr,wantClusterMorphology,"wantclustermorphology","value"))
 		return false;
+	
+	nodePtr=tmpPtr;
+	if(!XMLGetNextElemAttrib(nodePtr,wantClusterID,"wantclustermorphology","value"))
+	{
+		//COMPAT_BREAK: compat fix, 0.0.16.
+		wantClusterID=false;
+	}
+	else
+	{
+		wantClusterComposition=false;
+	}
 	//===
 
 
@@ -1797,17 +1803,15 @@ unsigned int ClusterAnalysisFilter::getRefreshUseMask() const
 
 std::string ClusterAnalysisFilter::getErrString(unsigned int i) const
 {
-	switch(i)
-	{
-		case ABORT_ERR:
-			return std::string(TRANS("Clustering aborted"));
-		case NOCORE_ERR:
-			return std::string(TRANS("No core ions for cluster"));
-		case NOBULK_ERR:
-			return std::string(TRANS("No bulk ions for cluster"));
-		default:
-			ASSERT(false);
-	}
+	const char *errStrs[] = {"",
+		"Clustering aborted",
+		"No core ions for cluster",
+		"No bulk ions for cluster" };
+
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == CLUSTER_ERR_ENUM_END );
+	ASSERT(i < CLUSTER_ERR_ENUM_END);
+
+	return errStrs[i];
 }
 
 void ClusterAnalysisFilter::setPropFromBinding(const SelectionBinding &b)
@@ -2672,7 +2676,7 @@ PlotStreamData* ClusterAnalysisFilter::clusterSizeDistribution(const vector<vect
 	dist->dataLabel=SIZE_DIST_DATALABEL;
 	dist->logarithmic=logClusterSize;
 
-	dist->plotStyle=PLOT_TRACE_STEM;
+	dist->plotStyle=PLOT_LINE_STEM;
 	dist->plotMode=PLOT_MODE_1D;
 	dist->xyData.resize(countMap.size());
 	std::copy(countMap.begin(),countMap.end(),dist->xyData.begin());
@@ -2879,7 +2883,7 @@ void ClusterAnalysisFilter::genCompositionVersusSize(const vector<vector<IonHit>
 		p->dataLabel=string(CHEM_DIST_DATALABEL) + string(":") + rng->getName(ui);
 		p->logarithmic=logClusterSize && !normaliseComposition;
 
-		p->plotStyle=PLOT_TRACE_STEM;
+		p->plotStyle=PLOT_LINE_STEM;
 
 		p->xyData.resize(countMap.size());
 
@@ -2909,6 +2913,7 @@ void ClusterAnalysisFilter::genCompositionVersusSize(const vector<vector<IonHit>
 
 }
 
+/*
 void ClusterAnalysisFilter::getSingularValues(const vector<vector<IonHit> > &clusteredCore, 
 	const vector<vector<IonHit> > &clusteredBulk, vector<vector<float> > &singularValues,
 		vector<std::pair<Point3D,vector<Point3D> > > &singularVectors) const
@@ -2988,8 +2993,8 @@ void ClusterAnalysisFilter::getSingularValues(const vector<vector<IonHit> > &clu
 
 			//Cmpute the DIMENSION-D singular value decomposition for
 			//this vector set
-			computeSingularValues(data,numEntries,
-						DIMENSION,curSingularVals,curSingularBases);
+//			computeSingularValues(data,numEntries,
+//						DIMENSION,curSingularVals,curSingularBases);
 
 #pragma omp critical
 			{
@@ -3063,7 +3068,7 @@ void ClusterAnalysisFilter::getSingularValues(const vector<vector<IonHit> > &clu
 	if(data)
 		delete[] data;
 }
-
+*/
 
 #ifdef DEBUG
 
diff --git a/src/backend/filters/clusterAnalysis.h b/src/backend/filters/clusterAnalysis.h
index 7bc42bf..266bdff 100644
--- a/src/backend/filters/clusterAnalysis.h
+++ b/src/backend/filters/clusterAnalysis.h
@@ -50,6 +50,9 @@ class ClusterAnalysisFilter : public Filter
 		bool enableErosion;
 		//Erosion distance for bulk from nonclustered bulk
 		float dErosion;
+
+		//convert clusters mass to an ID #?
+		bool wantClusterID;
 		//---	
 
 		//post processing options
diff --git a/src/backend/filters/compositionProfile.cpp b/src/backend/filters/compositionProfile.cpp
index 684331f..f0b7c75 100644
--- a/src/backend/filters/compositionProfile.cpp
+++ b/src/backend/filters/compositionProfile.cpp
@@ -35,7 +35,8 @@ enum
 {
 	ERR_NUMBINS=1,
 	ERR_MEMALLOC,
-	ERR_ABORT
+	ERR_ABORT,
+	ERR_COMP_ENUM_END
 };
 
 const char *PRIMITIVE_NAME[]={
@@ -50,7 +51,7 @@ const unsigned int MINEVENTS_DEFAULT =10;
 
 CompositionProfileFilter::CompositionProfileFilter() : primitiveType(PRIMITIVE_CYLINDER),
 	showPrimitive(true), lockAxisMag(false),normalise(true), fixedBins(0),
-	nBins(1000), binWidth(0.5f), minEvents(MINEVENTS_DEFAULT), r(0.0f),g(0.0f),b(1.0f),a(1.0f), plotStyle(0)
+	nBins(1000), binWidth(0.5f), minEvents(MINEVENTS_DEFAULT), rgba(0,0,1), plotStyle(0)
 {
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(PRIMITIVE_NAME) == PRIMITIVE_END);
 	
@@ -78,7 +79,12 @@ void CompositionProfileFilter::binIon(unsigned int targetBin, const RangeStreamD
 		//that makes the target bin equate to the table size. 
 		//disallow this.
 		if(targetBin < frequencyTable[0].size())
-			frequencyTable[0][targetBin]++;
+		{
+			vector<size_t>::iterator it;
+			it=frequencyTable[0].begin()+targetBin;
+			#pragma omp critical
+			(*it)++;
+		}
 		return;
 	}
 
@@ -92,7 +98,10 @@ void CompositionProfileFilter::binIon(unsigned int targetBin, const RangeStreamD
 		unsigned int ionID=rng->rangeFile->getIonID(rangeID); 
 		unsigned int pos;
 		pos = ionIDMapping.find(ionID)->second;
-		frequencyTable[pos][targetBin]++;
+		vector<size_t>::iterator it;
+		it=frequencyTable[pos].begin()+targetBin;
+		#pragma omp critical
+		(*it)++;
 	}
 }
 
@@ -112,13 +121,10 @@ Filter *CompositionProfileFilter::cloneUncached() const
 	p->normalise=normalise;	
 	p->fixedBins=fixedBins;
 	p->lockAxisMag=lockAxisMag;
-
+	
+	p->rgba=rgba;
 	p->binWidth=binWidth;
 	p->nBins = nBins;
-	p->r=r;	
-	p->g=g;	
-	p->b=b;	
-	p->a=a;	
 	p->plotStyle=plotStyle;
 	p->errMode=errMode;
 	//We are copying wether to cache or not,
@@ -406,12 +412,22 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 		{
 			case STREAM_TYPE_IONS:
 			{
+				const IonStreamData *dIon = (const IonStreamData*)dataIn[ui];
+#ifdef _OPENMP
+				bool spin=false;
+#endif
 				//Process ion streams
-				for(vector<IonHit>::const_iterator it=((const IonStreamData *)dataIn[ui])->data.begin();
-					       it!=((const IonStreamData *)dataIn[ui])->data.end(); ++it)
+			
+				size_t nIons=dIon->data.size();	
+				#pragma omp parallel for
+				for(size_t uj=0;uj<nIons;uj++)
 				{
+#ifdef _OPENMP
+					//if parallelised, abort computaiton
+					if(spin) continue;
+#endif
 					unsigned int targetBin;
-					targetBin=dataMapping.mapIon1D(*it);
+					targetBin=dataMapping.mapIon1D(dIon->data[uj]);
 
 					//Keep ion if inside cylinder 
 					if(targetBin!=(unsigned int)-1)
@@ -419,9 +435,13 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 						//Push data into the correct bin.
 						// based upon eg ranging information and target 1D bin
 						binIon(targetBin,rngData,ionIDMapping,ionFrequencies,
-								it->getMassToCharge());
+								dIon->data[uj].getMassToCharge());
 					}
 
+#ifdef _OPENMP
+					if(omp_get_thread_num() == 0)	
+					{
+#endif
 					//update progress every CALLBACK ions
 					if(!curProg--)
 					{
@@ -429,9 +449,23 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 						progress.filterProgress= (unsigned int)((float)(n)/((float)totalSize)*100.0f);
 						curProg=NUM_CALLBACK;
 						if(!(*callback)(false))
+						{
+							#ifdef _OPENMP
+								spin=true;
+							#else
 							return ERR_ABORT;
+							#endif 
+						}
+					}
+#ifdef _OPENMP
 					}
+#endif
 				}
+
+#ifdef _OPENMP
+				if(spin)
+					return ERR_ABORT;
+#endif
 					
 				break;
 			}
@@ -457,7 +491,6 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 	normalisationFactor.resize(ionFrequencies[0].size());
 	normalisationCount.resize(ionFrequencies[0].size());
 	bool needNormalise=false;
-	bool needNormaliseCount=false;
 
 	//Perform the appropriate normalisation
 	if(!rngData && normalise)
@@ -503,7 +536,6 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 		// the loops' nesting is reversed as we need to sum over distinct plots
 		//Density profiles (non-ranged plots) have a fixed normalisation factor
 		needNormalise=true;
-		needNormaliseCount = true; // we also need to have at least one count to normalise
 
 		for(unsigned int uj=0;uj<ionFrequencies[0].size(); uj++)
 		{
@@ -571,10 +603,10 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 			//If it only has one component, then 
 			//it's not really a composition profile is it?
 			plotData[ui]->dataLabel= TRANS("Freq. Profile");
-			plotData[ui]->r = r;
-			plotData[ui]->g = g;
-			plotData[ui]->b = b;
-			plotData[ui]->a = a;
+			plotData[ui]->r = rgba.r();
+			plotData[ui]->g = rgba.g();
+			plotData[ui]->b = rgba.b();
+			plotData[ui]->a = rgba.a();
 		}
 
 		plotData[ui]->xyData.reserve(ionFrequencies[ui].size());
@@ -585,6 +617,10 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 		{
 			float xPos;
 			xPos = (((float)uj+0.5f)/(float)ionFrequencies[ui].size())*length;
+
+			if(ionFrequencies[ui][uj] < minEvents)
+				continue;
+
 			//Recompute normalisation value for this bin, if needed
 			if(needNormalise)
 			{
@@ -592,12 +628,9 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 
 				//keep the data if we are not using minimum threshold for normalisation, or we met the 
 				// threhsold
-				if(!needNormaliseCount || normalisationCount[uj] > minEvents)
-				{
-					plotData[ui]->xyData.push_back(
-						std::make_pair(xPos,
-						normFactor*(float)ionFrequencies[ui][uj]));
-				}
+				plotData[ui]->xyData.push_back(
+					std::make_pair(xPos,
+					normFactor*(float)ionFrequencies[ui][uj]));
 			}
 			else
 			{	
@@ -608,13 +641,6 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 
 
 
-		if(cache)
-		{
-			plotData[ui]->cached=1;
-			filterOutputs.push_back(plotData[ui]);	
-		}
-		else
-			plotData[ui]->cached=0;
 
 		plotData[ui]->plotStyle = plotStyle;
 		plotData[ui]->plotMode=PLOT_MODE_1D;
@@ -623,11 +649,14 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 		// otherwise, trash the plot info
 		if(plotData[ui]->xyData.size())
 		{
-			cacheOK=cache;
+			cacheAsNeeded(plotData[ui]);
 			getOut.push_back(plotData[ui]);
 		}
 		else
+		{
+			consoleOutput.push_back(TRANS("No data remained in profile - cannot display result"));
 			delete plotData[ui];
+		}
 	}
 
 	return 0;
@@ -635,16 +664,15 @@ unsigned int CompositionProfileFilter::refresh(const std::vector<const FilterStr
 
 std::string  CompositionProfileFilter::getErrString(unsigned int code) const
 {
-	switch(code)
-	{
-		case ERR_NUMBINS:
-			return std::string(TRANS("Too many bins in comp. profile."));
-		case ERR_MEMALLOC:
-			return std::string(TRANS("Not enough memory for comp. profile."));
-		case ERR_ABORT:
-			return std::string(TRANS("Aborted composition prof."));
-	}
-	return std::string("BUG: (CompositionProfileFilter::getErrString) Shouldn't see this!");
+	const char *errCodes[] =   { "",
+		"Too many bins in comp. profile.",
+		"Not enough memory for comp. profile.",
+		"Aborted composition prof." }; 
+
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errCodes) == ERR_COMP_ENUM_END);
+	ASSERT(code < ERR_COMP_ENUM_END);
+
+	return errCodes[code];
 }
 
 bool CompositionProfileFilter::setProperty( unsigned int key, 
@@ -670,24 +698,8 @@ bool CompositionProfileFilter::setProperty( unsigned int key,
 		}
 		case COMPOSITION_KEY_FIXEDBINS:
 		{
-			unsigned int valueInt;
-			if(stream_cast(valueInt,value))
+			if(!applyPropertyNow(fixedBins,value,needUpdate))
 				return false;
-
-			if(valueInt ==0 || valueInt == 1)
-			{
-				if(fixedBins!= (bool)valueInt)
-				{
-					needUpdate=true;
-					fixedBins=valueInt;
-				}
-				else
-					needUpdate=false;
-			}
-			else
-				return false;
-			clearCache();
-			needUpdate=true;	
 			break;	
 		}
 		case COMPOSITION_KEY_NORMAL:
@@ -718,24 +730,10 @@ bool CompositionProfileFilter::setProperty( unsigned int key,
 		}
 		case COMPOSITION_KEY_MINEVENTS:
 		{
-			unsigned int valueInt;
-			if(stream_cast(valueInt,value))
+			if(!applyPropertyNow(minEvents,value,needUpdate))
 				return false;
-
-			if(minEvents!= valueInt)
-			{
-				needUpdate=true;
-				minEvents=valueInt;
-			}
-			else
-				needUpdate=false;
-
-			clearCache();
-			needUpdate=true;	
 			break;	
 		}
-	
-		
 		case COMPOSITION_KEY_NUMBINS:
 		{
 			unsigned int newNumBins;
@@ -754,17 +752,8 @@ bool CompositionProfileFilter::setProperty( unsigned int key,
 		}
 		case COMPOSITION_KEY_ORIGIN:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(vectorParams[0],value,needUpdate))
 				return false;
-
-			if(!(vectorParams[0] == newPt ))
-			{
-				vectorParams[0] = newPt;
-				needUpdate=true;
-				clearCache();
-			}
-
 			return true;
 		}
 		case COMPOSITION_KEY_PRIMITIVETYPE:
@@ -854,67 +843,29 @@ bool CompositionProfileFilter::setProperty( unsigned int key,
 		}
 		case COMPOSITION_KEY_SHOWPRIMITIVE:
 		{
-			unsigned int valueInt;
-			if(stream_cast(valueInt,value))
+			if(!applyPropertyNow(showPrimitive,value,needUpdate))
 				return false;
-
-			if(valueInt ==0 || valueInt == 1)
-			{
-				if(showPrimitive!= (bool)valueInt)
-				{
-					needUpdate=true;
-					showPrimitive=valueInt;
-				}
-				else
-					needUpdate=false;
-			}
-			else
-				return false;		
 			break;	
 		}
-
 		case COMPOSITION_KEY_NORMALISE:
 		{
-			unsigned int valueInt;
-			if(stream_cast(valueInt,value))
-				return false;
-
-			if(!(valueInt ==0 || valueInt == 1))
+			if(!applyPropertyNow(normalise,value,needUpdate))
 				return false;
-			
-			if(normalise!= (bool)valueInt)
-			{
-				needUpdate=true;
-				normalise=valueInt;
-			}
-			else
-				needUpdate=false;
-		
-			clearCache();
-			needUpdate=true;	
 			break;	
 		}
 		case COMPOSITION_KEY_LOCKAXISMAG:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(lockAxisMag,value,needUpdate))
 				return false;
-
-			lockAxisMag=(stripped=="1");
-
-			needUpdate=true;
-
 			break;
 		}
-
 		case COMPOSITION_KEY_PLOTTYPE:
 		{
 			unsigned int tmpPlotType;
 
 			tmpPlotType=plotID(value);
 
-			if(tmpPlotType >= PLOT_TRACE_ENDOFENUM)
+			if(tmpPlotType >= PLOT_LINE_NONE)
 				return false;
 
 			plotStyle = tmpPlotType;
@@ -923,14 +874,11 @@ bool CompositionProfileFilter::setProperty( unsigned int key,
 		}
 		case COMPOSITION_KEY_COLOUR:
 		{
-			unsigned char newR,newG,newB,newA;
-			parseColString(value,newR,newG,newB,newA);
-
-			r=((float)newR)/255.0f;
-			g=((float)newG)/255.0f;
-			b=((float)newB)/255.0f;
-			a=1.0;
-
+			ColourRGBA tmpRgba;
+			if(!tmpRgba.parse(value))
+				return false;
+			
+			rgba=tmpRgba.toRGBAf();
 			needUpdate=true;
 			break;	
 		}
@@ -992,6 +940,7 @@ void CompositionProfileFilter::getProperties(FilterPropGroup &propertyList) cons
 		p.type=PROPERTY_TYPE_CHOICE;
 		p.helpText=TRANS("Basic shape to use for profile");
 		propertyList.addProperty(p,curGroup);
+		propertyList.setGroupTitle(curGroup,TRANS("Primitive"));	
 		curGroup++;
 	}
 
@@ -1026,10 +975,7 @@ void CompositionProfileFilter::getProperties(FilterPropGroup &propertyList) cons
 			p.helpText=TRANS("Vector between ends of cylinder");
 			propertyList.addProperty(p,curGroup);
 
-			if(lockAxisMag)
-				str="1";
-			else
-				str="0";
+			str=boolStrEnc(lockAxisMag);
 			p.key=COMPOSITION_KEY_LOCKAXISMAG;
 			p.name=TRANS("Lock Axis Mag.");
 			p.data= str;
@@ -1119,6 +1065,7 @@ void CompositionProfileFilter::getProperties(FilterPropGroup &propertyList) cons
 	p.helpText=TRANS("Drop data that does not have this many events");
 	propertyList.addProperty(p,curGroup);
 
+	propertyList.setGroupTitle(curGroup,TRANS("Settings"));	
 
 
 
@@ -1130,14 +1077,14 @@ void CompositionProfileFilter::getProperties(FilterPropGroup &propertyList) cons
 	vector<pair<unsigned int,string> > choices;
 
 
-	tmpStr=plotString(PLOT_TRACE_LINES);
-	choices.push_back(make_pair((unsigned int) PLOT_TRACE_LINES,tmpStr));
-	tmpStr=plotString(PLOT_TRACE_BARS);
-	choices.push_back(make_pair((unsigned int)PLOT_TRACE_BARS,tmpStr));
-	tmpStr=plotString(PLOT_TRACE_STEPS);
-	choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEPS,tmpStr));
-	tmpStr=plotString(PLOT_TRACE_STEM);
-	choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEM,tmpStr));
+	tmpStr=plotString(PLOT_LINE_LINES);
+	choices.push_back(make_pair((unsigned int) PLOT_LINE_LINES,tmpStr));
+	tmpStr=plotString(PLOT_LINE_BARS);
+	choices.push_back(make_pair((unsigned int)PLOT_LINE_BARS,tmpStr));
+	tmpStr=plotString(PLOT_LINE_STEPS);
+	choices.push_back(make_pair((unsigned int)PLOT_LINE_STEPS,tmpStr));
+	tmpStr=plotString(PLOT_LINE_STEM);
+	choices.push_back(make_pair((unsigned int)PLOT_LINE_STEM,tmpStr));
 
 	tmpStr= choiceString(choices,plotStyle);
 	p.name=TRANS("Plot Type");
@@ -1149,12 +1096,9 @@ void CompositionProfileFilter::getProperties(FilterPropGroup &propertyList) cons
 	//Convert the colour to a hex string
 	if(!haveRangeParent)
 	{
-		string thisCol;
-		genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0),
-		(unsigned char)(b*255.0),(unsigned char)(a*255.0),thisCol);
 
 		p.name=TRANS("Colour");
-		p.data=thisCol; 
+		p.data=rgba.toColourRGBA().rgbString();
 		p.type=PROPERTY_TYPE_COLOUR;
 		p.helpText=TRANS("Colour of plot");
 		p.key=COMPOSITION_KEY_COLOUR;
@@ -1281,8 +1225,8 @@ bool CompositionProfileFilter::writeState(std::ostream &f,unsigned int format, u
 			f << tabs(depth+1) << "<fixedbins value=\"" << (int)fixedBins << "\"/>" << endl;
 			f << tabs(depth+1) << "<nbins value=\"" << nBins << "\"/>" << endl;
 			f << tabs(depth+1) << "<binwidth value=\"" << binWidth << "\"/>" << endl;
-			f << tabs(depth+1) << "<colour r=\"" <<  r<< "\" g=\"" << g << "\" b=\"" <<b
-				<< "\" a=\"" << a << "\"/>" <<endl;
+			f << tabs(depth+1) << "<colour r=\"" <<  rgba.r() << "\" g=\"" << rgba.g() << "\" b=\"" << rgba.b()
+				<< "\" a=\"" << rgba.a() << "\"/>" <<endl;
 
 			f << tabs(depth+1) << "<plottype value=\"" << plotStyle << "\"/>" << endl;
 			f << tabs(depth) << "</" << trueName()  << ">" << endl;
@@ -1350,11 +1294,7 @@ bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string
 		return false;
 	tmpStr=(char *)xmlString;
 
-	if(tmpStr == "0")
-		showPrimitive=false;
-	else if(tmpStr == "1")
-		showPrimitive=true;
-	else
+	if(!boolStrDec(tmpStr,showPrimitive))
 		return false;
 
 	xmlFree(xmlString);
@@ -1370,11 +1310,7 @@ bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string
 		return false;
 	tmpStr=(char *)xmlString;
 
-	if(tmpStr == "0")
-		lockAxisMag=false;
-	else if(tmpStr == "1")
-		lockAxisMag=true;
-	else
+	if(!boolStrDec(tmpStr,lockAxisMag))
 		return false;
 
 	xmlFree(xmlString);
@@ -1485,11 +1421,8 @@ bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string
 		return false;
 	tmpStr=(char *)xmlString;
 
-	if(tmpStr == "0")
-		normalise=false;
-	else if(tmpStr == "1")
-		normalise=true;
-	else
+
+	if(!boolStrDec(tmpStr,normalise))
 		return false;
 
 	xmlFree(xmlString);
@@ -1505,11 +1438,7 @@ bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string
 		return false;
 	tmpStr=(char *)xmlString;
 
-	if(tmpStr == "0")
-		fixedBins=false;
-	else if(tmpStr == "1")
-		fixedBins=true;
-	else
+	if(!boolStrDec(tmpStr,fixedBins))
 		return false;
 
 
@@ -1553,7 +1482,7 @@ bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string
 	//====
 	if(XMLHelpFwdToElem(nodePtr,"colour"))
 		return false;
-	if(!parseXMLColour(nodePtr,r,g,b,a))
+	if(!parseXMLColour(nodePtr,rgba))
 		return false;
 	//====
 	
@@ -1571,7 +1500,7 @@ bool CompositionProfileFilter::readState(xmlNodePtr &nodePtr, const std::string
 	if(stream_cast(plotStyle,tmpStr))
 		return false;
 
-	if(plotStyle >= PLOT_TRACE_ENDOFENUM)
+	if(plotStyle >= PLOT_LINE_NONE)
 	       return false;	
 	xmlFree(xmlString);
 	//====
@@ -1710,6 +1639,7 @@ bool testCompositionCylinder()
 	bool needUp; std::string s;
 	stream_cast(s,Point3D((startPt+endPt)*0.5f));
 	TEST(f->setProperty(COMPOSITION_KEY_ORIGIN,s,needUp),"set origin");
+	TEST(f->setProperty(COMPOSITION_KEY_MINEVENTS,"0",needUp),"set origin");
 	
 	stream_cast(s,Point3D((endPt-startPt)*0.5f));
 	TEST(f->setProperty(COMPOSITION_KEY_NORMAL,s,needUp),"set direction");
diff --git a/src/backend/filters/compositionProfile.h b/src/backend/filters/compositionProfile.h
index 2799828..b4a677b 100644
--- a/src/backend/filters/compositionProfile.h
+++ b/src/backend/filters/compositionProfile.h
@@ -76,7 +76,7 @@ class CompositionProfileFilter : public Filter
 		//Plotting stuff
 		//--
 		//colour of plot
-		float r,g,b,a;
+		ColourRGBAf rgba;
 		//Mode for plotting (eg lines, steps)
 		unsigned int plotStyle;
 	
diff --git a/src/backend/filters/dataLoad.cpp b/src/backend/filters/dataLoad.cpp
index 5fc4809..b35a2df 100644
--- a/src/backend/filters/dataLoad.cpp
+++ b/src/backend/filters/dataLoad.cpp
@@ -68,7 +68,7 @@ const char *DEFAULT_LABEL="Mass-to-Charge (amu/e)";
 
 // == Pos load filter ==
 DataLoadFilter::DataLoadFilter() : fileType(FILEDATA_TYPE_POS), doSample(true), maxIons(MAX_IONS_LOAD_DEFAULT),
-	r(1.0f),g(0.0f),b(0.0f),a(1.0f),ionSize(2.0f), numColumns(4), enabled(true),
+	rgbaf(1.0f,0.0f,0.0f,1.0f),ionSize(2.0f), numColumns(4), enabled(true),
 	volumeRestrict(false), monitorTimestamp(-1),monitorSize((size_t)-1),wantMonitor(false),
 	valueLabel(TRANS(DEFAULT_LABEL)), endianMode(0)
 {
@@ -91,12 +91,8 @@ Filter *DataLoadFilter::cloneUncached() const
 	p->maxIons=maxIons;
 	p->ionSize=ionSize;
 	p->fileType=fileType;
-	p->guessType=guessType;
 	//Colours
-	p->r=r;	
-	p->g=g;	
-	p->b=b;	
-	p->a=a;	
+	p->rgbaf=rgbaf;	
 	//Bounding volume
 	p->bound.setBounds(bound);
 	p->volumeRestrict=volumeRestrict;
@@ -198,7 +194,7 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 		//the same timestamp as on the file.
 		if(wantMonitor)
 		{
-			if(!wxFile::Exists(wxStr(ionFilename)))
+			if(!wxFile::Exists((ionFilename)))
 			{
 				monitorTimestamp=-1;
 				monitorSize=-1;
@@ -214,7 +210,7 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 				size_t fileSizeVal;
 				getFilesize(ionFilename.c_str(),fileSizeVal);
 
-				if(wxFileModificationTime(wxStr(ionFilename)) ==monitorTimestamp
+				if(wxFileModificationTime((ionFilename)) ==monitorTimestamp
 					||  fileSizeVal!= monitorSize)
 				{
 					doUseCache=false;
@@ -235,9 +231,9 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 	}
 
 	//If theres no file, then there is not a lot we can do..
-	if(!wxFile::Exists(wxStr(ionFilename)))
+	if(!wxFile::Exists((ionFilename)))
 	{
-		wxFileName f(wxStr(ionFilename));
+		wxFileName f((ionFilename));
 		
 		errStr= stlStr(f.GetFullName())  + TRANS(" does not exist");
 		return ERR_FILE_OPEN;
@@ -245,7 +241,7 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 	
 	//If we have disable the filter, or we are are monitoring and 
 	//there is no file
-	if(!enabled ||(wantMonitor && !wxFile::Exists(wxStr(ionFilename))) )
+	if(!enabled ||(wantMonitor && !wxFile::Exists((ionFilename))) )
 	{
 		monitorTimestamp=-1;
 		monitorSize=-1;
@@ -257,7 +253,7 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 
 	//Update the monitoring timestamp such that we know
 	//when the file was last loaded
-	monitorTimestamp = wxFileModificationTime(wxStr(ionFilename));
+	monitorTimestamp = wxFileModificationTime((ionFilename));
 	size_t tmp;
 	if(getFilesize(ionFilename.c_str(),tmp))
 		monitorSize=tmp;
@@ -423,10 +419,10 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 			ASSERT(false);
 	}
 
-	ionData->r = r;
-	ionData->g = g;
-	ionData->b = b;
-	ionData->a = a;
+	ionData->r = rgbaf.r();
+	ionData->g = rgbaf.g();
+	ionData->b = rgbaf.b();
+	ionData->a = rgbaf.a();
 	ionData->ionSize=ionSize;
 	ionData->valueType=valueLabel;
 
@@ -451,15 +447,7 @@ unsigned int DataLoadFilter::refresh(const std::vector<const FilterStreamData *>
 			       "(magnitude too large). Consider rescaling data before loading"));
 	}
 
-	if(cache)
-	{
-		ionData->cached=1;
-		filterOutputs.push_back(ionData);
-		cacheOK=true;
-	}
-	else
-		ionData->cached=0;
-
+	cacheAsNeeded(ionData);
 
 	//Append the ion data 
 	getOut.push_back(ionData);
@@ -476,11 +464,13 @@ void DataLoadFilter::getProperties(FilterPropGroup &propertyList) const
 
 	size_t curGroup=0;
 
-	p.type=PROPERTY_TYPE_STRING;
+	p.type=PROPERTY_TYPE_FILE;
 	p.key=DATALOAD_KEY_FILE;
 	p.name=TRANS("File");
 	p.helpText=TRANS("File from which to load data");
 	p.data=ionFilename;
+	//Wx- acceptable string format
+	p.dataSecondary = TRANS("Readable files (*.xml, *.pos, *.txt,*.csv, *.ato)|*.xml;*.pos;*.txt;*.csv;*.ato|All Files|*") ;
 
 	propertyList.addProperty(p,curGroup);
 
@@ -497,6 +487,7 @@ void DataLoadFilter::getProperties(FilterPropGroup &propertyList) const
 	
 	propertyList.addProperty(p,curGroup);
 
+	propertyList.setGroupTitle(curGroup,TRANS("File"));
 	//---------
 	curGroup++;	
 	
@@ -603,7 +594,7 @@ void DataLoadFilter::getProperties(FilterPropGroup &propertyList) const
 	{
 		std::string tmpStr;
 
-		//FIXME: ATO Files need an imeplmentation of sampling read
+		//FIXME: ATO Files need an implementation of sampling read
 		if(fileType!=FILEDATA_TYPE_ATO)
 		{
 			stream_cast(tmpStr,doSample);
@@ -633,18 +624,17 @@ void DataLoadFilter::getProperties(FilterPropGroup &propertyList) const
 		p.type=PROPERTY_TYPE_BOOL;
 		p.helpText=TRANS("Watch file timestamp to track changes to file contents from other programs");
 		propertyList.addProperty(p,curGroup);
-		propertyList.setGroupTitle(curGroup,TRANS("Load params."));
+	}
+	
+	propertyList.setGroupTitle(curGroup,TRANS("Load params."));
 
+	if(enabled)
+	{
 		
 		curGroup++;
 
-		string thisCol;
-		//Convert the ion colour to a hex string	
-		genColString((unsigned char)(r*255),(unsigned char)(g*255),
-				(unsigned char)(b*255),(unsigned char)(a*255),thisCol);
-
 		p.name=TRANS("Default colour ");
-		p.data=thisCol; 
+		p.data=rgbaf.toColourRGBA().rgbaString(); 
 		p.type=PROPERTY_TYPE_COLOUR;
 		p.helpText=TRANS("Default colour for points, if not overridden by other filters");
 		p.key=DATALOAD_KEY_COLOUR;
@@ -656,6 +646,7 @@ void DataLoadFilter::getProperties(FilterPropGroup &propertyList) const
 		p.type=PROPERTY_TYPE_REAL;
 		p.helpText=TRANS("Default size for points, if not overridden by other filters");
 		p.key=DATALOAD_KEY_IONSIZE;
+		
 		propertyList.addProperty(p,curGroup);
 		propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 	}
@@ -715,57 +706,21 @@ bool DataLoadFilter::setProperty(  unsigned int key,
 		}
 		case DATALOAD_KEY_ENABLED:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(enabled,value,needUpdate))
 				return false;
-
-			bool lastVal=enabled;
-			enabled=(stripped == "1");
-			
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=enabled)
-				needUpdate=true;
-			
-			clearCache();
 			break;
 		}
 		case DATALOAD_KEY_MONITOR:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(wantMonitor,value,needUpdate))
 				return false;
-
-			bool lastVal=wantMonitor;
-			wantMonitor=(stripped=="1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=wantMonitor)
-				needUpdate=true;
-			
-			clearCache();
 			break;
 		}
 		
 		case DATALOAD_KEY_SAMPLE:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(doSample,value,needUpdate))
 				return false;
-
-			bool lastVal=doSample;
-			doSample=(stripped == "1");
-			
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=doSample)
-				needUpdate=true;
-			
-			clearCache();
 			break;
 		}
 		case DATALOAD_KEY_SIZE:
@@ -789,17 +744,12 @@ bool DataLoadFilter::setProperty(  unsigned int key,
 		}
 		case DATALOAD_KEY_COLOUR:
 		{
-			unsigned char newR,newG,newB,newA;
-
-			parseColString(value,newR,newG,newB,newA);
+			ColourRGBA tmpRgba;
+			tmpRgba.parse(value);
 
-			if(newB != b || newR != r ||
-				newG !=g || newA != a)
+			if(tmpRgba != rgbaf.toColourRGBA())
 			{
-				r=newR/255.0;
-				g=newG/255.0;
-				b=newB/255.0;
-				a=newA/255.0;
+				rgbaf=tmpRgba.toRGBAf();
 
 
 				//Check the cache, updating it if needed
@@ -811,10 +761,10 @@ bool DataLoadFilter::setProperty(  unsigned int key,
 						{
 							IonStreamData *i;
 							i=(IonStreamData *)filterOutputs[ui];
-							i->r=r;
-							i->g=g;
-							i->b=b;
-							i->a=a;
+							i->r=rgbaf.r();
+							i->g=rgbaf.g();
+							i->b=rgbaf.b();
+							i->a=rgbaf.a();
 						}
 					}
 
@@ -1145,7 +1095,7 @@ bool DataLoadFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFile
 	if(XMLHelpFwdToElem(nodePtr,"colour"))
 		return false;
 
-	if(!parseXMLColour(nodePtr,r,g,b,a))
+	if(!parseXMLColour(nodePtr,rgbaf))
 		return false;	
 	//====
 
@@ -1207,8 +1157,8 @@ bool DataLoadFilter::writeState(std::ostream &f,unsigned int format, unsigned in
 			f << tabs(depth+1) << "<dosample value=\"" << doSample << "\"/>" << endl;
 			f << tabs(depth+1) << "<maxions value=\"" << maxIons << "\"/>" << endl;
 
-			f << tabs(depth+1) << "<colour r=\"" <<  r<< "\" g=\"" << g << "\" b=\"" <<b
-				<< "\" a=\"" << a << "\"/>" <<endl;
+			f << tabs(depth+1) << "<colour r=\"" <<  rgbaf.r() << "\" g=\"" << rgbaf.g() 
+				<< "\" b=\"" << rgbaf.b() << "\" a=\"" << rgbaf.a() << "\"/>" <<endl;
 			f << tabs(depth+1) << "<ionsize value=\"" << ionSize << "\"/>" << endl;
 			f << tabs(depth) << "</" << trueName() << ">" << endl;
 			break;
@@ -1257,7 +1207,7 @@ bool DataLoadFilter::monitorNeedsRefresh() const
 	{
 		//Check to see that the file exists, if
 		// not fall back to the cache.
-		if(!wxFile::Exists(wxStr(ionFilename)))
+		if(!wxFile::Exists((ionFilename)))
 			return cacheOK;
 
 
@@ -1266,7 +1216,7 @@ bool DataLoadFilter::monitorNeedsRefresh() const
 		if(sizeVal != monitorSize)
 			return true;
 
-		return( wxFileModificationTime(wxStr(ionFilename))
+		return( wxFileModificationTime((ionFilename))
 						!=monitorTimestamp);
 		
 		
diff --git a/src/backend/filters/dataLoad.h b/src/backend/filters/dataLoad.h
index 09499f9..cb28899 100644
--- a/src/backend/filters/dataLoad.h
+++ b/src/backend/filters/dataLoad.h
@@ -20,6 +20,7 @@
 
 #include "../filter.h"
 
+#include "../../common/basics.h"
 #include "../../common/translation.h"
 
 enum
@@ -57,8 +58,6 @@ class DataLoadFilter:public Filter
 		//!Type of file to open
 		unsigned int fileType;
 
-		//!Try our best to guess the file type?
-		bool guessType;
 
 
 		//!Whether to randomly sample dataset during load or not
@@ -68,7 +67,7 @@ class DataLoadFilter:public Filter
 		size_t maxIons;
 
 		//!Default ion colour vars
-		float r,g,b,a;
+		ColourRGBAf rgbaf;
 
 		//!Default ion size (view size)
 		float ionSize;
diff --git a/src/backend/filters/externalProgram.cpp b/src/backend/filters/externalProgram.cpp
index b82cc5b..fa621f2 100644
--- a/src/backend/filters/externalProgram.cpp
+++ b/src/backend/filters/externalProgram.cpp
@@ -21,6 +21,7 @@
 
 #include "../../wx/wxcommon.h"
 #include "backend/APT/APTFileIO.h"
+#include "backend/plot.h"
 
 #include <wx/filename.h>
 #include <wx/dir.h>
@@ -39,6 +40,7 @@ enum
 	READPOS_FAIL,
 	SUBSTITUTE_FAIL,
 	COMMAND_FAIL, 
+	EXT_PROG_ERR_ENUM_END, 
 };
 
 //=== External program filter === 
@@ -226,7 +228,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 	string s;
 	wxString tempDir;
 	if(workingDir.size())
-		tempDir=(wxStr(workingDir) +wxT("/inputData"));
+		tempDir=((workingDir) +wxT("/inputData"));
 	else
 		tempDir=(wxT("inputData"));
 
@@ -320,7 +322,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 	if(workingDir.size())
 	{
 		//Set the working directory before launching
-		if(!wxSetWorkingDirectory(wxStr(workingDir)))
+		if(!wxSetWorkingDirectory((workingDir)))
 			return SETWORKDIR_FAIL;
 	}
 	else
@@ -331,7 +333,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 
 	bool result;
 	//Execute the program
-	result=wxShell(wxStr(substitutedCommand));
+	result=wxShell((substitutedCommand));
 
 	if(cleanInput)
 	{
@@ -340,7 +342,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 		for(unsigned int ui=0;ui<ionOutputNames.size();ui++)
 		{
 			//try to delete the file
-			wxRemoveFile(wxStr(ionOutputNames[ui]));
+			wxRemoveFile((ionOutputNames[ui]));
 
 			//call the update to be nice
 			(*callback)(false);
@@ -348,7 +350,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 		for(unsigned int ui=0;ui<plotOutputNames.size();ui++)
 		{
 			//try to delete the file
-			wxRemoveFile(wxStr(plotOutputNames[ui]));
+			wxRemoveFile((plotOutputNames[ui]));
 
 			//call the update to be nice
 			(*callback)(false);
@@ -363,7 +365,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 	wxDir *dir = new wxDir;
 	wxArrayString *a = new wxArrayString;
 	if(workingDir.size())
-		dir->GetAllFiles(wxStr(workingDir),a,wxT("*.pos"),wxDIR_FILES);
+		dir->GetAllFiles((workingDir),a,wxT("*.pos"),wxDIR_FILES);
 	else
 		dir->GetAllFiles(wxGetCwd(),a,wxT("*.pos"),wxDIR_FILES);
 
@@ -418,7 +420,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 
 	a->Clear();
 	if(workingDir.size())
-		dir->GetAllFiles(wxStr(workingDir),a,wxT("*.xy"),wxDIR_FILES);
+		dir->GetAllFiles((workingDir),a,wxT("*.xy"),wxDIR_FILES);
 	else
 		dir->GetAllFiles(wxGetCwd(),a,wxT("*.xy"),wxDIR_FILES);
 
@@ -478,7 +480,7 @@ unsigned int ExternalProgramFilter::refresh(const std::vector<const FilterStream
 				d->a=1.0;
 				d->index=uj;
 				d->plotMode=PLOT_MODE_1D;
-				d->plotStyle=PLOT_TRACE_LINES;
+				d->plotStyle=PLOT_LINE_LINES;
 
 
 				//set the title to the filename (trim the .xy extension
@@ -554,12 +556,9 @@ void ExternalProgramFilter::getProperties(FilterPropGroup &propertyList) const
 	p.key=EXTERNALPROGRAM_KEY_WORKDIR;		
 	propertyList.addProperty(p,curGroup);
 	
-
-	if(cleanInput)
-		tmpStr="1";
-	else
-		tmpStr="0";
-
+	propertyList.setGroupTitle(curGroup,TRANS("Command"));
+	curGroup++;
+	tmpStr=boolStrEnc(cleanInput);
 	p.name=TRANS("Cleanup input");
 	p.data=tmpStr;
 	p.type=PROPERTY_TYPE_BOOL;
@@ -567,11 +566,7 @@ void ExternalProgramFilter::getProperties(FilterPropGroup &propertyList) const
 	p.key=EXTERNALPROGRAM_KEY_CLEANUPINPUT;		
 	propertyList.addProperty(p,curGroup);
 	
-	if(alwaysCache)
-		tmpStr="1";
-	else
-		tmpStr="0";
-	
+	tmpStr=boolStrEnc(alwaysCache);
 	p.name=TRANS("Cache");
 	p.data=tmpStr;
 	p.type=PROPERTY_TYPE_BOOL;
@@ -579,6 +574,7 @@ void ExternalProgramFilter::getProperties(FilterPropGroup &propertyList) const
 	p.key=EXTERNALPROGRAM_KEY_ALWAYSCACHE;		
 	propertyList.addProperty(p,curGroup);
 
+	propertyList.setGroupTitle(curGroup,TRANS("Data"));
 }
 
 bool ExternalProgramFilter::setProperty(  unsigned int key,
@@ -589,12 +585,8 @@ bool ExternalProgramFilter::setProperty(  unsigned int key,
 	{
 		case EXTERNALPROGRAM_KEY_COMMAND:
 		{
-			if(commandLine!=value)
-			{
-				commandLine=value;
-				needUpdate=true;
-				clearCache();
-			}
+			if(!applyPropertyNow(commandLine,value,needUpdate))
+				return false;
 			break;
 		}
 		case EXTERNALPROGRAM_KEY_WORKDIR:
@@ -602,7 +594,7 @@ bool ExternalProgramFilter::setProperty(  unsigned int key,
 			if(workingDir!=value)
 			{
 				//Check the directory exists
-				if(!wxDirExists(wxStr(value)))
+				if(!wxDirExists((value)))
 					return false;
 
 				workingDir=value;
@@ -613,33 +605,14 @@ bool ExternalProgramFilter::setProperty(  unsigned int key,
 		}
 		case EXTERNALPROGRAM_KEY_ALWAYSCACHE:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(alwaysCache,value,needUpdate))
 				return false;
-
-			if(stripped=="1")
-				alwaysCache=true;
-			else
-			{
-				alwaysCache=false;
-
-				//If we need to generate a cache, do so
-				//otherwise, trash it
-				clearCache();
-			}
-
-			needUpdate=true;
 			break;
 		}
 		case EXTERNALPROGRAM_KEY_CLEANUPINPUT:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(cleanInput,value,needUpdate))
 				return false;
-			cleanInput=(stripped=="1");
-			needUpdate=true;
 			break;
 		}
 		default:
@@ -653,33 +626,21 @@ bool ExternalProgramFilter::setProperty(  unsigned int key,
 
 std::string  ExternalProgramFilter::getErrString(unsigned int code) const
 {
-
-	switch(code)
-	{
-		case COMMANDLINE_FAIL:
-			return std::string(TRANS("Error processing command line"));
-		case SETWORKDIR_FAIL:
-			return std::string(TRANS("Unable to set working directory"));
-		case WRITEPOS_FAIL:
-			return std::string(TRANS("Error saving posfile result for external program"));
-		case WRITEPLOT_FAIL:
-			return std::string(TRANS("Error saving plot result for externalprogram"));
-		case MAKEDIR_FAIL:
-			return std::string(TRANS("Error creating temporary directory"));
-		case PLOTCOLUMNS_FAIL:
-			return std::string(TRANS("Detected unusable number of columns in plot"));
-		case READPLOT_FAIL:
-			return std::string(TRANS("Unable to parse plot result from external program"));
-		case READPOS_FAIL:
-			return std::string(TRANS("Unable to load ions from external program")); 
-		case SUBSTITUTE_FAIL:
-			return std::string(TRANS("Unable to perform commandline substitution"));
-		case COMMAND_FAIL: 
-			return std::string(TRANS("Error executing external program"));
-		default:
-			//Currently the only error is aborting
-			return std::string("Bug: write me (externalProgramfilter).");
-	}
+	const char *errStrs[] = 	{ "",
+			"Error processing command line",
+			"Unable to set working directory",
+			"Error saving posfile result for external program",
+			"Error saving plot result for externalprogram",
+			"Error creating temporary directory",
+			"Detected unusable number of columns in plot",
+			"Unable to parse plot result from external program",
+			"Unable to load ions from external program", 
+			"Unable to perform commandline substitution",
+			"Error executing external program" };
+	
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == EXT_PROG_ERR_ENUM_END);
+	ASSERT(code < EXT_PROG_ERR_ENUM_END);
+	return errStrs[code];
 }
 
 void ExternalProgramFilter::setPropFromBinding(const SelectionBinding &b)
@@ -749,22 +710,14 @@ bool ExternalProgramFilter::readState(xmlNodePtr &nodePtr, const std::string &st
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"alwayscache","value"))
 		return false;
 
-	if(tmpStr == "1") 
-		alwaysCache=true;
-	else if(tmpStr== "0")
-		alwaysCache=false;
-	else
+	if(!boolStrDec(tmpStr,alwaysCache))
 		return false;
 
 	//check readable 
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"cleaninput","value"))
 		return false;
 
-	if(tmpStr == "1") 
-		cleanInput=true;
-	else if(tmpStr== "0")
-		cleanInput=false;
-	else
+	if(!boolStrDec(tmpStr,cleanInput))
 		return false;
 
 	return true;
@@ -870,12 +823,18 @@ bool posTest()
 #else
 	tmpDir=tmpDir + wxT("/3Depict/");
 #endif
+	if(wxDirExists(tmpDir))
+	{
+		wxFileName dirFile(tmpDir);
+		dirFile.Rmdir( wxPATH_RMDIR_RECURSIVE);
+	}
+
+		
 	wxMkdir(tmpDir);
 
 	tmpFilename=wxFileName::CreateTempFileName(tmpDir+ wxT("unittest-"));
-	wxRemoveFile(tmpFilename);
 	tmpFilename+=wxT(".pos");
-	s ="mv \%i " + stlStr(tmpFilename);
+	s ="mv -f \%i " + stlStr(tmpFilename);
 
 	ASSERT(tmpFilename.size());
 	
@@ -943,13 +902,14 @@ bool ExternalProgramFilter::runUnitTests()
 {
 	if(!echoTest())
 		return false;
-	
+
+#ifndef __APPLE__
 	if(!posTest())
 		return false;
 
 	if(!substituteTest())
 		return false;
-
+#endif
 	return true;
 }
 
diff --git a/src/backend/filters/filterCommon.cpp b/src/backend/filters/filterCommon.cpp
index 5b8afdf..4a754f7 100644
--- a/src/backend/filters/filterCommon.cpp
+++ b/src/backend/filters/filterCommon.cpp
@@ -19,7 +19,7 @@
 #include "filterCommon.h"
 
 #include "common/colourmap.h"
-
+#include "wx/wxcommon.h"
 
 
 //TODO: Work out where the payoff for this is
@@ -111,9 +111,11 @@ bool readVectorsXML(xmlNodePtr nodePtr,	std::vector<Point3D> &vectorParams)
 	return true;
 }
 
-bool parseXMLColour(xmlNodePtr &nodePtr, float &r,float&g,float&b,float&a)
+bool parseXMLColour(xmlNodePtr &nodePtr, ColourRGBAf &rgba)
 {
 	xmlChar *xmlString;
+
+	float r,g,b,a;
 	std::string tmpStr;
 	//--red--
 	xmlString=xmlGetProp(nodePtr,(const xmlChar *)"r");
@@ -185,6 +187,10 @@ bool parseXMLColour(xmlNodePtr &nodePtr, float &r,float&g,float&b,float&a)
 	//disallow negative or values gt 1.
 	if(a < 0.0f || a > 1.0f)
 		return false;
+	rgba.r(r);
+	rgba.g(g);
+	rgba.b(b);
+	rgba.a(a);
 
 	return true;
 }
@@ -675,7 +681,7 @@ void freeConvexHull()
 	qhullInited=false;
 }
 
-DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_t colourMap, bool reverseMap) 
+DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_t colourMap, bool reverseMap, float alpha) 
 {
 	//Set up the colour bar. Place it in a draw stream type
 	DrawColourBarOverlay *dc = new DrawColourBarOverlay;
@@ -702,7 +708,39 @@ DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_
 	dc->setSize(0.08,0.6);
 	dc->setPosition(0.1,0.1);
 	dc->setMinMax(minV,maxV);
-
+	dc->setAlpha(alpha);
 
 	return dc;
 }
+
+//creates a temporary filename for use
+std::string createTmpFilename(const char *dir,const char *extension)
+{
+	wxString tmpFilename,tmpDir;
+	
+	if(!dir)
+	{
+		tmpDir=wxFileName::GetTempDir();
+
+
+	#if defined(__WIN32__) || defined(__WIN64__)
+		tmpDir=tmpDir + wxT("\\3Depict\\");
+
+	#else
+		tmpDir=tmpDir + wxT("/3Depict/");
+	#endif
+
+	}
+	else
+		tmpDir=dir;
+	
+	if(!wxDirExists(tmpDir))
+		wxMkdir(tmpDir);
+	tmpFilename=wxFileName::CreateTempFileName(tmpDir+ wxT("unittest-"));
+	wxRemoveFile(tmpFilename);
+	if(extension)
+		tmpFilename+=wxT(".pos");
+
+	return stlStr(tmpFilename);
+}
+
diff --git a/src/backend/filters/filterCommon.h b/src/backend/filters/filterCommon.h
index eec1f41..5085124 100644
--- a/src/backend/filters/filterCommon.h
+++ b/src/backend/filters/filterCommon.h
@@ -22,6 +22,7 @@
 #include "../filter.h"
 
 #include "common/stringFuncs.h"
+#include "common/basics.h"
 #include "common/xmlHelper.h"
 
 #include "backend/APT/APTRanges.h"
@@ -105,8 +106,8 @@ bool readVectorsXML(xmlNodePtr nodePtr,
 
 
 //Parse a "colour" node, extracting rgba data
-bool parseXMLColour(xmlNodePtr &nodePtr, 
-		float &r, float&g, float&b, float&a);
+bool parseXMLColour(xmlNodePtr &nodePtr, ColourRGBAf &rgbaf); 
+		
 
 //Returns the ion stream's range ID from the rangefile, if and only if it every ion in input
 // is ranged tht way. Otherwise returns -1.
@@ -130,6 +131,11 @@ unsigned int computeConvexHull(const std::vector<Point3D> &data,
 //Release the memory held by qhull, and notify the computeConvexHull routines that this has been done
 void freeConvexHull();
 //Draw a colour bar
-DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_t colourMap, bool reverseMap=false) ;
+DrawColourBarOverlay *makeColourBar(float minV, float maxV,size_t nColours,size_t colourMap, bool reverseMap=false, float alpha=1.0f) ;
+
+
+//Create a temporary filename, optionally providing an extension to use/
+// - note that any subdirs will be automatically created if needed.
+std::string createTmpFilename(const char *dir=NULL,const char *extension=NULL);
 
 #endif
diff --git a/src/backend/filters/ionClip.cpp b/src/backend/filters/ionClip.cpp
index 9e8ac91..6502ea9 100644
--- a/src/backend/filters/ionClip.cpp
+++ b/src/backend/filters/ionClip.cpp
@@ -29,6 +29,7 @@ enum
 {
 	CALLBACK_FAIL=1,
 	BAD_ALLOC,
+	IONCLIP_ERR_ENUM_END
 };
 
 //!Possible primitive types for ion clipping
@@ -435,15 +436,7 @@ unsigned int IonClipFilter::refresh(const std::vector<const FilterStreamData *>
 						d->representationType=((IonStreamData *)dataIn[ui])->representationType;
 
 						//getOut is const, so shouldn't be modified
-						if(cache)
-						{
-							d->cached=1;
-							filterOutputs.push_back(d);
-							cacheOK=true;
-						}
-						else
-							d->cached=0;
-						
+						cacheAsNeeded(d);
 
 						getOut.push_back(d);
 						d=0;
@@ -581,10 +574,7 @@ void IonClipFilter::getProperties(FilterPropGroup &propertyList) const
 			p.helpText=TRANS("Positive vector for cylinder");
 			propertyList.addProperty(p,curGroup);
 			
-			if(lockAxisMag)
-				tmpStr="1";
-			else
-				tmpStr="0";
+			tmpStr=boolStrEnc(lockAxisMag);
 			p.key=KEY_AXIS_LOCKMAG;
 			p.name=TRANS("Lock Axis Mag.");
 			p.data=tmpStr;
@@ -625,7 +615,8 @@ void IonClipFilter::getProperties(FilterPropGroup &propertyList) const
 		default:
 			ASSERT(false);
 	}
-	
+
+	propertyList.setGroupTitle(curGroup,TRANS("Clipping"));
 }
 
 //!Set the properties for the nth filter. Returns true if prop set OK
@@ -737,50 +728,21 @@ bool IonClipFilter::setProperty(unsigned int key,
 		}
 		case KEY_ORIGIN:
 		{
-			ASSERT(vectorParams.size() >= 1);
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(vectorParams[0],value,needUpdate))
 				return false;
-
-			if(!(vectorParams[0] == newPt ))
-			{
-				vectorParams[0] = newPt;
-				needUpdate=true;
-				clearCache();
-			}
-
-			return true;
+			break;
 		}
 		case KEY_CORNER:
 		{
-			ASSERT(vectorParams.size() >= 2);
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(vectorParams[1],value,needUpdate))
 				return false;
-
-			if(!(vectorParams[1] == newPt ))
-			{
-				vectorParams[1] = newPt;
-				needUpdate=true;
-				clearCache();
-			}
-
-			return true;
+			break;
 		}
 		case KEY_RADIUS:
 		{
-			ASSERT(scalarParams.size() >=1);
-			float newRad;
-			if(stream_cast(newRad,value))
+			if(!applyPropertyNow(scalarParams[0],value,needUpdate))
 				return false;
-
-			if(scalarParams[0] != newRad )
-			{
-				scalarParams[0] = newRad;
-				needUpdate=true;
-				clearCache();
-			}
-			return true;
+			break;
 		}
 		case KEY_NORMAL:
 		{
@@ -808,58 +770,20 @@ bool IonClipFilter::setProperty(unsigned int key,
 		}
 		case KEY_PRIMITIVE_SHOW:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(showPrimitive,value,needUpdate))
 				return false;
-
-			if(stripped=="1")
-				showPrimitive=true;
-			else
-				showPrimitive=false;
-
-			needUpdate=true;
-
 			break;
 		}
 		case KEY_PRIMITIVE_INVERTCLIP:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(invertedClip,value,needUpdate))
 				return false;
-
-			bool lastVal=invertedClip;
-			if(stripped=="1")
-				invertedClip=true;
-			else
-				invertedClip=false;
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=invertedClip)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-
 			break;
 		}
-
 		case KEY_AXIS_LOCKMAG:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(lockAxisMag,value,needUpdate))
 				return false;
-
-			if(stripped=="1")
-				lockAxisMag=true;
-			else
-				lockAxisMag=false;
-
-			needUpdate=true;
-
 			break;
 		}
 		default:
@@ -875,14 +799,13 @@ bool IonClipFilter::setProperty(unsigned int key,
 //!Get the human readable error string associated with a particular error code during refresh(...)
 std::string IonClipFilter::getErrString(unsigned int code) const
 {
-	switch(code)
-	{
-		case BAD_ALLOC:
-			return std::string("Insufficient mem. for Ionclip");
-		case CALLBACK_FAIL:
-			return std::string("Ionclip Aborted");
-	}
-	ASSERT(false);
+	const char *errCode[] = { "",
+				"Insufficient mem. for Ionclip",
+				"Ionclip Aborted"
+	};
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errCode) == IONCLIP_ERR_ENUM_END);
+	ASSERT(code < IONCLIP_ERR_ENUM_END);
+	return errCode[code];
 }
 
 bool IonClipFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const
@@ -942,11 +865,8 @@ bool IonClipFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileD
 	//
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"invertedclip","value"))
 		return false;
-	if(tmpStr == "0")
-		invertedClip=false;
-	else if(tmpStr == "1")
-		invertedClip=true;
-	else
+
+	if(!boolStrDec(tmpStr,invertedClip))
 		return false;
 	//====
 	
@@ -954,11 +874,7 @@ bool IonClipFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileD
 	//====
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"showprimitive","value"))
 		return false;
-	if(tmpStr == "0")
-		showPrimitive=false;
-	else if(tmpStr == "1")
-		showPrimitive=true;
-	else
+	if(!boolStrDec(tmpStr,showPrimitive))
 		return false;
 	//====
 	
@@ -966,11 +882,8 @@ bool IonClipFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileD
 	//====
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"lockaxismag","value"))
 		return false;
-	if(tmpStr == "0")
-		lockAxisMag=false;
-	else if(tmpStr == "1")
-		lockAxisMag=true;
-	else
+
+	if(!boolStrDec(tmpStr,lockAxisMag))
 		return false;
 	//====
 	
diff --git a/src/backend/filters/ionColour.cpp b/src/backend/filters/ionColour.cpp
index 7bf43e0..cf2e05b 100644
--- a/src/backend/filters/ionColour.cpp
+++ b/src/backend/filters/ionColour.cpp
@@ -32,6 +32,7 @@ enum
 	KEY_IONCOLOURFILTER_NCOLOURS,
 	KEY_IONCOLOURFILTER_REVERSE,
 	KEY_IONCOLOURFILTER_SHOWBAR,
+	KEY_IONCOLOURFILTER_ALPHA,
 };
 
 enum
@@ -40,7 +41,7 @@ enum
 };
 
 IonColourFilter::IonColourFilter() : colourMap(0),reverseMap(false), 
-		nColours(MAX_NUM_COLOURS),showColourBar(true)
+		nColours(MAX_NUM_COLOURS),showColourBar(true), alpha(1.0f)
 {
 	mapBounds[0] = 0.0f;
 	mapBounds[1] = 100.0f;
@@ -57,6 +58,7 @@ Filter *IonColourFilter::cloneUncached() const
 	p->mapBounds[0]=mapBounds[0];
 	p->mapBounds[1]=mapBounds[1];
 	p->nColours =nColours;	
+	p->alpha = alpha;
 	p->showColourBar =showColourBar;	
 	p->reverseMap=reverseMap;	
 	
@@ -88,10 +90,11 @@ unsigned int IonColourFilter::refresh(const std::vector<const FilterStreamData *
 
 		if(filterOutputs.size() && showColourBar)
 		{
+			//TODO:  Can I remove this? Caching for drawables now should work, right?
 			DrawStreamData *d = new DrawStreamData;
 			d->parent=this;
 			d->drawables.push_back(makeColourBar(mapBounds[0],
-					mapBounds[1],nColours,colourMap));
+					mapBounds[1],nColours,colourMap,alpha));
 			d->cached=0;
 			getOut.push_back(d);
 		}
@@ -191,7 +194,7 @@ unsigned int IonColourFilter::refresh(const std::vector<const FilterStreamData *
 	if(foundIons && showColourBar)
 	{
 		DrawStreamData *d = new DrawStreamData;
-		d->drawables.push_back(makeColourBar(mapBounds[0],mapBounds[1],nColours,colourMap,reverseMap));
+		d->drawables.push_back(makeColourBar(mapBounds[0],mapBounds[1],nColours,colourMap,reverseMap,alpha));
 		d->parent=this;
 		d->cached=0;
 		getOut.push_back(d);
@@ -276,6 +279,12 @@ void IonColourFilter::getProperties(FilterPropGroup &propertyList) const
 	p.data=boolStrEnc(showColourBar);
 	p.type=PROPERTY_TYPE_BOOL;
 	propertyList.addProperty(p,curGroup);
+	
+	p.name=TRANS("Opacity");
+	p.key=KEY_IONCOLOURFILTER_ALPHA;
+	stream_cast(p.data,alpha);
+	p.type=PROPERTY_TYPE_REAL;
+	propertyList.addProperty(p,curGroup);
 
 	stream_cast(tmpStr,nColours);
 	p.name=TRANS("Num Colours");
@@ -300,6 +309,7 @@ void IonColourFilter::getProperties(FilterPropGroup &propertyList) const
 	p.key=KEY_IONCOLOURFILTER_MAPEND;
 	p.type=PROPERTY_TYPE_REAL;
 	propertyList.addProperty(p,curGroup);
+	propertyList.setGroupTitle(curGroup,TRANS("Data"));
 	
 
 }
@@ -334,18 +344,8 @@ bool IonColourFilter::setProperty(  unsigned int key,
 		}
 		case KEY_IONCOLOURFILTER_REVERSE:
 		{
-			bool newVal;
-			if(!boolStrDec(value,newVal))
+			if(!applyPropertyNow(reverseMap,value,needUpdate))
 				return false;
-
-			//Only need update if changed
-			if(newVal!=reverseMap)
-			{
-				clearCache();
-				needUpdate=true;
-			}
-
-			reverseMap=newVal;
 			break;
 		}	
 		case KEY_IONCOLOURFILTER_MAPSTART:
@@ -390,19 +390,16 @@ bool IonColourFilter::setProperty(  unsigned int key,
 		}
 		case KEY_IONCOLOURFILTER_SHOWBAR:
 		{
-			bool newVal;
-			if(!boolStrDec(value,newVal))
+			if(!applyPropertyNow(showColourBar,value,needUpdate))
 				return false;
-			//Only need update if changed
-			if(newVal!=showColourBar)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			showColourBar=newVal;
 			break;
 		}	
-
+		case KEY_IONCOLOURFILTER_ALPHA:
+		{
+			if(!applyPropertyNow(alpha,value,needUpdate))
+				return false;
+			break;
+		}
 		default:
 			ASSERT(false);
 	}	
@@ -434,7 +431,7 @@ bool IonColourFilter::writeState(std::ostream &f,unsigned int format, unsigned i
 			f << tabs(depth+1) << "<colourmap value=\"" << colourMap << "\"/>" << endl;
 			f << tabs(depth+1) << "<extrema min=\"" << mapBounds[0] << "\" max=\"" 
 				<< mapBounds[1] << "\"/>" << endl;
-			f << tabs(depth+1) << "<ncolours value=\"" << nColours << "\"/>" << endl;
+			f << tabs(depth+1) << "<ncolours value=\"" << nColours << "\" opacity=\"" << alpha << "\"/>" << endl;
 
 			f << tabs(depth+1) << "<showcolourbar value=\"" << boolStrEnc(showColourBar)<< "\"/>" << endl;
 			f << tabs(depth+1) << "<reversemap value=\"" << boolStrEnc(reverseMap)<< "\"/>" << endl;
@@ -482,6 +479,16 @@ bool IonColourFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 	if(colourMap>= NUM_COLOURMAPS)
 	       return false;	
 	xmlFree(xmlString);
+
+	if(XMLHelpGetProp(alpha, nodePtr,"opacity"))
+	{
+		alpha=1.0f;
+	}
+	else
+	{
+		//clamp alpha to [0,1]
+		alpha = std::max(0.0f,std::min(alpha,1.0f));
+	}
 	//====
 	
 	//Retrieve Extrema 
diff --git a/src/backend/filters/ionColour.h b/src/backend/filters/ionColour.h
index c57c979..8defcba 100644
--- a/src/backend/filters/ionColour.h
+++ b/src/backend/filters/ionColour.h
@@ -44,6 +44,8 @@ class IonColourFilter: public Filter
 		//!Should we display the colour bar?
 		bool showColourBar;
 
+		//Transparency value
+		float alpha;
 	public:
 		IonColourFilter();
 		//!Duplicate filter contents, excluding cache.
diff --git a/src/backend/filters/ionDownsample.cpp b/src/backend/filters/ionDownsample.cpp
index f9e7f65..6b0a174 100644
--- a/src/backend/filters/ionDownsample.cpp
+++ b/src/backend/filters/ionDownsample.cpp
@@ -28,6 +28,7 @@ enum
 {
 	IONDOWNSAMPLE_ABORT_ERR=1,
 	IONDOWNSAMPLE_BAD_ALLOC,
+	IONDOWNSAMPLE_ERR_ENUM_END
 };
 
 
@@ -268,15 +269,7 @@ unsigned int IonDownsampleFilter::refresh(const std::vector<const FilterStreamDa
 					d->valueType=((IonStreamData *)dataIn[ui])->valueType;
 
 					//getOut is const, so shouldn't be modified
-					if(cache)
-					{
-						d->cached=1;
-						filterOutputs.push_back(d);
-						cacheOK=true;
-					}
-					else
-						d->cached=0;
-			
+					cacheAsNeeded(d);
 
 					getOut.push_back(d);
 					break;
@@ -414,15 +407,7 @@ unsigned int IonDownsampleFilter::refresh(const std::vector<const FilterStreamDa
 
 
 						//getOut is const, so shouldn't be modified
-						if(cache)
-						{
-							d->cached=1;
-							filterOutputs.push_back(d);
-							cacheOK=true;
-						}
-						else
-							d->cached=0;
-			
+						cacheAsNeeded(d);
 
 						getOut.push_back(d);
 					}
@@ -475,7 +460,7 @@ void IonDownsampleFilter::getProperties(FilterPropGroup &propertyList) const
 	}	
 
 
-	propertyList.setGroupTitle(curGroup,TRANS("Sampling rates"));
+	propertyList.setGroupTitle(curGroup,TRANS("Mode"));
 	curGroup++;
 	if(rsdIncoming && perSpecies)
 	{
@@ -485,6 +470,7 @@ void IonDownsampleFilter::getProperties(FilterPropGroup &propertyList) const
 		else
 			typeVal=PROPERTY_TYPE_REAL;
 
+		bool haveProp=false;
 		//create a  single line for each
 		for(unsigned  int ui=0; ui<rsdIncoming->enabledIons.size(); ui++)
 		{
@@ -501,8 +487,12 @@ void IonDownsampleFilter::getProperties(FilterPropGroup &propertyList) const
 				p.helpText=TRANS("Sampling value for species");
 				p.key=KEY_IONDOWNSAMPLE_DYNAMIC+ui;
 				propertyList.addProperty(p,curGroup);
+				
+				haveProp=true;
 			}
 		}
+		if(haveProp)
+			propertyList.setGroupTitle(curGroup,TRANS("Sampling rates"));
 	}
 	else
 	{
@@ -526,6 +516,7 @@ void IonDownsampleFilter::getProperties(FilterPropGroup &propertyList) const
 
 		}
 		propertyList.addProperty(p,curGroup);
+		propertyList.setGroupTitle(curGroup,TRANS("Sampling rates"));
 	}
 }
 
@@ -537,21 +528,8 @@ bool IonDownsampleFilter::setProperty(  unsigned int key,
 	{
 		case KEY_IONDOWNSAMPLE_FIXEDOUT: 
 		{
-			string stripped=stripWhite(value);
-
-			bool lastVal=fixedNumOut;
-
-			if(!boolStrDec(stripped,fixedNumOut))
+			if(!applyPropertyNow(fixedNumOut,value,needUpdate))
 				return false;
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=fixedNumOut)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-
 			break;
 		}	
 		case KEY_IONDOWNSAMPLE_FRACTION:
@@ -578,38 +556,14 @@ bool IonDownsampleFilter::setProperty(  unsigned int key,
 		}
 		case KEY_IONDOWNSAMPLE_COUNT:
 		{
-			size_t count;
-
-			if(stream_cast(count,value))
+			if(!applyPropertyNow(maxAfterFilter,value,needUpdate))
 				return false;
-
-			maxAfterFilter=count;
-			//In the case of fixed number output, 
-			//our cache is invalidated
-			if(fixedNumOut)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			
 			break;
 		}	
 		case KEY_IONDOWNSAMPLE_PERSPECIES: 
 		{
-			string stripped=stripWhite(value);
-
-			bool lastVal=perSpecies;
-			if(!boolStrDec(stripped,perSpecies))
+			if(!applyPropertyNow(perSpecies,value,needUpdate))
 				return false;
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=perSpecies)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-
 			break;
 		}	
 		default:
@@ -663,15 +617,13 @@ bool IonDownsampleFilter::setProperty(  unsigned int key,
 
 std::string  IonDownsampleFilter::getErrString(unsigned int code) const
 {
-	switch(code)
-	{
-		case IONDOWNSAMPLE_ABORT_ERR:
-			return std::string(TRANS("Downsample Aborted"));
-		case IONDOWNSAMPLE_BAD_ALLOC:
-			return std::string(TRANS("Insuffient memory for downsample"));
-	}	
-
-	return std::string("BUG! Should not see this (IonDownsample)");
+	const char *errStrs[] = { "",	
+		"Downsample Aborted",
+		"Insuffient memory for downsample",
+	};	
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == IONDOWNSAMPLE_ERR_ENUM_END);
+	ASSERT(code < IONDOWNSAMPLE_ERR_ENUM_END);
+	return errStrs[code];
 }
 
 void IonDownsampleFilter::setPropFromBinding(const SelectionBinding &b)
diff --git a/src/backend/filters/ionInfo.cpp b/src/backend/filters/ionInfo.cpp
index 5b9984b..d640d9c 100644
--- a/src/backend/filters/ionInfo.cpp
+++ b/src/backend/filters/ionInfo.cpp
@@ -33,9 +33,9 @@ const char *volumeModeString[] = {
 				
 enum
 {
-	ERR_NO_MEM,
-	ERR_USER_ABORT,
-	ERR_BAD_QHULL
+	ERR_USER_ABORT=1,
+	ERR_BAD_QHULL,
+	IONINFO_ERR_ENUM_END
 };
 
 
@@ -418,6 +418,7 @@ void IonInfoFilter::getProperties(FilterPropGroup &propertyList) const
 		propertyList.addProperty(p,curGroup);
 	}
 
+	propertyList.setGroupTitle(curGroup,TRANS("Ion data"));
 	curGroup++;
 
 	stream_cast(str,wantVolume);
@@ -453,55 +454,31 @@ void IonInfoFilter::getProperties(FilterPropGroup &propertyList) const
 		}
 	
 	}
+	propertyList.setGroupTitle(curGroup,TRANS("Volume data"));
 }
 
 
 bool IonInfoFilter::setProperty(  unsigned int key,
 					const std::string &value, bool &needUpdate)
 {
-	string stripped=stripWhite(value);
 	switch(key)
 	{
 		case IONINFO_KEY_TOTALS:
 		{
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(wantIonCounts,value,needUpdate))
 				return false;
-	
-			bool newVal;
-			newVal= (value == "1");	
-
-			if(newVal == wantIonCounts)
-				return false;
-			wantIonCounts=newVal;	
-			needUpdate=true;
 			break;
 		}
 		case IONINFO_KEY_NORMALISE:
 		{
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(wantNormalise,value,needUpdate))
 				return false;
-	
-			bool newVal;
-			newVal= (value == "1");	
-
-			if(newVal == wantNormalise)
-				return false;
-			wantNormalise=newVal;	
-			needUpdate=true;
 			break;
 		}
 		case IONINFO_KEY_VOLUME:
 		{
-			if(!(stripped == "1"|| stripped == "0"))
-				return false;
-	
-			bool newVal;
-			newVal= (value == "1");	
-
-			if(newVal == wantVolume)
+			if(!applyPropertyNow(wantVolume,value,needUpdate))
 				return false;
-			wantVolume=newVal;	
-			needUpdate=true;
 			break;
 		}
 		case IONINFO_KEY_VOLUME_ALGORITHM:
@@ -533,16 +510,15 @@ bool IonInfoFilter::setProperty(  unsigned int key,
 
 std::string  IonInfoFilter::getErrString(unsigned int code) const
 {
-	switch(code)
-	{
-		case ERR_NO_MEM:
-			return string(TRANS("Insufficient memory for operation"));
-		case ERR_USER_ABORT:
-			return string(TRANS("Aborted"));
-		case ERR_BAD_QHULL:
-			return string(TRANS("Bug? Problem with qhull library, cannot run convex hull."));
-	}
-	ASSERT(false);
+	const char *errStrs[] = { "",
+		"Aborted",
+		"Bug? Problem with qhull library, cannot run convex hull.",
+	};
+	
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == IONINFO_ERR_ENUM_END);
+	ASSERT(code < IONINFO_ERR_ENUM_END);
+
+	return errStrs[code];
 }
 
 void IonInfoFilter::setPropFromBinding(const SelectionBinding &b)
@@ -664,22 +640,14 @@ bool IonInfoFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileD
 	//--
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantioncounts","value"))
 		return false;
-	if(tmpStr == "1")
-		wantIonCounts=true;
-	else if(tmpStr == "0")
-		wantIonCounts=false;
-	else
+	if(!boolStrDec(tmpStr,wantIonCounts))
 		return false;
 	//--=
 	
 	//--
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantnormalise","value"))
 		return false;
-	if(tmpStr == "1")
-		wantNormalise=true;
-	else if(tmpStr == "0")
-		wantNormalise=false;
-	else
+	if(!boolStrDec(tmpStr,wantNormalise))
 		return false;
 	//--=
 
@@ -687,11 +655,7 @@ bool IonInfoFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFileD
 	//--
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"wantvolume","value"))
 		return false;
-	if(tmpStr == "1")
-		wantVolume=true;
-	else if(tmpStr == "0")
-		wantVolume=false;
-	else
+	if(!boolStrDec(tmpStr,wantVolume))
 		return false;
 	//--=
 
diff --git a/src/backend/filters/rangeFile.cpp b/src/backend/filters/rangeFile.cpp
index 1bada94..667d917 100644
--- a/src/backend/filters/rangeFile.cpp
+++ b/src/backend/filters/rangeFile.cpp
@@ -30,13 +30,15 @@ const unsigned int NUM_ROWS_RANGE=4;
 enum
 {
 	RANGEFILE_ABORT_FAIL=1,
-	RANGEFILE_BAD_ALLOC
+	RANGEFILE_BAD_ALLOC,
+	RANGEFILE_ERR_ENUM_END
 };
 //== Range File Filter == 
 
 RangeFileFilter::RangeFileFilter()
 {
 	dropUnranged=true;
+	showLegend=false;
 	assumedFileFormat=RANGE_FORMAT_ORNL;
 }
 
@@ -467,26 +469,42 @@ unsigned int RangeFileFilter::refresh(const std::vector<const FilterStreamData *
 		//======================================
 
 		//Having ranged all streams, merge them back into one ranged stream.
-		if(cache)
-		{
-			for(unsigned int ui=0;ui<d.size(); ui++)
-			{
-				d[ui]->cached=1; //IMPORTANT: ->cached must be set PRIOR to push back
-				filterOutputs.push_back(d[ui]);
-			}
-		}
-		else
-		{
-			for(unsigned int ui=0;ui<d.size(); ui++)
-				d[ui]->cached=0; //IMPORTANT: ->cached must be set PRIOR to push back
-			cacheOK=false;
-		}
+		for(unsigned int ui=0;ui<d.size(); ui++)
+			cacheAsNeeded(d[ui]);
 		
 		for(unsigned int ui=0;ui<d.size(); ui++)
 			getOut.push_back(d[ui]);
 	}
 
+	if(haveEnabled && showLegend)
+	{
+		//Create a legend bar, which shows the ions that are present
+		DrawStreamData *dS = new DrawStreamData;
+
+		dS->parent=this;
+
+		DrawPointLegendOverlay *dl=new DrawPointLegendOverlay;
+		dl->setPosition(0.1,0.1);
+	
+		for(unsigned int ui=0;ui<enabledIons.size();ui++)
+		{	
+			if(!enabledIons[ui])
+				continue;
+
+			RGBf curRGBf;
+			curRGBf =rng.getColour(ui);
+			dl->addItem(rng.getName(ui),
+				curRGBf.red, curRGBf.green,curRGBf.blue);
+		}
+
+		dS->drawables.push_back(dl);
+		cacheAsNeeded(dS);
+
+		getOut.push_back(dS);
 
+	}
+
+	
 	//Put out rangeData
 	RangeStreamData *rngData=new RangeStreamData;
 	rngData->parent=this;
@@ -497,12 +515,8 @@ unsigned int RangeFileFilter::refresh(const std::vector<const FilterStreamData *
 	rngData->enabledIons.resize(enabledIons.size());	
 	std::copy(enabledIons.begin(),enabledIons.end(),rngData->enabledIons.begin());
 	
-	
-	rngData->cached=cache;
-	
-	if(cache)
-		filterOutputs.push_back(rngData);
 
+	cacheAsNeeded(rngData);	
 	getOut.push_back(rngData);
 		
 	cacheOK=cache;
@@ -515,15 +529,9 @@ bool RangeFileFilter::updateRng()
 		return false;
 
 	unsigned int nRng = rng.getNumRanges();
-	enabledRanges.resize(nRng);
+	enabledRanges.resize(nRng,(char)1);
 	unsigned int nIon = rng.getNumIons();
-	enabledIons.resize(nIon);
-	//Turn all ranges to "on" 
-	for(unsigned int ui=0;ui<enabledRanges.size(); ui++)
-		enabledRanges[ui]=(char)1;
-	//Turn all ions to "on" 
-	for(unsigned int ui=0;ui<enabledIons.size(); ui++)
-		enabledIons[ui]=(char)1;
+	enabledIons.resize(nIon,(char)1);
 
 	return true;
 }
@@ -533,15 +541,9 @@ void RangeFileFilter::setRangeData(const RangeFile &rngNew)
 	rng=rngNew;		
 	
 	unsigned int nRng = rng.getNumRanges();
-	enabledRanges.resize(nRng);
+	enabledRanges.resize(nRng,1);
 	unsigned int nIon = rng.getNumIons();
-	enabledIons.resize(nIon);
-	//Turn all ranges to "on" 
-	for(unsigned int ui=0;ui<enabledRanges.size(); ui++)
-		enabledRanges[ui]=(char)1;
-	//Turn all ions to "on" 
-	for(unsigned int ui=0;ui<enabledIons.size(); ui++)
-		enabledIons[ui]=(char)1;
+	enabledIons.resize(nIon,1);
 
 	clearCache();
 }
@@ -565,19 +567,18 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 	size_t curGroup=0;
 
 	prop.name=TRANS("File");
-	prop.type=PROPERTY_TYPE_STRING;
+	//Wx- acceptable string format
+	prop.type=PROPERTY_TYPE_FILE;
 	prop.helpText=TRANS("File to use for range data");
 	prop.key=RANGE_KEY_RANGE_FILENAME;
 	prop.data=rngName;
+	prop.dataSecondary=TRANS(RANGEFILE_WX_CONSTANT);
+
 
 	p.addProperty(prop,curGroup);	
 
 	std::string tmpStr;
-	if(dropUnranged)
-		tmpStr="1";
-	else
-		tmpStr="0";
-
+	tmpStr=boolStrEnc(dropUnranged);
 	prop.name=TRANS("Drop unranged");
 	prop.type=PROPERTY_TYPE_BOOL;
 	prop.helpText=TRANS("Remove unranged points when generating output");
@@ -585,8 +586,20 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 	prop.data=tmpStr;
 
 	p.addProperty(prop,curGroup);
+	p.setGroupTitle(curGroup,TRANS("File"));
 
 	curGroup++;
+
+	
+	prop.name = TRANS("Legend");
+	prop.type = PROPERTY_TYPE_BOOL;
+	prop.helpText = TRANS("Display colour legend for enabled ions");
+	prop.key= RANGE_KEY_ENABLE_LEGEND;
+	prop.data=boolStrEnc(showLegend);
+	p.addProperty(prop,curGroup);
+	p.setGroupTitle(curGroup,TRANS("View"));
+	curGroup++;
+
 	//---
 	//Option to disable/enable all ions
 	if(rng.getNumIons())
@@ -624,11 +637,8 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 
 			p.addProperty(prop,curGroup);
 
-			string str;	
-			if(enabledIons[ui])
-				str="1";
-			else
-				str="0";
+			string str;
+			str=boolStrEnc(enabledIons[ui]);
 			
 			prop.name=TRANS("Active Ion ") + suffix;
 			prop.type=PROPERTY_TYPE_BOOL;
@@ -638,16 +648,13 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 		
 			p.addProperty(prop,curGroup);
 
-			RGBf col;
-			string thisCol;
-		
+			ColourRGBAf col;
 			//Convert the ion colour to a hex string	
 			col=rng.getColour(ui);
-			genColString((unsigned char)(col.red*255),(unsigned char)(col.green*255),
-					(unsigned char)(col.blue*255),255,thisCol);
-
+			
 			prop.name=TRANS("Colour ") + suffix;
-			prop.data=thisCol;
+			prop.data=col.toColourRGBA().rgbaString();
+
 			prop.type=PROPERTY_TYPE_COLOUR;
 			prop.helpText=TRANS("Colour used to represent ion");
 			prop.key=NUM_ROWS_ION*ui+3+RANGE_KEY_ENABLE_ALL_IONS;
@@ -655,12 +662,11 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			p.addProperty(prop,curGroup);
 		}
 
+		p.setGroupTitle(curGroup,TRANS("Ions"));
+		curGroup++;
 	}
 	//----
 
-
-	curGroup++;
-
 	//----
 	if(rng.getNumRanges())
 	{
@@ -686,11 +692,8 @@ void RangeFileFilter::getProperties(FilterPropGroup &p) const
 			std::string suffix;
 			stream_cast(suffix,ui);
 
-			string str;	
-			if(enabledRanges[ui])
-				str="1";
-			else
-				str="0";
+			string str;
+			str=boolStrEnc(enabledRanges[ui]);
 
 			prop.name=TRANS("Active Rng ")+suffix;
 			prop.data=str;
@@ -773,37 +776,21 @@ bool RangeFileFilter::setProperty(unsigned int key,
 		}
 		case RANGE_KEY_DROP_UNRANGED: //Enable/disable unranged dropping
 		{
-			unsigned int valueInt;
-			if(stream_cast(valueInt,value))
+			if(!applyPropertyNow(dropUnranged,value,needUpdate))
+				return false;
+			break;
+		}	
+		case RANGE_KEY_ENABLE_LEGEND:
+		{
+			if(!applyPropertyNow(showLegend,value,needUpdate))
 				return false;
-
-			if(valueInt ==0 || valueInt == 1)
-			{
-				if(dropUnranged!= (bool)valueInt)
-				{
-					needUpdate=true;
-					dropUnranged=valueInt;
-				}
-				else
-					needUpdate=false;
-			}
-			else
-				return false;		
-			
-			if(needUpdate)
-				clearCache();
-
 			break;
 		}	
 		case RANGE_KEY_ENABLE_ALL_RANGES:
 		{
 
 			bool allEnable;
-			if(value == "1")
-				allEnable=true;
-			else if ( value == "0")
-				allEnable=false;
-			else
+			if(!boolStrDec(value,allEnable))
 				return false;
 
 			//set them to the opposite of whatever we have now
@@ -826,11 +813,7 @@ bool RangeFileFilter::setProperty(unsigned int key,
 		{
 
 			bool allEnable;
-			if(value == "1")
-				allEnable=true;
-			else if ( value == "0")
-				allEnable=false;
-			else
+			if(!boolStrDec(value,allEnable))
 				return false;
 
 			//set them to the opposite of whatever we have now
@@ -902,15 +885,9 @@ bool RangeFileFilter::setProperty(unsigned int key,
 					}	
 					case 2: //Colour of the ion
 					{
-						unsigned char r,g,b,a;
-						parseColString(value,r,g,b,a);
-
-						RGBf newCol;
-						newCol.red=(float)r/255.0f;
-						newCol.green=(float)g/255.0f;
-						newCol.blue=(float)b/255.0f;
-
-						rng.setColour(ionID,newCol);
+						ColourRGBA rgba;
+						rgba.parse(value);
+						rng.setColour(ionID,rgba.toRGBAf().toRGBf());
 						needUpdate=true;
 						break;
 					}
@@ -1023,15 +1000,15 @@ bool RangeFileFilter::setProperty(unsigned int key,
 
 std::string  RangeFileFilter::getErrString(unsigned int code) const
 {
-	switch(code)
-	{
-		case RANGEFILE_ABORT_FAIL:
-			return std::string(TRANS("Ranging aborted by user"));
-		case RANGEFILE_BAD_ALLOC:
-			return std::string(TRANS("Insufficient memory for range"));
-	}
+	const char *errStrs[] ={ "",
+		"Ranging aborted by user",
+		"Insufficient memory for range",
+	};
+
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == RANGEFILE_ERR_ENUM_END);
+	ASSERT(code < RANGEFILE_ERR_ENUM_END);
 
-	return std::string("BUG(range file filter): Shouldn't see this!");
+	return errStrs[code];
 }
 
 void RangeFileFilter::setPropFromBinding(const SelectionBinding &b)
@@ -1057,18 +1034,17 @@ bool RangeFileFilter::writeState(std::ostream &f,unsigned int format, unsigned i
 			f << tabs(depth+1) << "<userstring value=\""<< escapeXML(userString) << "\"/>"  << endl;
 
 			f << tabs(depth+1) << "<file name=\""<< escapeXML(convertFileStringToCanonical(rngName)) << "\"/>"  << endl;
+			f << tabs(depth+1) << "<legend enabled=\""<< boolStrEnc(showLegend) << "\"/>"  << endl;
 			f << tabs(depth+1) << "<dropunranged value=\""<<(int)dropUnranged<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<enabledions>"<< endl;
 			for(unsigned int ui=0;ui<enabledIons.size();ui++)
 			{
-				RGBf col;
-				string colourString;
+				ColourRGBAf col;
 				col = rng.getColour(ui);
 
-				genColString((unsigned char)(col.red*255),(unsigned char)(col.green*255),
-						(unsigned char)(col.blue*255),255,colourString);
+				
 				f<< tabs(depth+2) << "<ion id=\"" << ui << "\" enabled=\"" 
-					<< (int)enabledIons[ui] << "\" colour=\"" << colourString << "\"/>" << endl;
+					<< (int)enabledIons[ui] << "\" colour=\"" << col.toColourRGBA().rgbString()<< "\"/>" << endl;
 			}
 			f << tabs(depth+1) << "</enabledions>"<< endl;
 
@@ -1118,7 +1094,7 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 	rngName=(char *)xmlString;
 	xmlFree(xmlString);
 
-	//Override the string, as needed
+	//Override the string to strip leading ./ notation, as needed
 	if( (stateFileDir.size()) &&
 		(rngName.size() > 2 && rngName.substr(0,2) == "./") )
 	{
@@ -1132,18 +1108,28 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 		return false;
 		
 	//==
-	
+
+
+	//TODO: Deprecate me. Did not exist prior to 0.0.17/
+	// internal 3e88134daeea
+	xmlNodePtr tmpNode=nodePtr;
+	if(!XMLHelpFwdToElem(tmpNode,"legend"))
+	{
+		if(XMLHelpGetProp(showLegend,tmpNode,"enabled"))
+		{
+			return false;
+		}
+	}
+	else
+		showLegend=false;
+
 	std::string tmpStr;
-	//Retrieve user string
+	//Retrieve range status 
 	//==
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"dropunranged","value"))
 		return false;
-	
-	if(tmpStr=="1")
-		dropUnranged=true;
-	else if(tmpStr=="0")
-		dropUnranged=false;
-	else
+
+	if(!boolStrDec(tmpStr,dropUnranged))
 		return false;
 
 	//==
@@ -1153,7 +1139,7 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 	//===
 	if(XMLHelpFwdToElem(nodePtr,"enabledions"))
 		return false;
-	xmlNodePtr tmpNode=nodePtr;
+	tmpNode=nodePtr;
 
 	nodePtr=nodePtr->xmlChildrenNode;
 
@@ -1161,7 +1147,7 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 	bool enabled;
 	//By default, turn ions off, but use state file to turn them on
 	map<unsigned int ,char> tmpEnabledIons;
-	map<unsigned int, RGBf> tmpCol;
+	map<unsigned int ,RGBf> tmpCol;
 	while(!XMLHelpFwdToElem(nodePtr,"ion"))
 	{
 		//Get ID value
@@ -1183,13 +1169,8 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 			return false;
 		tmpStr=(char *)xmlString;
 
-		if(tmpStr == "0")
-			enabled=false;
-		else if(tmpStr == "1")
-			enabled=true;
-		else
+		if(!boolStrDec(tmpStr,enabled))
 			return false;
-
 		tmpEnabledIons[ionID]=enabled;
 		xmlFree(xmlString);
 		
@@ -1201,15 +1182,11 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 
 		tmpStr=(char *)xmlString;
 
-		unsigned char r,g,b,a;
-		if(!parseColString(tmpStr,r,g,b,a))
+		ColourRGBA rgbaTmp;
+		if(!rgbaTmp.parse(tmpStr))
 			return false;
 		
-		RGBf col;
-		col.red=(float)r/255.0f;
-		col.green=(float)g/255.0f;
-		col.blue=(float)b/255.0f;
-		tmpCol[ionID]=col;	
+		tmpCol[ionID]=rgbaTmp.toRGBAf().toRGBf();	
 		xmlFree(xmlString);
 	}
 
@@ -1250,11 +1227,7 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 			return false;
 		tmpStr=(char *)xmlString;
 
-		if(tmpStr == "0")
-			enabled=false;
-		else if(tmpStr == "1")
-			enabled=true;
-		else
+		if(!boolStrDec(tmpStr,enabled))
 			return false;
 
 		xmlFree(xmlString);
@@ -1271,7 +1244,11 @@ bool RangeFileFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFil
 	if(tmpEnabledIons.size() == rng.getNumIons())
 	{
 		for(size_t ui=0;ui<tmpEnabledIons.size(); ui++)
+		{
 			enabledIons[ui] = tmpEnabledIons[ui];
+			rng.setColour(ui,tmpCol[ui]);
+			
+		}
 		
 		for(size_t ui=0;ui<tmpEnabledRanges.size(); ui++)
 			enabledRanges[ui] = tmpEnabledRanges[ui];
@@ -1291,7 +1268,10 @@ unsigned int RangeFileFilter::getRefreshBlockMask() const
 
 unsigned int RangeFileFilter::getRefreshEmitMask() const
 {
-	return STREAM_TYPE_RANGE | STREAM_TYPE_IONS ;
+	unsigned int retmask=  STREAM_TYPE_RANGE | STREAM_TYPE_IONS;
+	if(showLegend)
+		retmask |= STREAM_TYPE_DRAW;
+	return retmask;
 }
 
 unsigned int RangeFileFilter::getRefreshUseMask() const
diff --git a/src/backend/filters/rangeFile.h b/src/backend/filters/rangeFile.h
index 57e6d51..f8190d9 100644
--- a/src/backend/filters/rangeFile.h
+++ b/src/backend/filters/rangeFile.h
@@ -26,6 +26,7 @@ enum
 	RANGE_KEY_RANGE_ACTIVE=1,
 	RANGE_KEY_DROP_UNRANGED,
 	RANGE_KEY_RANGE_FILENAME,
+	RANGE_KEY_ENABLE_LEGEND,
 	RANGE_KEY_ENABLE_ALL_IONS, //Limited to ~100K ions
 	RANGE_KEY_ENABLE_ALL_RANGES=100000,
 };
@@ -51,6 +52,9 @@ class RangeFileFilter : public Filter
 		//!range file object 
 		RangeFile rng;
 
+		//Show a legend of enabled ions
+		bool showLegend;
+
 	public:
 
 		//!Set the format to assume when loading file
diff --git a/src/backend/filters/spatialAnalysis.cpp b/src/backend/filters/spatialAnalysis.cpp
index dc98e01..b0fdb44 100644
--- a/src/backend/filters/spatialAnalysis.cpp
+++ b/src/backend/filters/spatialAnalysis.cpp
@@ -23,7 +23,9 @@
 #include "geometryHelpers.h"
 #include "filterCommon.h"
 #include "algorithms/binomial.h"
-
+#include "algorithms/K3DTree-mk2.h"
+#include "backend/plot.h"
+#include "../APT/APTFileIO.h"
 
 enum
 {
@@ -31,6 +33,7 @@ enum
 	KEY_ALGORITHM,
 	KEY_DISTMAX,
 	KEY_NNMAX,
+	KEY_NNMAX_NORMALISE,
 	KEY_NUMBINS,
 	KEY_REMOVAL,
 	KEY_REDUCTIONDIST,
@@ -49,6 +52,10 @@ enum
 	KEY_SHOW_BINOM_3D_GRID,
 	KEY_BINOMIAL_MAX_ASPECT,
 	KEY_BINOMIAL_EXTRUDE_DIR,
+	KEY_REPLACE_FILE,
+	KEY_REPLACE_TOLERANCE,
+	KEY_REPLACE_ALGORITHM,
+	KEY_REPLACE_VALUE,
 };
 
 enum {
@@ -57,6 +64,7 @@ enum {
 	ALGORITHM_RDF, //Radial Distribution Function
 	ALGORITHM_AXIAL_DF, //Axial Distribution Function (aka atomvicinity, sdm, 1D rdf)
 	ALGORITHM_BINOMIAL, //Binomial block method for statistical randomness testing
+	ALGORITHM_REPLACE, //Remove, set or modify points using an external file
 	ALGORITHM_ENUM_END,
 };
 
@@ -66,14 +74,23 @@ enum{
 	STOP_MODE_ENUM_END
 };
 
+enum
+{
+	REPLACE_MODE_SUBTRACT,
+	REPLACE_MODE_INTERSECT,
+	REPLACE_MODE_UNION,
+	REPLACE_MODE_ENUM_END
+};
+
 //!Error codes
 enum
 {
-	ABORT_ERR=1,
+	ERR_ABORT_FAIL=1,
 	ERR_BINOMIAL_NO_MEM,
 	ERR_BINOMIAL_NO_RANGE,
 	ERR_BINOMIAL_BIN_FAIL,
 	INSUFFICIENT_SIZE_ERR,
+	ERR_FILE_READ_FAIL,
 	SPAT_ERR_END_OF_ENUM,
 };
 // == NN analysis filter ==
@@ -85,7 +102,8 @@ const char *SPATIAL_ALGORITHMS[] = {
 	NTRANS("Density Filtering"),
 	NTRANS("Radial Distribution"),
 	NTRANS("Axial Distribution"),
-	NTRANS("Binomial Distribution")
+	NTRANS("Binomial Distribution"),
+	NTRANS("Point Em/Replacement")
 	};
 
 const char *STOP_MODES[] = {
@@ -93,12 +111,20 @@ const char *STOP_MODES[] = {
 	NTRANS("Radius")
 };
 
+//User viisble names for the replace sub-algorithms
+const char *REPLACE_ALGORITHMS[] = { "Subtract",
+					"Intersect",
+					"Union",
+					};
+					
+
 //Switch to determine if algorithms need range propagation or not
 const bool WANT_RANGE_PROPAGATION[] = { false, 
 					true,
 					false,
 					false,
-					false
+					false,
+					true,
 					};
 
 
@@ -118,6 +144,9 @@ SpatialAnalysisFilter::SpatialAnalysisFilter()
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(STOP_MODES) == STOP_MODE_ENUM_END);
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(SPATIAL_ALGORITHMS) == ALGORITHM_ENUM_END);
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(WANT_RANGE_PROPAGATION) == ALGORITHM_ENUM_END);
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(REPLACE_ALGORITHMS) == REPLACE_MODE_ENUM_END);
+	
+	
 	algorithm=ALGORITHM_DENSITY;
 	nnMax=1;
 	distMax=1;
@@ -126,13 +155,13 @@ SpatialAnalysisFilter::SpatialAnalysisFilter()
 	haveRangeParent=false;
 	
 	//Default colour is red
-	r=a=1.0f;
-	g=b=0.0f;
+	rgba=ColourRGBAf(1.0f,0,0);
 
 	//RDF params
 	numBins=100;
 	excludeSurface=false;
-
+	reductionDistance=distMax;
+	normaliseNNHist=true;
 	//Density filtering params
 	densityCutoff=1.0f;
 	keepDensityUpper=true;
@@ -148,7 +177,10 @@ SpatialAnalysisFilter::SpatialAnalysisFilter()
 	showGridOverlay=true;
 	//--
 
-	reductionDistance=distMax;
+	//replace tolerance
+	replaceTolerance=sqrt(std::numeric_limits<float>::epsilon());
+	replaceMode=REPLACE_MODE_SUBTRACT;
+	replaceMass=true;
 
 	cacheOK=false;
 	cache=true; //By default, we should cache, but decision is made higher up
@@ -159,10 +191,7 @@ Filter *SpatialAnalysisFilter::cloneUncached() const
 {
 	SpatialAnalysisFilter *p=new SpatialAnalysisFilter;
 
-	p->r=r;
-	p->g=g;
-	p->b=b;
-	p->a=a;
+	p->rgba=rgba;
 	
 	p->algorithm=algorithm;
 	p->stopMode=stopMode;
@@ -185,6 +214,11 @@ Filter *SpatialAnalysisFilter::cloneUncached() const
 	p->showTheoreticFrequencies=showTheoreticFrequencies;
 	p->showGridOverlay=showGridOverlay;
 
+	p->replaceFile=replaceFile;
+	p->replaceMode=replaceMode;
+	p->replaceTolerance=replaceTolerance;
+	p->replaceMass=replaceMass;
+
 	//We are copying whether to cache or not,
 	//not the cache itself
 	p->cache=cache;
@@ -280,7 +314,7 @@ unsigned int SpatialAnalysisFilter::refresh(const std::vector<const FilterStream
 	if(cacheOK)
 	{
 		size_t mask=STREAM_TYPE_IONS;
-		if(WANT_RANGE_PROPAGATION[algorithm])
+		if(!WANT_RANGE_PROPAGATION[algorithm])
 			mask|=STREAM_TYPE_RANGE;
 
 		//Propagate input streams as desired 
@@ -348,6 +382,10 @@ unsigned int SpatialAnalysisFilter::refresh(const std::vector<const FilterStream
 						dataIn,getOut,rngF);
 			break;
 		}
+		case ALGORITHM_REPLACE:
+			result=algorithmReplace(progress,callback,totalDataSize,
+						dataIn,getOut);
+			break;
 		default:
 			ASSERT(false);
 	}
@@ -355,6 +393,136 @@ unsigned int SpatialAnalysisFilter::refresh(const std::vector<const FilterStream
 	return result;
 }
 
+size_t SpatialAnalysisFilter::algorithmReplace(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, 
+			const vector<const FilterStreamData *>  &dataIn, 
+			vector<const FilterStreamData * > &getOut)
+{
+	//Merge the ions form the incoming streams
+	vector<IonHit> inIons;
+	Filter::collateIons(dataIn,inIons,progress,callback,totalDataSize);
+	
+	vector<IonHit> fileIons;
+	const unsigned int loadPositions[] = {
+						0,1,2,3};
+	unsigned int errCode=GenericLoadFloatFile(4,4,loadPositions,
+			fileIons,replaceFile.c_str(),progress.filterProgress,callback);
+
+	if(errCode)
+		return ERR_FILE_READ_FAIL;
+
+
+	K3DTreeMk2 tree;
+	tree.setProgressPointer(&progress.filterProgress);
+	tree.setCallback(callback);
+	tree.resetPts(fileIons,false);
+	tree.build();
+	BoundCube b;
+	tree.getBoundCube(b);
+
+	//map the offset of the nearest to
+	//the tree ID 
+	vector<size_t > nearestVec;
+	nearestVec.resize(inIons.size());
+
+	//TODO: pair vector might be faster
+	// as we can use it in sequence, and can use openmp
+	map<size_t,size_t> matchedMap;
+
+	#pragma omp parallel
+	{
+	//Find the nearest point for all points in the dataset
+
+	#pragma omp for 
+	for(size_t ui=0;ui<inIons.size();ui++)
+	{
+		nearestVec[ui]=tree.findNearestUntagged(inIons[ui].getPos(),b,false);
+	}
+
+	//Filter this to only points that had an NN within range
+	for(size_t ui=0;ui<inIons.size();ui++)
+	{
+		if(nearestVec[ui]!=(size_t)-1 && inIons[ui].getPos().sqrDist(*tree.getPt(nearestVec[ui])) <=replaceTolerance)
+		{
+			#pragma omp critical
+			matchedMap[ui]=nearestVec[ui];
+		}
+	}
+	}
+
+	nearestVec.clear();
+
+	if(matchedMap.empty())
+		return 1;
+
+	vector<IonHit> outIons;
+	switch(replaceMode)
+	{
+		case REPLACE_MODE_SUBTRACT:
+		{
+			//In subtraction mode, we should have
+			// at least this many ions
+			if(inIons.size() > matchedMap.size())
+				outIons.reserve(inIons.size()-matchedMap.size());
+			
+			//
+			#pragma omp parallel for
+			for(unsigned int ui=0;ui<inIons.size();ui++)
+			{
+				map<size_t,size_t>::iterator it;
+				it=matchedMap.find(ui);
+				if(it != matchedMap.end())
+					continue;
+
+				#pragma omp critical
+				outIons.push_back(inIons[ui]);
+			}
+			break;
+		}
+		case REPLACE_MODE_INTERSECT:
+		{
+			outIons.reserve(matchedMap.size());
+
+			if(replaceMass)
+			{
+				for(map<size_t,size_t>::const_iterator it=matchedMap.begin();it!=matchedMap.end();++it)
+				{
+					outIons.push_back(fileIons[it->second]);
+				}
+			}
+			else
+			{
+				for(map<size_t,size_t>::const_iterator it=matchedMap.begin();it!=matchedMap.end();++it)
+				{
+					outIons.push_back(inIons[it->first]);
+				}
+			}
+			break;
+		}
+		case REPLACE_MODE_UNION:
+		{
+			ASSERT(false);
+			break;
+		}
+		default:
+			ASSERT(false);
+	}
+
+	//Only output ions if any were found
+	if(outIons.size())
+	{
+		IonStreamData *outData = new IonStreamData(this);
+
+		outData->g = outData->b = outData->r = 0.5;
+		outData->data.swap(outIons);
+		cacheAsNeeded(outData);
+
+
+		getOut.push_back(outData);
+	}
+
+	return 0;
+}
+
 void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 {
 	FilterProperty p;
@@ -378,6 +546,7 @@ void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 	propertyList.addProperty(p,curGroup);
 	choices.clear();
 
+	propertyList.setGroupTitle(curGroup,TRANS("Algorithm"));
 	curGroup++;
 	
 	//Get the options for the current algorithm
@@ -410,6 +579,16 @@ void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 			p.type=PROPERTY_TYPE_INTEGER;
 			p.helpText=TRANS("Maximum number of neighbours to examine");
 			p.key=KEY_NNMAX;
+			if(algorithm == ALGORITHM_RDF)
+			{
+				propertyList.addProperty(p,curGroup);
+
+				p.name=TRANS("Normalise bins");
+				p.data=boolStrEnc(normaliseNNHist);
+				p.type=PROPERTY_TYPE_BOOL;
+				p.helpText=TRANS("Normalise counts by binwidth. Needed when comparing NN histograms against one another");
+				p.key=KEY_NNMAX_NORMALISE;
+			}
 		}
 		else
 		{
@@ -460,16 +639,14 @@ void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 				
 			string thisCol;
 			//Convert the ion colour to a hex string	
-			genColString((unsigned char)(r*255),(unsigned char)(g*255),
-					(unsigned char)(b*255),(unsigned char)(a*255),thisCol);
-
 			p.name=TRANS("Plot colour ");
-			p.data=thisCol; 
+			p.data=rgba.toColourRGBA().rgbaString();
 			p.type=PROPERTY_TYPE_COLOUR;
 			p.helpText=TRANS("Colour of output plot");
 			p.key=KEY_COLOUR;
 			propertyList.addProperty(p,curGroup);
 
+			propertyList.setGroupTitle(curGroup,TRANS("Alg. Params."));
 			if(haveRangeParent)
 			{
 				ASSERT(ionSourceEnabled.size() == ionNames.size());
@@ -506,6 +683,8 @@ void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 					p.key=KEY_ENABLE_SOURCE*1000+ui;
 					propertyList.addProperty(p,curGroup);
 				}
+				
+				propertyList.setGroupTitle(curGroup,TRANS("Source Ion"));
 
 				curGroup++;
 				
@@ -535,10 +714,10 @@ void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 					p.key=KEY_ENABLE_TARGET*1000+ui;
 					propertyList.addProperty(p,curGroup);
 				}
+				propertyList.setGroupTitle(curGroup,TRANS("Target Ion"));
 
 			}
 	
-			propertyList.setGroupTitle(curGroup,TRANS("Alg. Params."));
 			break;
 		}	
 		case ALGORITHM_DENSITY_FILTER:
@@ -579,13 +758,9 @@ void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 			p.key=KEY_NUMBINS;
 			propertyList.addProperty(p,curGroup);
 			
-			string thisCol;
-			//Convert the ion colour to a hex string	
-			genColString((unsigned char)(r*255),(unsigned char)(g*255),
-					(unsigned char)(b*255),(unsigned char)(a*255),thisCol);
-
+			
 			p.name=TRANS("Plot colour ");
-			p.data=thisCol; 
+			p.data=rgba.toColourRGBA().rgbString(); 
 			p.type=PROPERTY_TYPE_COLOUR;
 			p.helpText=TRANS("Colour of output plot");
 			p.key=KEY_COLOUR;
@@ -700,6 +875,54 @@ void SpatialAnalysisFilter::getProperties(FilterPropGroup &propertyList) const
 			propertyList.setGroupTitle(curGroup,TRANS("View Options"));
 			break;	
 		}
+		case ALGORITHM_REPLACE:
+		{
+			tmpStr = replaceFile;
+			p.name=TRANS("Data File");
+			p.data=tmpStr;
+			p.dataSecondary="Pos File (*.pos)|*.pos|All Files|*";
+			p.type=PROPERTY_TYPE_FILE;
+			p.helpText=TRANS("Pos file of points to subtract/replace/etc");
+			p.key=KEY_REPLACE_FILE;
+			propertyList.addProperty(p,curGroup);
+		
+			stream_cast(tmpStr,replaceTolerance);
+			p.name=TRANS("Match Tol.");
+			p.data=tmpStr;
+			p.type=PROPERTY_TYPE_REAL;
+			p.helpText=TRANS("Tolerance to allow for matching");
+			p.key=KEY_REPLACE_TOLERANCE;
+			propertyList.addProperty(p,curGroup);
+		
+	
+			vector<pair<unsigned int,string> > choices;
+
+			for(unsigned int ui=0;ui<REPLACE_MODE_ENUM_END;ui++)
+			{
+				tmpStr=TRANS(REPLACE_ALGORITHMS[ui]);
+				choices.push_back(make_pair(ui,tmpStr));
+			}	
+		
+			p.name=TRANS("Mode");
+			p.data= choiceString(choices,replaceMode);
+			p.type=PROPERTY_TYPE_CHOICE;
+			p.helpText=TRANS("Replacment condition");
+			p.key=KEY_REPLACE_ALGORITHM;
+			propertyList.addProperty(p,curGroup);
+
+			if(replaceMode != REPLACE_MODE_SUBTRACT)
+			{
+				p.name=TRANS("Replace value");
+				p.data=boolStrEnc(replaceMass);
+				p.type=PROPERTY_TYPE_BOOL;
+				p.helpText=TRANS("Use value data from file when replacing ions");
+				p.key=KEY_REPLACE_VALUE;
+				propertyList.addProperty(p,curGroup);
+			}
+
+			propertyList.setGroupTitle(curGroup,TRANS("Replacement"));
+			break;
+		}
 		default:
 			ASSERT(false);
 	}
@@ -803,6 +1026,12 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 
 			break;
 		}	
+		case KEY_NNMAX_NORMALISE:
+		{
+			if(!applyPropertyNow(normaliseNNHist,value,needUpdate))
+				return false;
+			break;
+		}	
 		case KEY_NUMBINS:
 		{
 			unsigned int ltmp;
@@ -835,37 +1064,21 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 		}	
 		case KEY_REMOVAL:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(excludeSurface,value,needUpdate))
 				return false;
-
-			bool lastVal=excludeSurface;
-			excludeSurface=(stripped=="1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=excludeSurface)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			
 			break;
 		}
 		case KEY_COLOUR:
 		{
-			unsigned char newR,newG,newB,newA;
+			ColourRGBA tmpRgba;
 
-			parseColString(value,newR,newG,newB,newA);
+			if(!tmpRgba.parse(value))
+				return false;
 
-			if(newB != b || newR != r ||
-				newG !=g || newA != a)
+			
+			if(rgba.toColourRGBA() != tmpRgba)
 			{
-				r=newR/255.0;
-				g=newG/255.0;
-				b=newB/255.0;
-				a=newA/255.0;
+				rgba=tmpRgba.toRGBAf();
 
 				if(cacheOK)
 				{
@@ -876,9 +1089,9 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 							PlotStreamData *p;
 							p =(PlotStreamData*)filterOutputs[ui];
 
-							p->r=r;
-							p->g=g;
-							p->b=b;
+							p->r=rgba.r();
+							p->g=rgba.g();
+							p->b=rgba.b();
 						}
 					}
 
@@ -957,22 +1170,8 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 		}
 		case KEY_RETAIN_UPPER:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(keepDensityUpper,value,needUpdate))
 				return false;
-
-			bool lastVal=keepDensityUpper;
-			keepDensityUpper=(stripped=="1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=keepDensityUpper)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			
 			break;
 		}
 		case KEY_RADIUS:
@@ -1011,17 +1210,8 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 		}
 		case KEY_ORIGIN:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(vectorParams[0],value,needUpdate))
 				return false;
-
-			if(!(vectorParams[0] == newPt ))
-			{
-				vectorParams[0] = newPt;
-				needUpdate=true;
-				clearCache();
-			}
-
 			return true;
 		}
 		case KEY_NUMIONS:
@@ -1041,59 +1231,20 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 		}
 		case KEY_SHOW_BINOM_FREQ:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(showBinomialFrequencies,value,needUpdate))
 				return false;
-
-			bool lastVal=showBinomialFrequencies;
-			showBinomialFrequencies=(stripped=="1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=showBinomialFrequencies)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			
 			break;
 		}
 		case KEY_SHOW_BINOM_NORM_FREQ:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(showNormalisedBinomialFrequencies,value,needUpdate))
 				return false;
-
-			bool lastVal=showNormalisedBinomialFrequencies;
-			showNormalisedBinomialFrequencies=(stripped=="1");
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=showNormalisedBinomialFrequencies)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			
 			break;
 		}
 		case KEY_SHOW_BINOM_THEOR_FREQ:
 		{
-			bool lastVal=showTheoreticFrequencies;
-			
-			if(!boolStrDec(value,showTheoreticFrequencies))
+			if(!applyPropertyNow(showTheoreticFrequencies,value,needUpdate))
 				return false;
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=showTheoreticFrequencies)
-			{
-				needUpdate=true;
-				clearCache();
-			}
-			
 			break;
 		}
 		case KEY_BINOMIAL_MAX_ASPECT:
@@ -1131,20 +1282,52 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 		}
 		case KEY_SHOW_BINOM_3D_GRID:
 		{
-			bool lastVal=showGridOverlay;
-			if(!boolStrDec(value,showGridOverlay))
+			if(!applyPropertyNow(showGridOverlay,value,needUpdate))
 				return false;
 
-			//if the result is different, the
-			//cache should be invalidated
-			if(lastVal!=showGridOverlay)
+			break;
+		}
+		case KEY_REPLACE_FILE:
+		{
+			if(!applyPropertyNow(replaceFile,value,needUpdate))
+				return false;
+			break;
+		}
+		case KEY_REPLACE_TOLERANCE:
+		{
+			if(!applyPropertyNow(replaceTolerance,value,needUpdate))
+				return false;
+			break;
+		}
+		case KEY_REPLACE_ALGORITHM:
+		{
+			size_t newVal=REPLACE_MODE_ENUM_END;
+			for(size_t ui=0;ui<REPLACE_MODE_ENUM_END; ui++)
+			{
+				if( value == TRANS(REPLACE_ALGORITHMS[ui]))
+				{
+					newVal=ui;
+					break;
+				}
+			}
+			if(newVal==REPLACE_MODE_ENUM_END)
+				return false;
+
+			if(replaceMode != newVal)
 			{
 				needUpdate=true;
 				clearCache();
+				replaceMode=newVal;
 			}
-			
 			break;
 		}
+		case KEY_REPLACE_VALUE:
+		{
+			if(!applyPropertyNow(replaceMass,value,needUpdate))
+				return false;
+			break;
+			
+		}
 		default:
 		{
 			ASSERT(haveRangeParent);
@@ -1218,33 +1401,26 @@ bool SpatialAnalysisFilter::setProperty(  unsigned int key,
 
 std::string  SpatialAnalysisFilter::getErrString(unsigned int code) const
 {
-	//Currently the only error is aborting
-
-
-	switch(code)
-	{
-		case ABORT_ERR:
-			return std::string(TRANS("Spatial analysis aborted by user"));
-		case INSUFFICIENT_SIZE_ERR:
-			return std::string(TRANS("Insufficient data to complete analysis."));
-		case ERR_BINOMIAL_BIN_FAIL:
-			return std::string(TRANS("Insufficient bins in histogram for analysis."));
-		case ERR_BINOMIAL_NO_MEM:
-			return std::string(TRANS("Insufficient memory for binomial. Reduce input size?"));
-		case ERR_BINOMIAL_NO_RANGE:
-			return std::string(TRANS("Binomial requires a parent range file"));
-		default:
-			ASSERT(false);
-
-	}
+	const char *errStrings[] = {"",
+				"Spatial analysis aborted by user",
+				"Insufficient memory to complete analysis",
+				"Insufficient bins in histogram for analysis",
+				"Insufficient memory for binomial. Reduce input size?",
+				"Binomial requires a parent range file",
+				"File read failed",
+				};
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrings) == SPAT_ERR_END_OF_ENUM);
+	
+	
+	ASSERT(code < SPAT_ERR_END_OF_ENUM);
 
-	return std::string("Bug! (Spatial analysis filter) Shouldn't see this");
+	return std::string(errStrings[code]);
 }
 
 void SpatialAnalysisFilter::setUserString(const std::string &str)
 {
 	//Which algorithms have plot outputs?
-	const bool ALGORITHM_HAS_PLOTS[] = { false,false,true,true,true};
+	const bool ALGORITHM_HAS_PLOTS[] = { false,false,true,true,true,false};
 
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(ALGORITHM_HAS_PLOTS) == ALGORITHM_ENUM_END);
 
@@ -1299,14 +1475,19 @@ bool SpatialAnalysisFilter::writeState(std::ostream &f,unsigned int format, unsi
 			f << tabs(depth+1) << "<algorithm value=\""<<algorithm<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<stopmode value=\""<<stopMode<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<nnmax value=\""<<nnMax<< "\"/>"  << endl;
+			f << tabs(depth+1) << "<normalisennhist value=\""<<boolStrEnc(normaliseNNHist)<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<distmax value=\""<<distMax<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<numbins value=\""<<numBins<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<excludesurface value=\""<<excludeSurface<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<reductiondistance value=\""<<reductionDistance<< "\"/>"  << endl;
-			f << tabs(depth+1) << "<colour r=\"" <<  r<< "\" g=\"" << g << "\" b=\"" <<b
-				<< "\" a=\"" << a << "\"/>" <<endl;
+			f << tabs(depth+1) << "<colour r=\"" <<  rgba.r() << "\" g=\"" << rgba.g() << "\" b=\"" <<rgba.b()
+				<< "\" a=\"" << rgba.a() << "\"/>" <<endl;
+			
 			f << tabs(depth+1) << "<densitycutoff value=\""<<densityCutoff<< "\"/>"  << endl;
 			f << tabs(depth+1) << "<keepdensityupper value=\""<<(int)keepDensityUpper<< "\"/>"  << endl;
+			
+			f << tabs(depth+1) << "<replace file=\""<<replaceFile << "\" mode=\"" << replaceMode 
+				<< "\" tolerance=\"" << replaceTolerance <<  "\" replacemass=\"" << boolStrEnc(replaceMass) << "\" />"  << endl;
 
 
 			//-- Binomial paramters ---
@@ -1322,11 +1503,11 @@ bool SpatialAnalysisFilter::writeState(std::ostream &f,unsigned int format, unsi
 			//--------------------------
 
 			
-			writeVectorsXML(f,"vectorparams",vectorParams,depth);
-			writeScalarsXML(f,"scalarparams",scalarParams,depth);
+			writeVectorsXML(f,"vectorparams",vectorParams,depth+1);
+			writeScalarsXML(f,"scalarparams",scalarParams,depth+1);
 			
-			writeIonsEnabledXML(f,"source",ionSourceEnabled,ionNames,depth);
-			writeIonsEnabledXML(f,"target",ionTargetEnabled,ionNames,depth);
+			writeIonsEnabledXML(f,"source",ionSourceEnabled,ionNames,depth+1);
+			writeIonsEnabledXML(f,"target",ionTargetEnabled,ionNames,depth+1);
 
 			f << tabs(depth) << "</" << trueName() << ">" << endl;
 			break;
@@ -1380,6 +1561,17 @@ bool SpatialAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &st
 		return false;
 	//===
 	
+	//Retrieve histogram normalisation 
+	//TODO: COMPAT : did not exist prior to 0.0.17
+	// internal 5033191f0c61
+	//====== 
+	xmlNodePtr tmpNode = nodePtr;
+	if(!XMLGetNextElemAttrib(tmpNode,nnMax,"normalisennhist","value"))
+	{
+		normaliseNNHist=false;
+	}
+	//===
+	
 	//Retrieve distMax val
 	//====== 
 	if(!XMLGetNextElemAttrib(nodePtr,distMax,"distmax","value"))
@@ -1418,8 +1610,10 @@ bool SpatialAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &st
 	//====
 	if(XMLHelpFwdToElem(nodePtr,"colour"))
 		return false;
-	if(!parseXMLColour(nodePtr,r,g,b,a))
+	ColourRGBAf tmpRgbaf;
+	if(!parseXMLColour(nodePtr,tmpRgbaf))
 		return false;
+	rgba=tmpRgbaf;
 	//====
 
 
@@ -1436,9 +1630,29 @@ bool SpatialAnalysisFilter::readState(xmlNodePtr &nodePtr, const std::string &st
 		return false;
 
 
+	//FIXME:COMPAT_BREAK : 3Depict <= internal fb7d66397b7b does not contain
+	tmpNode=nodePtr;
+	if(!XMLHelpFwdToElem(nodePtr,"replace"))
+	{
+		if(XMLHelpGetProp(replaceFile,nodePtr,"file"))
+			return false;
+	
+		if(XMLHelpGetProp(replaceMode,nodePtr,"mode"))
+			return false;
+		
+		if(replaceMode>REPLACE_MODE_ENUM_END)
+			return false;
+		
+		if(XMLHelpGetProp(replaceTolerance,nodePtr,"tolerance"))
+			return false;
+		if(replaceTolerance < 0)
+			return false;
+	}
+	else
+		nodePtr=tmpNode;
+
 	//FIXME:COMPAT_BREAK : 3Depict <= 1796:5639f6d50732 does not contain
 	// this section
-	xmlNodePtr tmpNode;
 
 	tmpNode=nodePtr;
 	if(!XMLHelpFwdToElem(nodePtr,"binomial"))
@@ -1650,7 +1864,7 @@ size_t SpatialAnalysisFilter::buildSplitPoints(const vector<const FilterStreamDa
 				{
 					if(extendPointVector(pSource,d->data,callback,
 					                     progress.filterProgress,curPos[0]))
-						return ABORT_ERR;
+						return ERR_ABORT_FAIL;
 
 					curPos[0]+=d->data.size();
 				}
@@ -1659,7 +1873,7 @@ size_t SpatialAnalysisFilter::buildSplitPoints(const vector<const FilterStreamDa
 				{
 					if(extendPointVector(pTarget,d->data,callback,
 					                     progress.filterProgress,curPos[1]))
-						return ABORT_ERR;
+						return ERR_ABORT_FAIL;
 
 					curPos[1]+=d->data.size();
 				}
@@ -1721,7 +1935,7 @@ size_t buildMonolithicPoints(const vector<const FilterStreamData *> &dataIn,
 
 	progress.filterProgress=0;
 	if(!(*callback)(true))
-		return ABORT_ERR;
+		return ERR_ABORT_FAIL;
 
 	for(unsigned int ui=0;ui<dataIn.size() ;ui++)
 	{
@@ -1735,7 +1949,7 @@ size_t buildMonolithicPoints(const vector<const FilterStreamData *> &dataIn,
 				if(extendPointVector(p,d->data,
 						callback,progress.filterProgress,
 						dataSize))
-					return ABORT_ERR;
+					return ERR_ABORT_FAIL;
 
 				dataSize+=d->data.size();
 			}
@@ -1762,7 +1976,7 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 		progress.maxStep=3;
 	
 	if(!(*callback)(true))
-		return ABORT_ERR;
+		return ERR_ABORT_FAIL;
 
 	K3DTree kdTree;
 	kdTree.setCallbackMethod(callback);
@@ -1793,6 +2007,8 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 		//Build the tree using the target ions
 		//(its roughly nlogn timing, but worst case n^2)
 		kdTree.buildByRef(pts[1]);
+		if(!(*callback)(true))
+			return ERR_ABORT_FAIL;
 		pts[1].clear();
 		
 		//Remove surface points from sources if desired
@@ -1803,7 +2019,7 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 			progress.stepName=TRANS("Surface");
 
 			if(!(*callback)(true))
-				return ABORT_ERR;
+				return ERR_ABORT_FAIL;
 
 
 			//Take the input points, then use them
@@ -1818,12 +2034,12 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 				else
 				{
 					ASSERT(false);
-					return ABORT_ERR;
+					return ERR_ABORT_FAIL;
 				}
 			}
 			
 			if(!(*callback)(true))
-				return ABORT_ERR;
+				return ERR_ABORT_FAIL;
 
 			pts[0].clear();
 			//Forget the original points, and use the new ones
@@ -1846,6 +2062,8 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 
 		//Build the tree (its roughly nlogn timing, but worst case n^2)
 		kdTree.buildByRef(p);
+		if(!(*callback)(true))
+			return ERR_ABORT_FAIL;
 
 		//Remove surface points if desired
 		if(excludeSurface)
@@ -1855,7 +2073,7 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 			progress.stepName=TRANS("Surface");
 		
 			if(!(*callback)(true))
-				return ABORT_ERR;
+				return ERR_ABORT_FAIL;
 
 
 			//Take the input points, then use them
@@ -1870,11 +2088,11 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 				if(errCode ==1)
 					return INSUFFICIENT_SIZE_ERR;
 				else if(errCode ==2)
-					return ABORT_ERR;
+					return ERR_ABORT_FAIL;
 				else
 				{
 					ASSERT(false);
-					return ABORT_ERR;
+					return ERR_ABORT_FAIL;
 				}
 			}
 
@@ -1884,7 +2102,7 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 			p.swap(returnPoints);
 			
 			if(!(*callback)(true))
-				return ABORT_ERR;
+				return ERR_ABORT_FAIL;
 
 		}
 		
@@ -1933,12 +2151,37 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 				case RDF_ABORT_FAIL:
 				{
 					delete[] binWidth;
-					return ABORT_ERR;
+					return ERR_ABORT_FAIL;
 				}
 				default:
 					ASSERT(false);
 			}
 
+		
+			vector<vector<float> > histogramFloat;
+			histogramFloat.resize(nnMax); 
+			//Normalise the NN histograms to a per bin width as required
+			if(normaliseNNHist)
+			{
+				for(unsigned int ui=0;ui<nnMax; ui++)
+				{
+					histogramFloat[ui].resize(numBins);
+					for(unsigned int uj=0;uj<numBins;uj++)
+						histogramFloat[ui][uj] = (float)histogram[ui][uj]/binWidth[ui] ;
+				}
+			
+			}
+			else
+			{
+				for(unsigned int ui=0;ui<nnMax;ui++)
+				{
+					histogramFloat[ui].resize(numBins);
+					for(unsigned int uj=0;uj<numBins;uj++)
+						histogramFloat[ui][uj] = (float)histogram[ui][uj];
+				}
+			}
+			histogram.clear();
+	
 			//Alright then, we have the histogram in x-{y1,y2,y3...y_n} form
 			//lets make some plots shall we?
 			PlotStreamData *plotData[nnMax];
@@ -1950,36 +2193,30 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 				plotData[ui]->parent=this;
 				plotData[ui]->plotMode=PLOT_MODE_1D;
 				plotData[ui]->xLabel=TRANS("Radial Distance");
-				plotData[ui]->yLabel=TRANS("Count");
+				if(normaliseNNHist)
+					plotData[ui]->yLabel=TRANS("Count/Distance");
+				else
+					plotData[ui]->yLabel=TRANS("Count");
 				std::string tmpStr;
 				stream_cast(tmpStr,ui+1);
 				plotData[ui]->dataLabel=getUserString() + string(" ") +tmpStr + TRANS("NN Freq.");
 
 				//Red plot.
-				plotData[ui]->r=r;
-				plotData[ui]->g=g;
-				plotData[ui]->b=b;
+				plotData[ui]->r=rgba.r();
+				plotData[ui]->g=rgba.g();
+				plotData[ui]->b=rgba.b();
 				plotData[ui]->xyData.resize(numBins);
 
 				for(unsigned int uj=0;uj<numBins;uj++)
 				{
 					float dist;
-					ASSERT(ui < histogram.size() && uj<histogram[ui].size());
+					ASSERT(ui < histogramFloat.size() && uj<histogramFloat[ui].size());
 					dist = (float)uj*binWidth[ui];
 					plotData[ui]->xyData[uj] = std::make_pair(dist,
-							histogram[ui][uj]);
+							histogramFloat[ui][uj]);
 				}
 
-				if(cache)
-				{
-					plotData[ui]->cached=1;
-					filterOutputs.push_back(plotData[ui]);
-					cacheOK=true;
-				}	
-				else
-				{
-					plotData[ui]->cached=0;
-				}
+				cacheAsNeeded(plotData[ui]);
 				
 				getOut.push_back(plotData[ui]);
 			}
@@ -2002,7 +2239,7 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 					warnBiasCount,&(progress.filterProgress),callback);
 
 			if(errcode)
-				return ABORT_ERR;
+				return ERR_ABORT_FAIL;
 
 			if(warnBiasCount)
 			{
@@ -2022,9 +2259,9 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 			plotData->yLabel=TRANS("Count");
 			plotData->dataLabel=getUserString() + TRANS(" RDF");
 
-			plotData->r=r;
-			plotData->g=g;
-			plotData->b=b;
+			plotData->r=rgba.r();
+			plotData->g=rgba.g();
+			plotData->b=rgba.b();
 			plotData->xyData.resize(numBins);
 
 			for(unsigned int uj=0;uj<numBins;uj++)
@@ -2036,15 +2273,8 @@ size_t SpatialAnalysisFilter::algorithmRDF(ProgressData &progress, bool (*callba
 			}
 
 			delete[] histogram;
-
-			if(cache)
-			{
-				plotData->cached=1;
-				filterOutputs.push_back(plotData);
-				cacheOK=true;
-			}
-			else
-				plotData->cached=0;	
+			
+			cacheAsNeeded(plotData);
 			
 			getOut.push_back(plotData);
 
@@ -2090,7 +2320,7 @@ size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress,
 	progress.stepName=TRANS("Build");
 	progress.filterProgress=0;
 	if(!(*callback)(true))
-		return ABORT_ERR;
+		return ERR_ABORT_FAIL;
 
 	BoundCube treeDomain;
 	treeDomain.setBounds(p);
@@ -2101,13 +2331,13 @@ size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress,
 	kdTree.setProgressPointer(&(progress.filterProgress));
 	
 	kdTree.buildByRef(p);
-	p.clear(); //We don't need pts any more, as tree *is* a copy.
 
 
 	//Update progress & User interface by calling callback
-	if(!(*callback)(false))
-		return ABORT_ERR;
+	if(!(*callback)(true))
+		return ERR_ABORT_FAIL;
 
+	p.clear(); //We don't need pts any more, as tree *is* a copy.
 
 	//Its algorithm time!
 	//----
@@ -2117,7 +2347,7 @@ size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress,
 	progress.stepName=TRANS("Analyse");
 	progress.filterProgress=0;
 	if(!(*callback)(true))
-		return ABORT_ERR;
+		return ERR_ABORT_FAIL;
 
 	//List of points for which there was a failure
 	//first entry is the point Id, second is the 
@@ -2190,7 +2420,7 @@ size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress,
 					if(spin)
 					{
 						delete newD;
-						return ABORT_ERR;
+						return ERR_ABORT_FAIL;
 					}
 
 
@@ -2247,7 +2477,7 @@ size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress,
 									spin=true;
 #else
 									delete newD;
-									return ABORT_ERR;
+									return ERR_ABORT_FAIL;
 #endif
 								}
 								}
@@ -2271,7 +2501,7 @@ size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress,
 					if(spin)
 					{
 						delete newD;
-						return ABORT_ERR;
+						return ERR_ABORT_FAIL;
 					}
 #endif
 				}
@@ -2312,15 +2542,8 @@ size_t SpatialAnalysisFilter::algorithmDensity(ProgressData &progress,
 					newD->representationType=d->representationType;
 					newD->valueType=TRANS("Number Density (\\#/Vol^3)");
 
-					//Cache result as needed
-					if(cache)
-					{
-						newD->cached=1;
-						filterOutputs.push_back(newD);
-						cacheOK=true;
-					}
-					else
-						newD->cached=0;
+					//Cache result as neede
+					cacheAsNeeded(newD);
 					getOut.push_back(newD);
 				}
 				else
@@ -2388,7 +2611,7 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 	progress.stepName=TRANS("Build");
 	progress.filterProgress=0;
 	if(!(*callback)(true))
-		return ABORT_ERR;
+		return ERR_ABORT_FAIL;
 
 	BoundCube treeDomain;
 	treeDomain.setBounds(p);
@@ -2402,8 +2625,8 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 
 
 	//Update progress & User interface by calling callback
-	if(!(*callback)(false))
-		return ABORT_ERR;
+	if(!(*callback)(true))
+		return ERR_ABORT_FAIL;
 	p.clear(); //We don't need pts any more, as tree *is* a copy.
 
 
@@ -2415,7 +2638,7 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 	progress.stepName=TRANS("Analyse");
 	progress.filterProgress=0;
 	if(!(*callback)(true))
-		return ABORT_ERR;
+		return ERR_ABORT_FAIL;
 
 	//List of points for which there was a failure
 	//first entry is the point Id, second is the 
@@ -2494,7 +2717,7 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 					if(spin)
 					{
 						delete newD;
-						return ABORT_ERR;
+						return ERR_ABORT_FAIL;
 					}
 
 
@@ -2551,7 +2774,7 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 									spin=true;
 #else
 									delete newD;
-									return ABORT_ERR;
+									return ERR_ABORT_FAIL;
 #endif
 								}
 								}
@@ -2579,7 +2802,7 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 					if(spin)
 					{
 						delete newD;
-						return ABORT_ERR;
+						return ERR_ABORT_FAIL;
 					}
 #endif
 				}
@@ -2621,14 +2844,7 @@ size_t SpatialAnalysisFilter::algorithmDensityFilter(ProgressData &progress,
 					newD->valueType=TRANS("Number Density (\\#/Vol^3)");
 
 					//Cache result as needed
-					if(cache)
-					{
-						newD->cached=1;
-						filterOutputs.push_back(newD);
-						cacheOK=true;
-					}
-					else
-						newD->cached=0;
+					cacheAsNeeded(newD);
 					getOut.push_back(newD);
 				}
 				else
@@ -2798,7 +3014,7 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 	}
 
 	if(wantAbort)
-		return ABORT_ERR;
+		return ERR_ABORT_FAIL;
 
 	//Now, the ions outside the targeting volume may be reduced 
 	vector<IonHit> ionsOutside;
@@ -2862,10 +3078,10 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 				case ERR_CROP_INSUFFICIENT_MEM:
 					return INSUFFICIENT_SIZE_ERR;
 				case ERR_CROP_CALLBACK_FAIL:
-					return ABORT_ERR;
+					return ERR_ABORT_FAIL;
 				default: 
 					ASSERT(false);
-					return ABORT_ERR;
+					return ERR_ABORT_FAIL;
 
 			}
 			tmp.swap(ionsOutside);
@@ -2932,6 +3148,8 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 	tree.setProgressPointer(&progress.filterProgress);
 	tree.setCallbackMethod(callback);
 	tree.buildByRef(dest);
+	if(!(*callback)(true))
+		return ERR_ABORT_FAIL;
 
 	progress.step=4;
 	progress.stepName=TRANS("Compute");
@@ -2955,19 +3173,6 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 			errCode=generate1DAxialNNHist(src,tree,axisNormal, histogram,
 					binWidth,nnMax,numBins,&progress.filterProgress,callback);
 
-			//Remap the underlying function code ot that for this function
-			switch(errCode)
-			{
-				case 0:
-					histOK=true;
-					break;
-				case RDF_ERR_INSUFFICIENT_INPUT_POINTS:
-					consoleOutput.push_back(TRANS("Insufficient points to complete analysis"));
-					errCode=0;
-					break;
-				default:
-					ASSERT(false);
-			}
 			break;
 		}
 		case STOP_MODE_RADIUS:
@@ -2978,12 +3183,29 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 			errCode=generate1DAxialDistHist(src,tree,axisNormal, histogram,
 					distMax,numBins,&progress.filterProgress,callback);
 
-			histOK = (errCode !=0);
+			histOK = (errCode ==0);
 			break;
 		}
 		default:
 			ASSERT(false);
 	}
+	
+	//Remap the underlying function code to that for this function
+	switch(errCode)
+	{
+		case 0:
+			histOK=true;
+			break;
+		case RDF_ERR_INSUFFICIENT_INPUT_POINTS:
+			consoleOutput.push_back(TRANS("Insufficient points to complete analysis"));
+			errCode=0;
+			break;
+		case RDF_ABORT_FAIL:
+			errCode=ERR_ABORT_FAIL;
+			break;
+		default:
+			ASSERT(false);
+	}
 
 	if(errCode)
 	{
@@ -3002,9 +3224,9 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 		plotData->yLabel=TRANS("Count");
 		plotData->dataLabel=getUserString() + TRANS(" 1D Dist. Func.");
 
-		plotData->r=r;
-		plotData->g=g;
-		plotData->b=b;
+		plotData->r=rgba.r();
+		plotData->g=rgba.g();
+		plotData->b=rgba.b();
 		plotData->xyData.resize(numBins);
 
 		for(unsigned int uj=0;uj<numBins;uj++)
@@ -3025,14 +3247,7 @@ size_t SpatialAnalysisFilter::algorithmAxialDf(ProgressData &progress,
 					histogram[uj]);
 		}
 
-		if(cache)
-		{
-			plotData->cached=1;
-			filterOutputs.push_back(plotData);
-			cacheOK=true;
-		}
-		else
-			plotData->cached=0;	
+		cacheAsNeeded(plotData);
 		getOut.push_back(plotData);
 	}
 
@@ -3213,7 +3428,7 @@ size_t SpatialAnalysisFilter::algorithmBinomial(ProgressData &progress,
 		plt->index=ui;
 		plt->parent=this;
 		plt->plotMode=PLOT_MODE_1D;
-		plt->plotStyle=PLOT_TRACE_STEM;
+		plt->plotStyle=PLOT_LINE_STEM;
 		plt->xLabel=TRANS("Block size");
 		if(showNormalisedBinomialFrequencies)
 			plt->yLabel=TRANS("Rel. Frequency");
@@ -3254,17 +3469,7 @@ size_t SpatialAnalysisFilter::algorithmBinomial(ProgressData &progress,
 			}
 		}
 
-		if(cache)
-		{
-			plt->cached=1;
-			filterOutputs.push_back(plt);
-			cacheOK=true;
-		}	
-		else
-		{
-			plt->cached=0;
-		}
-
+		cacheAsNeeded(plt);
 		getOut.push_back(plt);
 
 	}
@@ -3282,7 +3487,7 @@ size_t SpatialAnalysisFilter::algorithmBinomial(ProgressData &progress,
 		plt->index=ui + binHist.mapIonFrequencies.size();
 		plt->parent=this;
 		plt->plotMode=PLOT_MODE_1D;
-		plt->plotStyle=PLOT_TRACE_STEM;
+		plt->plotStyle=PLOT_LINE_STEM;
 		plt->xLabel=TRANS("Block size");
 		if(showNormalisedBinomialFrequencies)
 			plt->yLabel=TRANS("Rel. Frequency");
@@ -3323,16 +3528,7 @@ size_t SpatialAnalysisFilter::algorithmBinomial(ProgressData &progress,
 			}
 		}
 
-		if(cache)
-		{
-			plt->cached=1;
-			filterOutputs.push_back(plt);
-			cacheOK=true;
-		}	
-		else
-		{
-			plt->cached=0;
-		}
+		cacheAsNeeded(plt);
 
 		getOut.push_back(plt);
 
@@ -3347,6 +3543,7 @@ bool densityPairTest();
 bool nnHistogramTest();
 bool rdfPlotTest();
 bool axialDistTest();
+bool replaceTest();
 
 bool SpatialAnalysisFilter::runUnitTests()
 {
@@ -3361,7 +3558,8 @@ bool SpatialAnalysisFilter::runUnitTests()
 
 	if(!axialDistTest())
 		return false;
-	
+	if(!replaceTest())
+		return false;
 	return true;
 }
 
@@ -3627,5 +3825,66 @@ bool axialDistTest()
 	return true;
 }
 
+bool replaceTest()
+{
+	std::string ionFile=createTmpFilename(NULL,".pos");
+		
+	vector<IonHit> ions;
+	const unsigned int NIONS=10;
+	for(unsigned int ui=0;ui<NIONS;ui++)
+		ions.push_back(IonHit(Point3D(ui,ui,ui),1));
+
+	IonHit::makePos(ions,ionFile.c_str());
+	
+	for(unsigned int ui=0;ui<NIONS;ui++)
+		ions[ui].setMassToCharge(2);
+
+	IonStreamData *d = new IonStreamData;
+	d->data.swap(ions);
+
+	//Create a spatial analysis filter
+	SpatialAnalysisFilter *f=new SpatialAnalysisFilter;
+	f->setCaching(false);	
+	
+	//Set it to do a union calculation 
+	bool needUp;
+	string s;
+	s=TRANS(SPATIAL_ALGORITHMS[ALGORITHM_REPLACE]);
+	TEST(f->setProperty(KEY_ALGORITHM,s,needUp),"Set prop");
+	TEST(f->setProperty(KEY_REPLACE_FILE,ionFile,needUp),"Set prop");
+	s=TRANS(REPLACE_ALGORITHMS[REPLACE_MODE_INTERSECT]);
+	TEST(f->setProperty(KEY_REPLACE_ALGORITHM,s,needUp),"Set prop");
+	
+	s="1";
+	TEST(f->setProperty(KEY_REPLACE_VALUE,s,needUp),"Set prop");
+
+
+	//Do the refresh
+	ProgressData p;
+	vector<const FilterStreamData*> streamIn,streamOut;
+	streamIn.push_back(d);
+	TEST(!f->refresh(streamIn,streamOut,p,dummyCallback),"refresh OK");
+	delete f;
+	delete d;
+	streamIn.clear();
+
+	TEST(streamOut.size() == 1,"stream count");
+	TEST(streamOut[0]->getStreamType() == STREAM_TYPE_IONS,"stream type");
+	TEST(streamOut[0]->getNumBasicObjects() == NIONS,"Number objects");
+
+	//we should have taken the mass-to-charge from the file
+	const IonStreamData *outIons = (const IonStreamData*)streamOut[0];
+	for(unsigned int ui=0;ui<NIONS; ui++)
+	{
+		ASSERT(outIons->data[ui].getMassToCharge() == 1); 
+	}
+
+	wxRemoveFile(ionFile);
+
+	delete streamOut[0];
+	
+	return true;
+}
+
 #endif
 
diff --git a/src/backend/filters/spatialAnalysis.h b/src/backend/filters/spatialAnalysis.h
index 2a5260d..42422fc 100644
--- a/src/backend/filters/spatialAnalysis.h
+++ b/src/backend/filters/spatialAnalysis.h
@@ -25,7 +25,7 @@ class SpatialAnalysisFilter : public Filter
 {
 	private:
 		//!Colour to use for output plots
-		float r,g,b,a;
+		ColourRGBAf rgba;
 
 		//!Which algorithm to use
 		unsigned int algorithm;
@@ -56,6 +56,10 @@ class SpatialAnalysisFilter : public Filter
 
 		//!Surface reduction distance (convex hull)
 		float reductionDistance;
+
+		//!Change the NN histograms from counts to counts/nm
+		// - this allows comparing different binwidth histograms
+		bool normaliseNNHist;
 		//--------
 		
 		//Density filtering specific params
@@ -105,7 +109,20 @@ class SpatialAnalysisFilter : public Filter
 
 		//--------
 
+		//Replace specific code
+		//---------
+		//file to use as other data source
+		string replaceFile;
+
+		//replacement operator mode
+		unsigned int replaceMode;
 
+		//distance up to which to allow replacement
+		float replaceTolerance;
+		
+		//should we replace the current mass by the other file's ?
+		bool replaceMass;
+		//---------
 	
 		//Radial distribution function - creates a 1D histogram of spherical atom counts, centered around each atom
 		size_t algorithmRDF(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, 
@@ -132,6 +149,10 @@ class SpatialAnalysisFilter : public Filter
 			const vector<const FilterStreamData *>  &dataIn, 
 			vector<const FilterStreamData * > &getOut,const RangeFile *rngF);
 
+		size_t algorithmReplace(ProgressData &progress, bool (*callback)(bool), size_t totalDataSize, 
+			const vector<const FilterStreamData *>  &dataIn, 
+			vector<const FilterStreamData * > &getOut);
+
 		//Create a 3D manipulable cylinder as an output drawable
 		// using the parameters stored inside the vector/scalar params
 		// both parameters are outputs from this function
diff --git a/src/backend/filters/spectrumPlot.cpp b/src/backend/filters/spectrumPlot.cpp
index 39e6250..90f320a 100644
--- a/src/backend/filters/spectrumPlot.cpp
+++ b/src/backend/filters/spectrumPlot.cpp
@@ -27,6 +27,7 @@ enum
 	SPECTRUM_BAD_ALLOC=1,
 	SPECTRUM_BAD_BINCOUNT,
 	SPECTRUM_ABORT_FAIL,
+	SPECTRUM_ERR_ENUM_END,
 };
 
 enum
@@ -55,8 +56,7 @@ SpectrumPlotFilter::SpectrumPlotFilter()
 	logarithmic=1;
 
 	//Default to blue plot
-	r=g=0;
-	b=a=1;
+	rgba = ColourRGBAf(0,0,1.0f,1.0f);
 }
 
 Filter *SpectrumPlotFilter::cloneUncached() const
@@ -67,10 +67,7 @@ Filter *SpectrumPlotFilter::cloneUncached() const
 	p->maxPlot=maxPlot;
 	p->binWidth=binWidth;
 	p->autoExtrema=autoExtrema;
-	p->r=r;	
-	p->g=g;	
-	p->b=b;	
-	p->a=a;	
+	p->rgba=rgba;	
 	p->plotStyle=plotStyle;
 	p->logarithmic = logarithmic;
 
@@ -185,7 +182,7 @@ unsigned int SpectrumPlotFilter::refresh(const std::vector<const FilterStreamDat
 			fabs(delta) >  std::numeric_limits<float>::max() || // Check for out-of-range
 			 binWidth < sqrt(std::numeric_limits<float>::epsilon())	)
 		{
-			//If not, then simply set it to "1".
+			//If not, then simply set it to some defaults.
 			minPlot=0; maxPlot=1.0; binWidth=0.1;
 		}
 
@@ -225,10 +222,10 @@ unsigned int SpectrumPlotFilter::refresh(const std::vector<const FilterStreamDat
 	}
 
 	
-	d->r = r;
-	d->g = g;
-	d->b = b;
-	d->a = a;
+	d->r =rgba.r();
+	d->g = rgba.g();
+	d->b = rgba.b();
+	d->a = rgba.a();
 
 	d->logarithmic=logarithmic;
 	d->plotStyle = plotStyle;
@@ -371,15 +368,8 @@ unsigned int SpectrumPlotFilter::refresh(const std::vector<const FilterStreamDat
 
 	}
 
-	if(cache)
-	{
-		d->cached=1; //IMPORTANT: cached must be set PRIOR to push back
-		filterOutputs.push_back(d);
-		cacheOK=true;
-	}
-	else
-		d->cached=0;
-
+	cacheAsNeeded(d);
+	
 	getOut.push_back(d);
 
 	return 0;
@@ -400,11 +390,7 @@ void SpectrumPlotFilter::getProperties(FilterPropGroup &propertyList) const
 	p.helpText=TRANS("Step size for spectrum");
 	propertyList.addProperty(p,curGroup);
 
-	if(autoExtrema)
-		str = "1";
-	else
-		str = "0";
-
+	str=boolStrEnc(autoExtrema);
 
 	p.name=TRANS("Auto Min/max");
 	p.data=str;
@@ -428,11 +414,11 @@ void SpectrumPlotFilter::getProperties(FilterPropGroup &propertyList) const
 	p.type=PROPERTY_TYPE_REAL;
 	p.helpText=TRANS("Ending position for spectrum");
 	propertyList.addProperty(p,curGroup);
-	
-	if(logarithmic)
-		str = "1";
-	else
-		str = "0";
+
+	propertyList.setGroupTitle(curGroup,TRANS("Data"));
+	curGroup++;
+
+	str=boolStrEnc(logarithmic);
 	p.key=KEY_SPECTRUM_LOGARITHMIC;
 	p.name=TRANS("Logarithmic");
 	p.data=str;
@@ -445,14 +431,14 @@ void SpectrumPlotFilter::getProperties(FilterPropGroup &propertyList) const
 
 
 	string tmpStr;
-	tmpStr=plotString(PLOT_TRACE_LINES);
-	choices.push_back(make_pair((unsigned int) PLOT_TRACE_LINES,tmpStr));
-	tmpStr=plotString(PLOT_TRACE_BARS);
-	choices.push_back(make_pair((unsigned int)PLOT_TRACE_BARS,tmpStr));
-	tmpStr=plotString(PLOT_TRACE_STEPS);
-	choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEPS,tmpStr));
-	tmpStr=plotString(PLOT_TRACE_STEM);
-	choices.push_back(make_pair((unsigned int)PLOT_TRACE_STEM,tmpStr));
+	tmpStr=plotString(PLOT_LINE_LINES);
+	choices.push_back(make_pair((unsigned int) PLOT_LINE_LINES,tmpStr));
+	tmpStr=plotString(PLOT_LINE_BARS);
+	choices.push_back(make_pair((unsigned int)PLOT_LINE_BARS,tmpStr));
+	tmpStr=plotString(PLOT_LINE_STEPS);
+	choices.push_back(make_pair((unsigned int)PLOT_LINE_STEPS,tmpStr));
+	tmpStr=plotString(PLOT_LINE_STEM);
+	choices.push_back(make_pair((unsigned int)PLOT_LINE_STEM,tmpStr));
 
 
 	tmpStr= choiceString(choices,plotStyle);
@@ -463,18 +449,14 @@ void SpectrumPlotFilter::getProperties(FilterPropGroup &propertyList) const
 	p.key=KEY_SPECTRUM_PLOTTYPE;
 	propertyList.addProperty(p,curGroup);
 
-	string thisCol;
-
-	//Convert the colour to a hex string
-	genColString((unsigned char)(r*255.0),(unsigned char)(g*255.0),
-		(unsigned char)(b*255.0),(unsigned char)(a*255.0),thisCol);
-
 	p.name=TRANS("Colour");
-	p.data=thisCol; 
+	p.data=rgba.toColourRGBA().rgbaString(); 
 	p.type=PROPERTY_TYPE_COLOUR;
 	p.helpText=TRANS("Colour of plotted spectrum");
 	p.key=KEY_SPECTRUM_COLOUR;
 	propertyList.addProperty(p,curGroup);
+
+	propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 }
 
 bool SpectrumPlotFilter::setProperty( unsigned int key, 
@@ -512,28 +494,8 @@ bool SpectrumPlotFilter::setProperty( unsigned int key,
 		//Auto min/max
 		case KEY_SPECTRUM_AUTOEXTREMA:
 		{
-			//Only allow valid values
-			unsigned int valueInt;
-			if(stream_cast(valueInt,value))
+			if(!applyPropertyNow(autoExtrema,value,needUpdate))
 				return false;
-
-			//Only update as needed
-			if(valueInt ==0 || valueInt == 1)
-			{
-				if(autoExtrema != (bool)valueInt)
-				{
-					needUpdate=true;
-					autoExtrema=valueInt;
-				}
-				else
-					needUpdate=false;
-
-			}
-			else
-				return false;		
-	
-			clearCache();
-	
 			break;
 
 		}
@@ -623,7 +585,7 @@ bool SpectrumPlotFilter::setProperty( unsigned int key,
 
 			tmpPlotType=plotID(value);
 
-			if(tmpPlotType >= PLOT_TRACE_ENDOFENUM)
+			if(tmpPlotType >= PLOT_LINE_NONE)
 				return false;
 
 			plotStyle = tmpPlotType;
@@ -651,17 +613,15 @@ bool SpectrumPlotFilter::setProperty( unsigned int key,
 		}
 		case KEY_SPECTRUM_COLOUR:
 		{
-			unsigned char newR,newG,newB,newA;
+			ColourRGBA tmpRgb;
+			tmpRgb.parse(value);
 
-			parseColString(value,newR,newG,newB,newA);
-
-			if(newB != b || newR != r ||
-				newG !=g || newA != a)
+			if(tmpRgb.toRGBAf() != rgba)
+			{
+				rgba=tmpRgb.toRGBAf();
 				needUpdate=true;
-			r=newR/255.0;
-			g=newG/255.0;
-			b=newB/255.0;
-			a=newA/255.0;
+			}
+			
 			if(cacheOK)
 			{
 				for(size_t ui=0;ui<filterOutputs.size();ui++)
@@ -671,9 +631,9 @@ bool SpectrumPlotFilter::setProperty( unsigned int key,
 						PlotStreamData *p;
 						p =(PlotStreamData*)filterOutputs[ui];
 
-						p->r=r;
-						p->g=g;
-						p->b=b;
+						p->r=rgba.r();
+						p->g=rgba.g();
+						p->b=rgba.b();
 					}
 				}
 
@@ -703,14 +663,15 @@ void SpectrumPlotFilter::setUserString(const std::string &s)
 
 std::string  SpectrumPlotFilter::getErrString(unsigned int code) const
 {
-	switch(code)
-	{
-		case SPECTRUM_BAD_ALLOC:
-			return string(TRANS("Insufficient memory for spectrum filter."));
-		case SPECTRUM_BAD_BINCOUNT:
-			return string(TRANS("Bad bincount value in spectrum filter."));
-	}
-	return std::string("BUG: (SpectrumPlotFilter::getErrString) Shouldn't see this!");
+	const char *errStrs[] = {
+		"",
+		"Insufficient memory for spectrum filter.",
+		"Bad bincount value in spectrum filter.",
+		"Aborted."
+	};
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == SPECTRUM_ERR_ENUM_END);
+	ASSERT(code < SPECTRUM_ERR_ENUM_END);
+	return errStrs[code];
 }
 
 void SpectrumPlotFilter::setPropFromBinding(const SelectionBinding &b)
@@ -732,8 +693,8 @@ bool SpectrumPlotFilter::writeState(std::ostream &f,unsigned int format, unsigne
 					maxPlot  << "\" auto=\"" << autoExtrema << "\"/>" << endl;
 			f << tabs(depth+1) << "<binwidth value=\"" << binWidth<< "\"/>" << endl;
 
-			f << tabs(depth+1) << "<colour r=\"" <<  r<< "\" g=\"" << g << "\" b=\"" <<b
-				<< "\" a=\"" << a << "\"/>" <<endl;
+			f << tabs(depth+1) << "<colour r=\"" <<  rgba.r() << "\" g=\"" << rgba.g() << "\" b=\"" << rgba.b()
+				<< "\" a=\"" << rgba.a() << "\"/>" <<endl;
 			
 			f << tabs(depth+1) << "<logarithmic value=\"" << logarithmic<< "\"/>" << endl;
 
@@ -805,11 +766,7 @@ bool SpectrumPlotFilter::readState(xmlNodePtr &nodePtr, const std::string &state
 		return false;
 	
 	tmpStr=(char *)xmlString;
-	if(tmpStr == "1") 
-		autoExtrema=true;
-	else if(tmpStr== "0")
-		autoExtrema=false;
-	else
+	if(!boolStrDec(tmpStr,autoExtrema))
 	{
 		xmlFree(xmlString);
 		return false;
@@ -833,19 +790,17 @@ bool SpectrumPlotFilter::readState(xmlNodePtr &nodePtr, const std::string &state
 	//====
 	if(XMLHelpFwdToElem(nodePtr,"colour"))
 		return false;
-	if(!parseXMLColour(nodePtr,r,g,b,a))
+	ColourRGBAf tmpRgba;
+	if(!parseXMLColour(nodePtr,tmpRgba))
 		return false;
+	rgba=tmpRgba;
 	//====
 	
 	//Retrieve logarithmic mode
 	//====
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"logarithmic","value"))
 		return false;
-	if(tmpStr == "0")
-		logarithmic=false;
-	else if(tmpStr == "1")
-		logarithmic=true;
-	else
+	if(!boolStrDec(tmpStr,logarithmic))
 		return false;
 	//====
 
@@ -853,7 +808,7 @@ bool SpectrumPlotFilter::readState(xmlNodePtr &nodePtr, const std::string &state
 	//====
 	if(!XMLGetNextElemAttrib(nodePtr,plotStyle,"plottype","value"))
 		return false;
-	if(plotStyle >= PLOT_TRACE_ENDOFENUM)
+	if(plotStyle >= PLOT_LINE_NONE)
 	       return false;	
 	//====
 
@@ -909,11 +864,10 @@ bool countTest()
 
 
 	bool needUp;
-	std::string s;
 	TEST(f->setProperty(KEY_SPECTRUM_LOGARITHMIC,"0",needUp),"Set prop");
 	
-	genColString(255,0,0,s);
-	TEST(f->setProperty(KEY_SPECTRUM_COLOUR,s,needUp),"Set prop");
+	ColourRGBA tmpRGBA(255,0,0);
+	TEST(f->setProperty(KEY_SPECTRUM_COLOUR,tmpRGBA.rgbString(),needUp),"Set prop");
 
 	vector<const FilterStreamData*> streamIn,streamOut;
 
diff --git a/src/backend/filters/spectrumPlot.h b/src/backend/filters/spectrumPlot.h
index 09c25b1..a4c207d 100644
--- a/src/backend/filters/spectrumPlot.h
+++ b/src/backend/filters/spectrumPlot.h
@@ -33,7 +33,7 @@ class SpectrumPlotFilter : public Filter
 
 		//Vector of spectra. Each spectra is comprised of a sorted Y data
 		std::vector< std::vector<float > > spectraCache;
-		float r,g,b,a;
+		ColourRGBAf rgba;
 		unsigned int plotStyle;
 	public:
 		SpectrumPlotFilter();
diff --git a/src/backend/filters/transform.cpp b/src/backend/filters/transform.cpp
index 6b04ed6..3da7e09 100644
--- a/src/backend/filters/transform.cpp
+++ b/src/backend/filters/transform.cpp
@@ -71,7 +71,8 @@ enum
 enum
 {
 	ERR_CALLBACK_FAIL=1,
-	ERR_NOMEM
+	ERR_NOMEM,
+	TRANSFORM_ERR_ENUM_END
 };
 
 const char *TRANSFORM_MODE_STRING[] = { NTRANS("Translate"),
@@ -273,13 +274,8 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 		DrawStreamData *d=makeMarkerSphere(s);
 		if(s)
 			devices.push_back(s);
-		if(cache)
-		{
-			d->cached=1;
-			filterOutputs.push_back(d);
-		}
-		else
-			d->cached=0;
+
+		cacheAsNeeded(d);
 		
 		getOut.push_back(d);
 	}
@@ -417,14 +413,7 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 #endif
 							ASSERT(d->data.size() == src->data.size());
 
-							if(cache)
-							{
-								d->cached=1;
-								filterOutputs.push_back(d);
-								cacheOK=true;
-							}
-							else
-								d->cached=0;
+							cacheAsNeeded(d);
 
 							getOut.push_back(d);
 							break;
@@ -538,14 +527,7 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 #endif
 							ASSERT(d->data.size() == src->data.size());
 
-							if(cache)
-							{
-								d->cached=1;
-								filterOutputs.push_back(d);
-								cacheOK=true;
-							}
-							else
-								d->cached=0;
+							cacheAsNeeded(d);
 
 							getOut.push_back(d);
 							break;
@@ -659,14 +641,8 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 							ASSERT(pos == d->data.size());
 #endif
 							ASSERT(d->data.size() == src->data.size());
-							if(cache)
-							{
-								d->cached=1;
-								filterOutputs.push_back(d);
-								cacheOK=true;
-							}
-							else
-								d->cached=0;
+
+							cacheAsNeeded(d);
 							
 							getOut.push_back(d);
 							break;
@@ -776,14 +752,8 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 							ASSERT(pos == d->data.size());
 #endif
 							ASSERT(d->data.size() == src->data.size());
-							if(cache)
-							{
-								d->cached=1;
-								filterOutputs.push_back(d);
-								cacheOK=true;
-							}
-							else
-								d->cached=0;
+
+							cacheAsNeeded(d);
 							
 							getOut.push_back(d);
 							break;
@@ -876,14 +846,8 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 							}
 
 							ASSERT(d->data.size() == src->data.size());
-							if(cache)
-							{
-								d->cached=1;
-								filterOutputs.push_back(d);
-								cacheOK=true;
-							}
-							else
-								d->cached=0;
+
+							cacheAsNeeded(d);
 							
 							getOut.push_back(d);
 							break;
@@ -1005,14 +969,8 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 							}
 							
 							ASSERT(d->data.size() == src->data.size());
-							if(cache)
-							{
-								d->cached=1;
-								filterOutputs.push_back(d);
-								cacheOK=true;
-							}
-							else
-								d->cached=0;
+
+							cacheAsNeeded(d);
 							
 							getOut.push_back(d);
 							break;
@@ -1150,15 +1108,8 @@ unsigned int TransformFilter::refresh(const std::vector<const FilterStreamData *
 
 		massData.clear();
 
-		if(cache)
-		{
-			d->cached=1;
-			filterOutputs.push_back(d);
-			cacheOK=true;
-		}
-		else
-			d->cached=0;
-
+		cacheAsNeeded(d);
+		
 		getOut.push_back(d);
 		
 	}
@@ -1186,6 +1137,7 @@ void TransformFilter::getProperties(FilterPropGroup &propertyList) const
 	p.key=KEY_MODE;
 	propertyList.addProperty(p,curGroup);
 	
+	propertyList.setGroupTitle(curGroup,TRANS("Algorithm"));
 	curGroup++;	
 	
 	//non-translation transforms require a user to select an origin	
@@ -1451,48 +1403,20 @@ bool TransformFilter::setProperty(  unsigned int key,
 		case KEY_NOISELEVEL:
 		case KEY_ORIGIN_VALUE:
 		{
-			ASSERT(scalarParams.size());
-
-			float newScale;
-			if(stream_cast(newScale,value))
+			if(!applyPropertyNow(scalarParams[0],value,needUpdate))
 				return false;
-
-			if(scalarParams[0] != newScale )
-			{
-				scalarParams[0] = newScale;
-				needUpdate=true;
-				clearCache();
-			}
 			return true;
 		}
 		case KEY_SCALEFACTOR_ANISOTROPIC:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(vectorParams[1],value,needUpdate))
 				return false;
-
-			if(!(vectorParams[1] == newPt ))
-			{
-				vectorParams[1] = newPt;
-				needUpdate=true;
-				clearCache();
-			}
-
 			return true;
 		}
 		case KEY_ORIGIN:
 		{
-			Point3D newPt;
-			if(!newPt.parse(value))
+			if(!applyPropertyNow(vectorParams[0],value,needUpdate))
 				return false;
-
-			if(!(vectorParams[0] == newPt ))
-			{
-				vectorParams[0] = newPt;
-				needUpdate=true;
-				clearCache();
-			}
-
 			return true;
 		}
 		case KEY_ROTATE_AXIS:
@@ -1534,15 +1458,8 @@ bool TransformFilter::setProperty(  unsigned int key,
 		}
 		case KEY_TRANSFORM_SHOWORIGIN:
 		{
-			string stripped=stripWhite(value);
-
-			if(!(stripped == "1"|| stripped == "0"))
+			if(!applyPropertyNow(showOrigin,value,needUpdate))
 				return false;
-
-			showOrigin=(stripped=="1");
-
-			needUpdate=true;
-
 			break;
 		}
 		case KEY_NOISETYPE:
@@ -1571,17 +1488,14 @@ bool TransformFilter::setProperty(  unsigned int key,
 
 std::string  TransformFilter::getErrString(unsigned int code) const
 {
-
-	switch(code)
-	{
-		//User aborted in a callback
-		case ERR_CALLBACK_FAIL:
-			return std::string(TRANS("Aborted"));
-		//Caught a memory issue
-		case ERR_NOMEM:
-			return std::string(TRANS("Unable to allocate memory"));
-	}
-	ASSERT(false);
+	const char *errStrs[] = { "",
+		"Aborted",//User aborted in a callback
+		"Unable to allocate memory"//Caught a memory issue,
+	};
+
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == TRANSFORM_ERR_ENUM_END);
+	ASSERT(code < TRANSFORM_ERR_ENUM_END);
+	return errStrs[code]; 
 }
 
 bool TransformFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const
diff --git a/src/backend/filters/voxelise.cpp b/src/backend/filters/voxelise.cpp
index 3001475..aaf7e55 100644
--- a/src/backend/filters/voxelise.cpp
+++ b/src/backend/filters/voxelise.cpp
@@ -88,10 +88,11 @@ enum
 //--
 enum
 {
-	VOXELISE_ABORT_ERR,
+	VOXELISE_ABORT_ERR=1,
 	VOXELISE_MEMORY_ERR,
 	VOXELISE_CONVOLVE_ERR,
-	VOXELISE_BOUNDS_INVALID_ERR
+	VOXELISE_BOUNDS_INVALID_ERR,
+	VOXELISE_ERR_ENUM_END
 };
 //--
 
@@ -184,8 +185,7 @@ VoxeliseFilter::VoxeliseFilter()
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(VOXEL_REPRESENT_KEEPCACHE) == VOXEL_REPRESENT_END);
 
 	splatSize=1.0f;
-	a=0.9f;
-	r=g=b=0.5;
+	rgba=ColourRGBAf(0.5,0.5,0.5,0.9f);
 	isoLevel=0.5;
 	
 	filterBins=3;
@@ -231,10 +231,7 @@ Filter *VoxeliseFilter::cloneUncached() const
 {
 	VoxeliseFilter *p=new VoxeliseFilter();
 	p->splatSize=splatSize;
-	p->a=a;
-	p->r=r;
-	p->g=g;
-	p->b=b;
+	p->rgba=rgba;
 
 	p->isoLevel=isoLevel;
 	
@@ -624,10 +621,10 @@ unsigned int VoxeliseFilter::refresh(const std::vector<const FilterStreamData *>
 			vs->representationType= representation;
 			vs->splatSize = splatSize;
 			vs->isoLevel=isoLevel;
-			vs->r=r;
-			vs->g=g;
-			vs->b=b;
-			vs->a=a;
+			vs->r=rgba.r();
+			vs->g=rgba.g();
+			vs->b=rgba.b();
+			vs->a=rgba.a();
 
 			if(cache)
 			{
@@ -672,7 +669,7 @@ unsigned int VoxeliseFilter::refresh(const std::vector<const FilterStreamData *>
 			
 			
 			if(showColourBar)
-				d->drawables.push_back(makeColourBar(minV,maxV,255,colourMap));
+				d->drawables.push_back(makeColourBar(minV,maxV,255,colourMap,1.0f));
 			d->cached=0;
 			d->parent=this;
 			
@@ -814,6 +811,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 
 	//Let the user know what the valid values for voxel value types are
 	vector<pair<unsigned int,string> > choices;
+	unsigned int defaultChoice=normaliseType;
 	tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_NONE);
 	choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_NONE,tmpStr));
 	tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_VOLUME);
@@ -827,8 +825,16 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 		tmpStr=getNormaliseTypeString(VOXELISE_NORMALISETYPE_COUNT2INVOXEL);
 		choices.push_back(make_pair((unsigned int)VOXELISE_NORMALISETYPE_COUNT2INVOXEL,tmpStr));
 	}
+	else
+	{
+		//prevent the case where we usd to have an incoing range stream, but now we dont.
+		// selected item within choice string must still be valid
+		if(normaliseType > VOXELISE_NORMALISETYPE_VOLUME)
+			defaultChoice= VOXELISE_NORMALISETYPE_NONE;
+		
+	}
 
-	tmpStr= choiceString(choices,normaliseType);
+	tmpStr= choiceString(choices,defaultChoice);
 	p.name=TRANS("Normalise by");
 	p.data=tmpStr;
 	p.type=PROPERTY_TYPE_CHOICE;
@@ -843,7 +849,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 	if (rsdIncoming) 
 	{
 		p.name=TRANS("Numerator");
-		p.data=numeratorAll ? "1" : "0";
+		p.data=boolStrEnc(numeratorAll);
 		p.type=PROPERTY_TYPE_BOOL;
 		p.helpText=TRANS("Parmeter \"a\" used in fraction (a/b) to get voxel value");
 		p.key=KEY_ENABLE_NUMERATOR;
@@ -856,10 +862,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 		for(unsigned  int ui=0; ui<rsdIncoming->enabledIons.size(); ui++)
 		{
 			string str;
-			if(enabledIons[0][ui])
-				str="1";
-			else
-				str="0";
+			str=boolStrEnc(enabledIons[0][ui]);
 
 			//Append the ion name with a checkbox
 			p.name=rsdIncoming->rangeFile->getName(ui);
@@ -870,6 +873,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			propertyList.addProperty(p,curGroup);
 		}
 	
+		propertyList.setGroupTitle(curGroup,TRANS("Ranges"));
 		curGroup++;
 	}
 	
@@ -877,7 +881,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 	if (normaliseType == VOXELISE_NORMALISETYPE_COUNT2INVOXEL && rsdIncoming) 
 	{
 		p.name=TRANS("Denominator");
-		p.data=denominatorAll ? "1" : "0";
+		p.data=boolStrEnc(denominatorAll );
 		p.type=PROPERTY_TYPE_BOOL;
 		p.helpText=TRANS("Parameter \"b\" used in fraction (a/b) to get voxel value");
 		p.key=KEY_ENABLE_DENOMINATOR;
@@ -885,10 +889,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 		for(unsigned  int ui=0; ui<rsdIncoming->enabledIons.size(); ui++)
 		{			
 			string str;
-			if(enabledIons[1][ui])
-				str="1";
-			else
-				str="0";
+			str=boolStrEnc(enabledIons[1][ui]);
 
 			//Append the ion name with a checkbox
 			p.key=KEY_ENABLE_DENOMINATOR*1000 + ui;
@@ -899,14 +900,15 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 
 			propertyList.addProperty(p,curGroup);
 		}
+		propertyList.setGroupTitle(curGroup,TRANS("Mode"));
 		curGroup++;
 	}
 
+/*
 	//Start a new set for filtering
 	//----
 	//TODO: Other filtering? threshold/median? laplacian? etc
 	
-/*
 	choices.clear();
 	//Post-filtering method
 	for(unsigned int ui=0;ui<VOXELISE_FILTERTYPE_MAX; ui++)
@@ -988,7 +990,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			p.key=KEY_SPOTSIZE;
 			propertyList.addProperty(p,curGroup);
 
-			stream_cast(tmpStr,1.0-a);
+			stream_cast(tmpStr,1.0-rgba.a());
 			p.name=TRANS("Transparency");
 			p.data=tmpStr;
 			p.type=PROPERTY_TYPE_REAL;
@@ -1012,21 +1014,18 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			propertyList.addProperty(p,curGroup);
 		
 			//-- 
-				
+			propertyList.setGroupTitle(curGroup,TRANS("Surface"));	
 			curGroup++;
 
 			//-- Isosurface appearance --
-			//Convert the ion colour to a hex string	
-			genColString((unsigned char)(r*255),(unsigned char)(g*255),
-					(unsigned char)(b*255),(unsigned char)(a*255),tmpStr);
 			p.name=TRANS("Colour");
-			p.data=tmpStr;
+			p.data=rgba.toColourRGBA().rgbString();
 			p.type=PROPERTY_TYPE_COLOUR;
 			p.helpText=TRANS("Colour of isosurface");
 			p.key=KEY_COLOUR;
 			propertyList.addProperty(p,curGroup);
 
-			stream_cast(tmpStr,1.0-a);
+			stream_cast(tmpStr,1.0-rgba.a());
 			p.name=TRANS("Transparency");
 			p.data=tmpStr;
 			p.type=PROPERTY_TYPE_REAL;
@@ -1034,7 +1033,6 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			p.key=KEY_TRANSPARENCY;
 			propertyList.addProperty(p,curGroup);
 			
-			propertyList.setGroupTitle(curGroup,TRANS("Appearance"));
 			//----
 			
 			break;
@@ -1081,6 +1079,7 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			propertyList.addProperty(p,curGroup);
 			choices.clear();
 			// ---	
+			propertyList.setGroupTitle(curGroup,TRANS("Surface"));	
 			curGroup++;
 
 			
@@ -1098,21 +1097,14 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			p.key=KEY_VOXEL_COLOURMODE;
 			propertyList.addProperty(p,curGroup);
 
-			if(showColourBar)
-				tmpStr="1";
-			else
-				tmpStr="0";
-			
+			tmpStr=boolStrEnc(showColourBar);
 			p.name=TRANS("Show Bar");
 			p.key=KEY_SHOW_COLOURBAR;
 			p.data=tmpStr;
 			p.type=PROPERTY_TYPE_BOOL;
 			propertyList.addProperty(p,curGroup);
 
-			if(autoColourMap)
-				tmpStr="1";
-			else
-				tmpStr="0";	
+			tmpStr=boolStrEnc(autoColourMap);
 			p.name=TRANS("Auto Bounds");
 			p.helpText=TRANS("Auto-compute min/max values in map"); 
 			p.data= tmpStr;
@@ -1147,6 +1139,8 @@ void VoxeliseFilter::getProperties(FilterPropGroup &propertyList) const
 			ASSERT(false);
 			;
 	}
+	
+	propertyList.setGroupTitle(curGroup,TRANS("Appearance"));	
 	curGroup++;
 
 	//----------------------------
@@ -1161,125 +1155,26 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 	{
 		case KEY_FIXEDWIDTH: 
 		{
-			bool b;
-			if(stream_cast(b,value))
+			if(!applyPropertyNow(fixedWidth,value,needUpdate))
 				return false;
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(b!=fixedWidth)
-			{
-				needUpdate=true;
-				fixedWidth=b;
-				clearCache();
-			}
 			break;
 		}	
 		case KEY_NBINSX:
-		{
-			 unsigned int i;
-			if(stream_cast(i,value))
-				return false;
-			if(!i)
-				return false;
-
-			//if the result is different, the
-			//cache should be invalidated
-			if(i!=nBins[0])
-			{
-				needUpdate=true;
-				nBins[0]=i;
-				calculateWidthsFromNumBins(binWidth, nBins);
-				clearCache();
-			}
-			break;
-		}
 		case KEY_NBINSY:
-		{
-			 unsigned int i;
-			if(stream_cast(i,value))
-				return false;
-			if(!i)
-				return false;
-			needUpdate=true;
-			//if the result is different, the
-			//cache should be invalidated
-			if(i!=nBins[1])
-			{
-				needUpdate=true;
-				nBins[1]=i;
-				calculateWidthsFromNumBins(binWidth, nBins);
-				clearCache();
-			}
-			break;
-		}
 		case KEY_NBINSZ:
 		{
-			 unsigned int i;
-			if(stream_cast(i,value))
-				return false;
-			if(!i)
+			if(!applyPropertyNow(nBins[key-KEY_NBINSX],value,needUpdate))
 				return false;
-			
-			//if the result is different, the
-			//cache should be invalidated
-			if(i!=nBins[2])
-			{
-				needUpdate=true;
-				nBins[2]=i;
-				calculateWidthsFromNumBins(binWidth, nBins);
-				clearCache();
-			}
+			calculateWidthsFromNumBins(binWidth, nBins);
 			break;
 		}
 		case KEY_WIDTHBINSX:
-		{
-			float f;
-			if(stream_cast(f,value))
-				return false;
-			if(f <= 0.0f)
-				return false;
-		
-			if(f!=binWidth[0])
-			{
-				needUpdate=true;
-				binWidth[0]=f;
-				calculateNumBinsFromWidths(binWidth, nBins);
-				clearCache();
-			}
-			break;
-		}
 		case KEY_WIDTHBINSY:
-		{
-			float f;
-			if(stream_cast(f,value))
-				return false;
-			if(f <= 0.0f)
-				return false;
-			
-			if(f!=binWidth[1])
-			{
-				needUpdate=true;
-				binWidth[1]=f;
-				calculateNumBinsFromWidths(binWidth, nBins);
-				clearCache();
-			}
-			break;
-		}
 		case KEY_WIDTHBINSZ:
 		{
-			float f;
-			if(stream_cast(f,value))
+			if(!applyPropertyNow(binWidth[key-KEY_WIDTHBINSX],value,needUpdate))
 				return false;
-			if(f <= 0.0f)
-				return false;
-			if(f!=binWidth[2])
-			{
-				needUpdate=true;
-				binWidth[2]=f;
-				calculateNumBinsFromWidths(binWidth, nBins);
-				clearCache();
-			}
+			calculateNumBinsFromWidths(binWidth, nBins);
 			break;
 		}
 		case KEY_NORMALISE_TYPE:
@@ -1334,7 +1229,7 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 				return false;
 			needUpdate=true;
 			//Alpha is opacity, which is 1-transparancy
-			a=1.0f-f;
+			rgba.a(1.0f-f);
 			//Go in and manually adjust the cached
 			//entries to have the new value, rather
 			//than doing a full recomputation
@@ -1344,7 +1239,7 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 				{
 					VoxelStreamData *d;
 					d=(VoxelStreamData*)filterOutputs[ui];
-					d->a=a;
+					d->a=rgba.a();
 				}
 			}
 			break;
@@ -1374,16 +1269,17 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 		}
 		case KEY_COLOUR:
 		{
-			unsigned char newR,newG,newB,newA;
+			ColourRGBA tmpRGBA;
 
-			parseColString(value,newR,newG,newB,newA);
+			if(!tmpRGBA.parse(value))
+				return false;
 
-			if(newB != b || newR != r ||
-				newG !=g || newA != a)
+			if(tmpRGBA.toRGBAf() != rgba)
+			{
+				rgba=tmpRGBA.toRGBAf();
 				needUpdate=true;
-			r=newR/255.0;
-			g=newG/255.0;
-			b=newB/255.0;
+			}
+
 			//Go in and manually adjust the cached
 			//entries to have the new value, rather
 			//than doing a full recomputation
@@ -1393,9 +1289,9 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 				{
 					VoxelStreamData *d;
 					d=(VoxelStreamData*)filterOutputs[ui];
-					d->r=r;
-					d->g=g;
-					d->b=b;
+					d->r=rgba.r();
+					d->g=rgba.g();
+					d->b=rgba.b();
 				}
 			}
 			break;
@@ -1513,7 +1409,7 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 		case KEY_VOXEL_SLICE_COLOURAUTO:
 		{
 			bool b;
-			if(stream_cast(b,value))
+			if(!boolStrDec(value,b))
 				return false;
 
 			//if the result is different, the
@@ -1615,7 +1511,7 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 		case KEY_SHOW_COLOURBAR:
 		{
 			bool b;
-			if(stream_cast(b,value))
+			if(!boolStrDec(value,b))
 				return false;
 
 			//if the result is different, the
@@ -1672,7 +1568,7 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 			// TODO: This is a bit of a hack.
 			if (key >= KEY_ENABLE_DENOMINATOR*1000) {
 				bool b;
-				if(stream_cast(b,value))
+				if(!boolStrDec(value,b))
 					return false;
 
 				enabledIons[1][key - KEY_ENABLE_DENOMINATOR*1000]=b;
@@ -1683,7 +1579,7 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 				clearCache();
 			} else if (key >= KEY_ENABLE_NUMERATOR*1000) {
 				bool b;
-				if(stream_cast(b,value))
+				if(!boolStrDec(value,b))
 					return false;
 				
 				enabledIons[0][key - KEY_ENABLE_NUMERATOR*1000]=b;
@@ -1705,19 +1601,17 @@ bool VoxeliseFilter::setProperty(unsigned int key,
 
 std::string  VoxeliseFilter::getErrString(unsigned int code) const
 {
-	switch(code)
-	{
-		case VOXELISE_ABORT_ERR:
-			return std::string(TRANS("Voxelisation aborted"));
-		case VOXELISE_MEMORY_ERR:
-			return std::string(TRANS("Out of memory"));
-		case VOXELISE_CONVOLVE_ERR:
-			return std::string(TRANS("Unable to perform filter convolution"));
-		case VOXELISE_BOUNDS_INVALID_ERR:
-			return std::string(TRANS("Voxelisation bounds are invalid"));
-	}	
+	const char *errStrs[]={
+	 	"",
+		"Voxelisation aborted",
+		"Out of memory",
+		"Unable to perform filter convolution",
+		"Voxelisation bounds are invalid",
+	};
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(errStrs) == VOXELISE_ERR_ENUM_END);	
 	
-	return std::string("BUG! Should not see this (VoxeliseFilter)");
+	ASSERT(code < VOXELISE_ERR_ENUM_END);
+	return errStrs[code];
 }
 
 bool VoxeliseFilter::writeState(std::ostream &f,unsigned int format, unsigned int depth) const
@@ -1737,29 +1631,28 @@ bool VoxeliseFilter::writeState(std::ostream &f,unsigned int format, unsigned in
 
 			f << tabs(depth+2) << "<numerator>" << endl;
 			for(unsigned int ui=0;ui<enabledIons[0].size(); ui++)
-				f << tabs(depth+3) << "<enabled value=\"" << (enabledIons[0][ui]?1:0) << "\"/>" << endl;
+				f << tabs(depth+3) << "<enabled value=\"" << boolStrEnc(enabledIons[0][ui]) << "\"/>" << endl;
 			f << tabs(depth+2) << "</numerator>" << endl;
 
 			f << tabs(depth+2) << "<denominator>" << endl;
 			for(unsigned int ui=0;ui<enabledIons[1].size(); ui++)
-				f << tabs(depth+3) << "<enabled value=\"" << (enabledIons[1][ui]?1:0) << "\"/>" << endl;
+				f << tabs(depth+3) << "<enabled value=\"" << boolStrEnc(enabledIons[1][ui]) << "\"/>" << endl;
 			f << tabs(depth+2) << "</denominator>" << endl;
 
 			f << tabs(depth+1) << "</enabledions>" << endl;
 
 			f << tabs(depth+1) << "<representation value=\""<<representation << "\"/>" << endl;
 			f << tabs(depth+1) << "<isovalue value=\""<<isoLevel << "\"/>" << endl;
-			f << tabs(depth+1) << "<colour r=\"" <<  r<< "\" g=\"" << g << "\" b=\"" <<b
-				<< "\" a=\"" << a << "\"/>" <<endl;
+			f << tabs(depth+1) << "<colour r=\"" <<  rgba.r()<< "\" g=\"" << rgba.g() << "\" b=\"" <<rgba.b()
+				<< "\" a=\"" << rgba.a() << "\"/>" <<endl;
 
 			f << tabs(depth+1) << "<axialslice>" << endl;
 			f << tabs(depth+2) << "<offset value=\""<<sliceOffset<< "\"/>" << endl;
 			f << tabs(depth+2) << "<interpolate value=\""<<sliceInterpolate<< "\"/>" << endl;
 			f << tabs(depth+2) << "<axis value=\""<<sliceAxis<< "\"/>" << endl;
-			f << tabs(depth+2) << "<colourbar show=\""<<(showColourBar?1:0)<< 
-					"\" auto=\"" << (autoColourMap?1:0)<< "\" min=\"" <<
-					colourMapBounds[0] << "\" max=\"" << 
-					colourMapBounds[1] << "\"/>" << endl;
+			f << tabs(depth+2) << "<colourbar show=\""<<boolStrEnc(showColourBar)<< 
+						"\" auto=\"" << boolStrEnc(autoColourMap)<< "\" min=\"" <<
+					colourMapBounds[0] << "\" max=\"" <<  colourMapBounds[1] << "\"/>" << endl;
 			f << tabs(depth+1) << "</axialslice>" << endl;
 
 
@@ -1797,11 +1690,7 @@ bool VoxeliseFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFile
 	//Retrieve fixedWidth mode
 	if(!XMLGetNextElemAttrib(nodePtr,tmpStr,"fixedwidth","value"))
 		return false;
-	if(tmpStr == "1") 
-		fixedWidth=true;
-	else if(tmpStr== "0")
-		fixedWidth=false;
-	else
+	if(!boolStrDec(tmpStr,fixedWidth))
 		return false;
 	
 	//Retrieve nBins	
@@ -1942,8 +1831,10 @@ bool VoxeliseFilter::readState(xmlNodePtr &nodePtr, const std::string &stateFile
 	//====
 	if(XMLHelpFwdToElem(nodePtr,"colour"))
 		return false;
-	if(!parseXMLColour(nodePtr,r,g,b,a))
+	ColourRGBAf tmpRgba;
+	if(!parseXMLColour(nodePtr,tmpRgba))
 		return false;
+	rgba=tmpRgba;
 
 	//====
 
diff --git a/src/backend/filters/voxelise.h b/src/backend/filters/voxelise.h
index 3ceb373..25b6f24 100644
--- a/src/backend/filters/voxelise.h
+++ b/src/backend/filters/voxelise.h
@@ -48,7 +48,7 @@ private:
 	//This is filter's enabled ranges
 	RangeStreamData *rsdIncoming;
 	
-	float r,g,b,a;
+	ColourRGBAf rgba;
 
 	//!Filter mode to apply to data before output
 	unsigned int filterMode;
diff --git a/src/backend/filtertree.cpp b/src/backend/filtertree.cpp
index d9ad635..34a3e8e 100644
--- a/src/backend/filtertree.cpp
+++ b/src/backend/filtertree.cpp
@@ -43,6 +43,9 @@ class FilterRefreshCollector
 		//Pile of lists of pointers that we are tracking
 		vector<list<const FilterStreamData *> > nodes;
 
+		//List of pointers we should *not* erase
+		set<const FilterStreamData *> forgottenNodes;
+
 		//Find out if a filter tracks itself or not
 		static bool tracksSelf(const FilterStreamData *p) { return p->cached;}
 
@@ -78,22 +81,16 @@ void FilterRefreshCollector::checkSanity()
 		for(list<const FilterStreamData *>::iterator it=nodes[ui].begin();
 				it!=nodes[ui].end(); ++it)
 		{
-			//Check that we hve not already inserted this
+			//Should never have something that tracks itself
+			ASSERT(!tracksSelf(*it) )
+			//Check that we have not already inserted this
 			ASSERT(s.find(*it) == s.end())
 			s.insert(*it);
-		}
-	}
-	s.clear();
 
-	//Should never have something that tracks itself
-	for(size_t ui=0;ui<nodes.size();ui++)
-	{
-		for(list<const FilterStreamData *>::iterator it=nodes[ui].begin();
-				it!=nodes[ui].end(); ++it)
-		{
-			ASSERT(!tracksSelf(*it) )
+			ASSERT(forgottenNodes.find(*it) == forgottenNodes.end());
 		}
 	}
+	s.clear();
 
 }
 #endif
@@ -126,6 +123,8 @@ void FilterRefreshCollector::trackPointers(const vector<const FilterStreamData *
 
 			}
 
+			found|=(forgottenNodes.find(v[ui])  != forgottenNodes.end());
+
 			if(!found)
 				lKeep.push_back(v[ui]);
 		}
@@ -150,9 +149,10 @@ void FilterRefreshCollector::forgetPointers(const vector<const FilterStreamData
 			it=std::find(nodes[ui].begin(),nodes[ui].end(),v[uj]) ;
 			if(it != nodes[ui].end())
 			{
-				nodes[ui].erase(it);
+				forgottenNodes.insert(*it);
 				//We deleted the source of this, no need to continue
 				// checking for this particular pointer.
+				nodes[ui].erase(it);
 				break;
 			}
 		}
@@ -652,37 +652,39 @@ unsigned int FilterTree::refreshFilterTree(list<FILTER_OUTPUT_DATA > &outData,
 			//Step 2: Check if we should cache this filter or not.
 			//Get the number of bytes that the filter expects to use
 			//---
-			unsigned long long cacheBytes;
-			if(inDataStack.empty())
-				cacheBytes=currentFilter->numBytesForCache(0);
-			else
-				cacheBytes=currentFilter->numBytesForCache(numElements(inDataStack.top()));
-
-			if(cacheBytes != (unsigned long long)(-1))
+			if(!currentFilter->haveCache())
 			{
-				//As long as we have caching enabled, let us cache according to the
-				//selected strategy
-				switch(cacheStrategy)
+				unsigned long long cacheBytes;
+				if(inDataStack.empty())
+					cacheBytes=currentFilter->numBytesForCache(0);
+				else
+					cacheBytes=currentFilter->numBytesForCache(numElements(inDataStack.top()));
+
+				if(cacheBytes != (unsigned long long)(-1))
 				{
-					case CACHE_NEVER:
-						currentFilter->setCaching(false);
-						break;
-					case CACHE_DEPTH_FIRST:
+					//As long as we have caching enabled, let us cache according to the
+					//selected strategy
+					switch(cacheStrategy)
 					{
-						float ramFreeForUse;
-						ramFreeForUse= maxCachePercent/(float)100.0f*getAvailRAM();
-
-						bool cache;
-						cache=(cacheBytes/(1024*1024) ) < ramFreeForUse;
-
-						currentFilter->setCaching( cache);
-						break;
+						case CACHE_NEVER:
+							currentFilter->setCaching(false);
+							break;
+						case CACHE_DEPTH_FIRST:
+						{
+							float ramFreeForUse;
+							ramFreeForUse= maxCachePercent/(float)100.0f*getAvailRAM();
+
+							bool cache;
+							cache=(cacheBytes/(1024*1024) ) < ramFreeForUse;
+
+							currentFilter->setCaching( cache);
+							break;
+						}
 					}
 				}
+				else
+					currentFilter->setCaching(false);
 			}
-			else
-				currentFilter->setCaching(false);
-
 			//---
 
 			//Step 3: Take the stack top, and turn it into "curdata" and refresh using the filter.
@@ -779,7 +781,7 @@ unsigned int FilterTree::refreshFilterTree(list<FILTER_OUTPUT_DATA > &outData,
 				refreshCollector.trackPointers(curData);
 				
 				//Put this in the intermediary stack, 
-				//so it is available for any other children at this leve.
+				//so it is available for any other children at this level.
 				inDataStack.push(curData);
 			}
 			else if(curData.size())
@@ -788,7 +790,7 @@ unsigned int FilterTree::refreshFilterTree(list<FILTER_OUTPUT_DATA > &outData,
 				outData.push_back(make_pair(currentFilter,curData));
 				refreshCollector.forgetPointers(curData);
 			}	
-			//Cur data is recorded either in outDta or on the data stack
+			//Cur data is recorded either in outData or on the data stack
 			curData.clear();
 			//---
 			
@@ -1224,7 +1226,7 @@ void FilterTree::stripHazardousContents()
 
 bool FilterTree::isChild(const tree<Filter *> &treeInst,
 				const tree<Filter *>::iterator &testParent,
-				tree<Filter *>::iterator testChild) const 
+				tree<Filter *>::iterator testChild) 
 {
 	// NOTE: A comparison against tree root (treeInst.begin())is INVALID
 	// for trees that have multiple base nodes.
@@ -1320,7 +1322,6 @@ void FilterTree::checkRefreshValidity(const vector< const FilterStreamData *> &c
 	//Filter outputs should
 	//	- Always have isCached set to 0 or 1.
 	//	- Filter should report that it has a cache, if it is emitting cached objects
-	//	- If caching is disabled, filter should not be caching objects
 	bool hasSomeCached=false;
 	for(size_t ui=0; ui<curData.size(); ui++)
 	{
@@ -1328,13 +1329,7 @@ void FilterTree::checkRefreshValidity(const vector< const FilterStreamData *> &c
 				curData[ui]->cached == 0);
 
 		if(curData[ui]->parent == refreshFilter)
-		{
-			if(!(refreshFilter->cacheEnabled()) )
-			{
-				ASSERT(curData[ui]->cached==0);
-			}
 			hasSomeCached|=curData[ui]->cached;
-		}
 	}
 
 	ASSERT(!(hasSomeCached == false && refreshFilter->haveCache()));
@@ -1420,7 +1415,7 @@ void FilterTree::checkRefreshValidity(const vector< const FilterStreamData *> &c
 #endif
 
 void FilterTree::safeDeleteFilterList( std::list<FILTER_OUTPUT_DATA> &outData, 
-						size_t typeMask, bool maskPrevents) const
+						size_t typeMask, bool maskPrevents) 
 {
 	//Loop through the list of vectors of filterstreamdata, then drop any elements that are deleted
 	for(list<FILTER_OUTPUT_DATA> ::iterator it=outData.begin(); 
diff --git a/src/backend/filtertree.h b/src/backend/filtertree.h
index 2baaa29..ca57afd 100644
--- a/src/backend/filtertree.h
+++ b/src/backend/filtertree.h
@@ -73,9 +73,9 @@ class FilterTree
 		//!Returns true if the testChild is a child of testParent.
 		// returns false if testchild == testParent, or if the testParent
 		// is not a parent of testChild.
-		bool isChild(const tree<Filter *> &treeInst,
+		static bool isChild(const tree<Filter *> &treeInst,
 				const tree<Filter *>::iterator &testParent,
-				tree<Filter *>::iterator testChild) const;
+				tree<Filter *>::iterator testChild);
 
 
 		static size_t countChildFilters(const tree<Filter *> &treeInst,
@@ -130,8 +130,8 @@ class FilterTree
 		
 		//!Safely delete data generated by refreshFilterTree(...). 
 		//a mask can be used to *prevent* STREAM_TYPE_blah from being deleted. Deleted items are removed from the list.
-		void safeDeleteFilterList(std::list<FILTER_OUTPUT_DATA> &outData, 
-								size_t typeMask=STREAMTYPE_MASK_ALL, bool maskPrevents=false) const;
+		static void safeDeleteFilterList(std::list<FILTER_OUTPUT_DATA> &outData, 
+								size_t typeMask=STREAMTYPE_MASK_ALL, bool maskPrevents=false);
 
 		//!compute the integrated (accumulated) propagation maps for emission and blocking.
 		// For emission this value gives the possible types that
diff --git a/src/backend/filtertreeAnalyse.cpp b/src/backend/filtertreeAnalyse.cpp
index e346c5e..7500c2b 100644
--- a/src/backend/filtertreeAnalyse.cpp
+++ b/src/backend/filtertreeAnalyse.cpp
@@ -401,13 +401,14 @@ bool filterAltersComposition(const Filter *f)
 
 			p=props.getPropValue(KEY_IONDOWNSAMPLE_PERSPECIES);
 
+			const int GROUP_SAMPLING=1;
 			
-			if(p.data== "1")
+			if(p.data== "1" && props.hasGroup(GROUP_SAMPLING))
 			{
 				vector<FilterProperty> propVec;
-				const int GROUP_SAMPLING=1;
 				props.getGroup(GROUP_SAMPLING,propVec);
 
+
 				//If using per-species mode, then
 				// we may affect the output ion composition
 				// if we have differing values
diff --git a/src/backend/plot.cpp b/src/backend/plot.cpp
index ea958a0..a6c5e99 100644
--- a/src/backend/plot.cpp
+++ b/src/backend/plot.cpp
@@ -21,9 +21,7 @@
 
 #include "common/translation.h"
 
-#ifdef USE_MGL2
-	#include <mgl2/canvas_wnd.h>
-#endif
+#include <mgl2/canvas_wnd.h>
 
 //!Plot error bar estimation strings
 const char *errModeStrings[] = { 
@@ -31,12 +29,15 @@ const char *errModeStrings[] = {
 				NTRANS("Moving avg.")
 				};
 
-const char *plotModeStrings[]= {
+const char *plotTypeStrings[]= {
 	NTRANS("Lines"),
 	NTRANS("Bars"),
 	NTRANS("Steps"),
 	NTRANS("Stem"),
-	NTRANS("Points")
+	NTRANS("Points"),
+	(""),
+	NTRANS("Density"),
+	NTRANS("Scatter"),
 				};
 
 using std::string;
@@ -47,118 +48,6 @@ using std::vector;
 // perform a little "push off" by this fudge factor
 const float AXIS_MIN_TOLERANCE=10*sqrtf(std::numeric_limits<float>::epsilon());
 
-int MGLColourFixer::maxCols=-1;
-
-void MGLColourFixer::reset()
-{
-	rs.clear();
-	gs.clear();
-	bs.clear();
-}
-
-char MGLColourFixer::haveExactColour(float r, float g, float b) const
-{
-	ASSERT(rs.size() == gs.size())
-	ASSERT(gs.size() == bs.size())
-
-	ASSERT(rs.size() <=getMaxColours());
-
-	for(unsigned int ui=0; ui<rs.size(); ui++)
-	{
-		if( fabs(r-rs[ui]) <std::numeric_limits<float>::epsilon()
-			&& fabs(g-gs[ui]) <std::numeric_limits<float>::epsilon()
-			&& fabs(b-bs[ui]) <std::numeric_limits<float>::epsilon())
-			return mglColorIds[ui+1].id; //Add one to offset to avoid the reserved "k" 
-	}
-
-	return 0;
-}
-
-unsigned int MGLColourFixer::getMaxColours() 
-{
-	//Used cached value if available
-	if(maxCols!=-1)
-		return maxCols;
-
-	//The array is statically defined in
-	//mgl/mgl_main.cpp, and must end with an id of zero.
-	//
-	//this is not documented at all.
-	maxCols=0;
-	while(mglColorIds[maxCols].id)
-		maxCols++;
-
-	return maxCols;
-}
-
-char MGLColourFixer::getNextBestColour(float r, float g, float b) 
-{
-	ASSERT(rs.size() == gs.size());
-	ASSERT(gs.size() == bs.size());
-	
-
-	//As a special case, mgl has its own black
-	if(r == 0.0f && g == 0.0f && b == 0.0f)
-		return mglColorIds[0].id;
-
-
-	unsigned int best=0;
-	if(rs.size() == getMaxColours())
-	{
-		ASSERT(getMaxColours());
-		//Looks like we ran out of palette colours.
-		//lets just give up and try to match this against our existing colours
-
-		//TODO: let this modify the existing palette
-		// to find a better match.
-		float distanceSqr=std::numeric_limits<float>::max();
-		for(unsigned int ui=0; ui<rs.size(); ui++)
-		{
-			float distanceTmp;
-			if(r <= 0.5)
-			{
-				//3,4,2 weighted euclidean distance. Weights allow for closer human perception
-				distanceTmp= 3.0*(rs[ui] - r )*(rs[ui] - r ) +4.0*(gs[ui] - g )*(gs[ui] - g )
-					     + 2.0*(bs[ui] - b )*(bs[ui] - b );
-			}
-			else
-			{
-				//use alternate weighting for closer colour perception in "non-red" half of colour cube
-				distanceTmp= 2.0*(rs[ui] - r )*(rs[ui] - r ) +4.0*(gs[ui] - g )*(gs[ui] - g )
-					     + 3.0*(bs[ui] - b )*(bs[ui] - b );
-			}
-
-			if(distanceTmp < distanceSqr)
-			{
-				distanceSqr = (distanceTmp);
-				best=ui+1; //offset by 1 because mathgl colour 0 is special
-			}
-
-		}
-	}
-	else
-	{
-		char exactMatch;
-		//Check to see if we don't already have this
-		// no use wasting palette positions on existing
-		// colours
-		exactMatch=haveExactColour(r,g,b);
-
-		if(exactMatch)
-			return exactMatch;
-
-		//Offset zero is special, for black things, like axes
-		best=rs.size()+1;
-		mglColorIds[best].col = mglColor(r,g,b);
-		
-		rs.push_back(r);
-		gs.push_back(g);
-		bs.push_back(b);
-	}
-
-	ASSERT(mglColorIds[best].id != 'k');
-	return mglColorIds[best].id;
-}
 
 //Mathgl uses some internal for(float=...) constructions, 
 // which are just generally a bad idea, as they often won't terminate
@@ -209,19 +98,35 @@ std::string wstrToStr(const std::wstring& s)
 }
 
 
+std::string mglColourCode(float r, float g, float b)
+{
+	ASSERT(r >=0.0f && g >=0.0f && b >=0.0f)
+	ASSERT(r <=255.0f && g <=255.0f && b <=255.0f)
+
+	ColourRGBA rgba(r*255.0,g*255.0,b*255.0);
+
+	std::string s;
+	//Make a #rrggbb hex string
+	s=rgba.rgbString();
+	s=s.substr(1);
+
+	return string("{x") + uppercase(s) + string("}");
+}
+
 //TODO: Refactor these functions to use a common string map
 //-----------
-string plotString(unsigned int traceType)
+string plotString(unsigned int plotMode)
 {
-	ASSERT(traceType< PLOT_TRACE_ENDOFENUM);
-	return TRANS(plotModeStrings[traceType]); 
+	ASSERT(plotMode< PLOT_TYPE_ENUM_END);
+	return TRANS(plotTypeStrings[plotMode]); 
 }
 
 unsigned int plotID(const std::string &plotString)
 {
-	for(unsigned int ui=0;ui<PLOT_TRACE_ENDOFENUM; ui++)
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(plotTypeStrings) == PLOT_TYPE_ENUM_END);
+	for(unsigned int ui=0;ui<PLOT_TYPE_ENUM_END; ui++)
 	{
-		if(plotString==TRANS(plotModeStrings[ui]))
+		if(plotString==TRANS(plotTypeStrings[ui]))
 			return ui;
 	}
 
@@ -441,7 +346,7 @@ std::string PlotRegion::getName() const
 
 PlotWrapper::PlotWrapper()
 {
-	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(plotModeStrings) == PLOT_TRACE_ENDOFENUM);
+	//COMPILE_ASSERT(THREEDEP_ARRAYSIZE(plotTypeStrings) == PLOT_TYPE_ENUM_END);
 
 	applyUserBounds=false;
 	plotChanged=true;
@@ -489,12 +394,13 @@ const PlotWrapper &PlotWrapper::operator=(const PlotWrapper &p)
 	return *this;
 }
 
-std::wstring PlotWrapper::getTitle(size_t plotId) const
+std::string PlotWrapper::getTitle(size_t plotId) const
 {
 	unsigned int plotPos=plotIDHandler.getPos(plotId);
-	return plottingData[plotPos]->title;
+	return plottingData[plotPos]->getTitle();
 }
 
+
 void PlotWrapper::getPlotIDs(vector<unsigned int> &ids) const
 {
 	plotIDHandler.getIds(ids);
@@ -511,6 +417,10 @@ size_t PlotWrapper::getParentType(size_t plotId) const
 
 unsigned int PlotWrapper::addPlot(PlotBase *p)
 {
+#ifdef DEBUG
+	p->checkConsistent();
+#endif
+
 	plottingData.push_back(p);
 
 	//assign a unique identifier to this plot, by which it can be referenced
@@ -554,36 +464,23 @@ void PlotWrapper::setStrings(unsigned int plotID, const std::string &x,
 				const std::string &y, const std::string &t)
 {
 	unsigned int plotPos=plotIDHandler.getPos(plotID);
-	plottingData[plotPos]->xLabel = strToWStr(x);
-	plottingData[plotPos]->yLabel = strToWStr(y);
-	
-	plottingData[plotPos]->title = strToWStr(t);
-	plotChanged=true;
-}
 
-void PlotWrapper::setParentData(unsigned int plotID, const void *parentObj, unsigned int idx)
-{
-	unsigned int plotPos=plotIDHandler.getPos(plotID);
-	plottingData[plotPos]->parentObject= parentObj;
-	plottingData[plotPos]->parentPlotIndex=idx;
-	
+	plottingData[plotPos]->setStrings(x,y,t);
 	plotChanged=true;
 }
 
 void PlotWrapper::setTraceStyle(unsigned int plotUniqueID,unsigned int mode)
 {
 
-	ASSERT(mode<PLOT_TRACE_ENDOFENUM);
-	plottingData[plotIDHandler.getPos(plotUniqueID)]->traceType=mode;
+	ASSERT(mode<PLOT_TYPE_ENUM_END);
+	plottingData[plotIDHandler.getPos(plotUniqueID)]->setPlotMode(mode);
 	plotChanged=true;
 }
 
-void PlotWrapper::setColours(unsigned int plotUniqueID, float rN,float gN,float bN) 
+void PlotWrapper::setColours(unsigned int plotUniqueID, float r,float g,float b) 
 {
 	unsigned int plotPos=plotIDHandler.getPos(plotUniqueID);
-	plottingData[plotPos]->r=rN;
-	plottingData[plotPos]->g=gN;
-	plottingData[plotPos]->b=bN;
+	plottingData[plotPos]->setColour(r,g,b);
 	plotChanged=true;
 }
 
@@ -703,8 +600,70 @@ void PlotWrapper::bestEffortRestoreVisibility()
 	plotChanged=true;
 }
 
+
+void PlotWrapper::getAppliedBounds(mglPoint &min, mglPoint &max) const
+{
+	
+	if(applyUserBounds)
+	{
+		ASSERT(yUserMax >=yUserMin);
+		ASSERT(xUserMax >=xUserMin);
+
+		max.x =xUserMax;
+		max.y=yUserMax;
+		
+		min.x =xUserMin;
+		min.y =yUserMin;
+
+	}
+	else
+	{
+		//Retrieve the bounds of the data that is in the plot
+		float minX,maxX,minY,maxY;
+		minX=std::numeric_limits<float>::max();
+		maxX=-std::numeric_limits<float>::max();
+		minY=std::numeric_limits<float>::max();
+		maxY=-std::numeric_limits<float>::max();
+		
+		for(unsigned int ui=0;ui<plottingData.size(); ui++)
+		{
+			if(plottingData[ui]->visible)
+			{
+				float tmpMinX,tmpMinY,tmpMaxX,tmpMaxY;
+				plottingData[ui]->getBounds(
+					tmpMinX,tmpMaxX,tmpMinY,tmpMaxY);
+
+				minX=std::min(minX,tmpMinX);
+				maxX=std::max(maxX,tmpMaxX);
+				minY=std::min(minY,tmpMinY);
+				maxY=std::max(maxY,tmpMaxY);
+			}
+		}
+
+		min.x=minX;
+		min.y=minY;
+		max.x=maxX;
+		max.y=maxY;
+
+	}
+
+
+	//"Push" bounds around to prevent min == max
+	// This is a hack to prevent mathgl from inf. looping
+	//---
+	if(mglFloatTooClose(min.x , max.x))
+	{
+		min.x-=0.05;
+		max.x+=0.05;
+	}
+
+	if(mglFloatTooClose(min.y , max.y))
+		max.y+=0.01;
+	//------
+}
+
 void PlotWrapper::getRawData(vector<vector<vector<float> > > &data,
-				std::vector<std::vector<std::wstring> > &labels) const
+				std::vector<std::vector<std::string> > &labels) const
 {
 	if(plottingData.empty())
 		return;
@@ -712,9 +671,10 @@ void PlotWrapper::getRawData(vector<vector<vector<float> > > &data,
 	//Determine if we have multiple types of plot.
 	//if so, we cannot really return the raw data for this
 	//in a meaningful fashion
-	switch(getVisibleType())
+	switch(getVisibleMode())
 	{
-		case PLOT_TYPE_ONED:
+		case PLOT_MODE_1D:
+		case PLOT_MODE_2D:
 		{
 			//Try to retrieve the raw data from the visible plots
 			for(unsigned int ui=0;ui<plottingData.size();ui++)
@@ -722,7 +682,7 @@ void PlotWrapper::getRawData(vector<vector<vector<float> > > &data,
 				if(plottingData[ui]->visible)
 				{
 					vector<vector<float> > thisDat,dummy;
-					vector<std::wstring> thisLabel;
+					vector<std::string> thisLabel;
 					plottingData[ui]->getRawData(thisDat,thisLabel);
 					
 					//Data title size should hopefully be the same
@@ -740,35 +700,36 @@ void PlotWrapper::getRawData(vector<vector<vector<float> > > &data,
 			}
 			break;
 		}
-		case PLOT_TYPE_ENUM_END:
+		case PLOT_MODE_ENUM_END:
+		case PLOT_MODE_MIXED:
 			return;
 		default:
 			ASSERT(false);
 	}
 }
 
-unsigned int PlotWrapper::getVisibleType() const
+unsigned int PlotWrapper::getVisibleMode() const
 {
-	unsigned int visibleType=PLOT_TYPE_ENUM_END;
+	unsigned int visibleMode=PLOT_MODE_ENUM_END;
 	for(unsigned int ui=0;ui<plottingData.size() ; ui++)
 	{
 		if(plottingData[ui]->visible &&
-			plottingData[ui]->plotType!= visibleType)
+			plottingData[ui]->getPlotMode()!= visibleMode)
 		{
-			if(visibleType == PLOT_TYPE_ENUM_END)
+			if(visibleMode == PLOT_MODE_ENUM_END)
 			{
-				visibleType=plottingData[ui]->plotType;
+				visibleMode=plottingData[ui]->getMode();
 				continue;
 			}
 			else
 			{
-				visibleType=PLOT_TYPE_MIXED;
+				visibleMode=PLOT_MODE_MIXED;
 				break;
 			}
 		}
 	}
 
-	return visibleType;
+	return visibleMode;
 }
 
 void PlotWrapper::getVisibleIDs(vector<unsigned int> &visiblePlotIDs ) const
@@ -794,68 +755,53 @@ void PlotWrapper::findRegionLimit(unsigned int plotId, unsigned int regionId,
 
 void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 {
-	unsigned int visType = getVisibleType();
-	if(visType == PLOT_TYPE_ENUM_END || 
-		visType == PLOT_TYPE_MIXED)
+	unsigned int visMode = getVisibleMode();
+	if(visMode == PLOT_MODE_ENUM_END || 
+		visMode == PLOT_MODE_MIXED)
 	{
 		//We don't handle the drawing case well here, so assert this.
 		// calling code should check this case and ensure that it draws something
 		// meaningful
-		ASSERT(false);
+		WARN(false,"Mixed calling code");
 		return;
 	}
 
 	//Un-fudger for mathgl plots
-	MGLColourFixer colourFixer;
 
 	bool haveMultiTitles=false;
-	float minX,maxX,minY,maxY;
-	minX=std::numeric_limits<float>::max();
-	maxX=-std::numeric_limits<float>::max();
-	minY=std::numeric_limits<float>::max();
-	maxY=-std::numeric_limits<float>::max();
 
 	//Compute the bounding box in data coordinates	
-	std::wstring xLabel,yLabel,plotTitle;
+	std::string xLabel,yLabel,plotTitle;
 
 	for(unsigned int ui=0;ui<plottingData.size(); ui++)
 	{
 		if(plottingData[ui]->visible)
 		{
-			float tmpMinX,tmpMinY,tmpMaxX,tmpMaxY;
-			plottingData[ui]->getBounds(
-				tmpMinX,tmpMaxX,tmpMinY,tmpMaxY);
-
-			minX=std::min(minX,tmpMinX);
-			maxX=std::max(maxX,tmpMaxX);
-			minY=std::min(minY,tmpMinY);
-			maxY=std::max(maxY,tmpMaxY);
-
 
 			if(!xLabel.size())
-				xLabel=plottingData[ui]->xLabel;
+				xLabel=plottingData[ui]->getXLabel();
 			else
 			{
 
-				if(xLabel!=plottingData[ui]->xLabel)
-					xLabel=stlStrToStlWStr(TRANS("Multiple data types"));
+				if(xLabel!=plottingData[ui]->getXLabel())
+					xLabel=string(TRANS("Multiple data types"));
 			}
 			if(!yLabel.size())
-				yLabel=plottingData[ui]->yLabel;
+				yLabel=plottingData[ui]->getYLabel();
 			else
 			{
 
-				if(yLabel!=plottingData[ui]->yLabel)
-					yLabel=stlStrToStlWStr(TRANS("Multiple data types"));
+				if(yLabel!=plottingData[ui]->getYLabel())
+					yLabel=string(TRANS("Multiple data types"));
 			}
 			if(!haveMultiTitles && !plotTitle.size())
-				plotTitle=plottingData[ui]->title;
+				plotTitle=plottingData[ui]->getTitle();
 			else
 			{
 
-				if(plotTitle!=plottingData[ui]->title)
+				if(plotTitle!=plottingData[ui]->getTitle())
 				{
-					plotTitle=L"";//L prefix means wide char
+					plotTitle="";
 					haveMultiTitles=true;
 				}
 			}
@@ -864,8 +810,6 @@ void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 		}
 	}
 
-
-
 	string sX,sY;
 	sX.assign(xLabel.begin(),xLabel.end()); //unicode conversion
 	sY.assign(yLabel.begin(),yLabel.end()); //unicode conversion
@@ -877,87 +821,46 @@ void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 
 	haveUsedLog=false;
 	mglPoint min,max;
-	switch(visType)
+	//work out the bounding box for the plot,
+	//and where the axis should cross
+	getAppliedBounds(min,max);
+	
+	//set up the graph axes as needed
+	switch(visMode)
 	{
-		case PLOT_TYPE_ONED:
+		case PLOT_MODE_1D:
 		{
 			//OneD connected value line plot f(x)
 			bool useLogPlot=false;
-			bool notLog=false;
 
 		
 			for(unsigned int ui=0;ui<plottingData.size(); ui++)
 			{
-				if(plottingData[ui]->visible)
-				{
-					if(((Plot1D*)plottingData[ui])->wantLogPlot()) 
-						useLogPlot=true;
-					else
-						notLog=true;
-				}
+				if(!plottingData[ui]->visible)
+					continue;
+
+				if(plottingData[ui]->getType()!= PLOT_MODE_1D)
+					continue;
+			
+				if(((Plot1D*)plottingData[ui])->wantLogPlot()) 
+					useLogPlot=true;
 			}
 
 			haveUsedLog|=useLogPlot;
 		
-			//work out the bounding box for the plot,
-			//and where the axis should cross
-			mglPoint axisCross;
-			if(applyUserBounds)
-			{
-				ASSERT(yUserMax >=yUserMin);
-				ASSERT(xUserMax >=xUserMin);
-
-				max.x =xUserMax;
-				max.y=yUserMax;
-				
-				min.x =xUserMin;
-				min.y =yUserMin;
 
-				axisCross.x=min.x;
-				axisCross.y=min.y;
-				
-			}
-			else
-			{
-				//Retrieve the bounds of the data that is in the plot
-
-				min.x=minX;
-				min.y=minY;
-				max.x=maxX;
-				max.y=maxY;
-
-				axisCross.x = minX;
-				axisCross.y=min.y;
-			}
 			
-			//Allow logarithmic mode, as needed.
+			//Allow for logarithmic mode, as needed.
 			// mathgl does not like a zero coordinate for plotting
 			if(min.y == 0 && useLogPlot)
 			{
 				min.y=0.1;
-				if(axisCross.y < min.y)
-					axisCross.y=min.y;
-			}
-			//"Push" bounds around to prevent min == max
-			// This is a hack to prevent mathgl from inf. looping
-			//---
-			if(mglFloatTooClose(min.x , max.x))
-			{
-				min.x-=5;
-				max.x+=5;
 			}
-
-			if(mglFloatTooClose(min.y , max.y))
-				max.y+=1;
-			//------
 			
 
 			//tell mathgl about the bounding box	
-#ifdef USE_MGL2
 			gr->SetRanges(min,max);
-			
-			gr->SetOrigin(axisCross);
-#endif
+			gr->SetOrigin(min);
 
 			WARN((fabs(min.x-max.x) > sqrt(std::numeric_limits<float>::epsilon())), 
 					"WARNING: Mgl limits (X) too Close! Due to limitiations in MGL, This may inf. loop!");
@@ -968,24 +871,19 @@ void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 				gr->SetFunc("","lg(y)");
 			else
 				gr->SetFunc("","");
-#ifdef USE_MGL2
-			gr->Axis();
 
 			mglCanvas *canvas = dynamic_cast<mglCanvas *>(gr->Self());
 			canvas->AdjustTicks("x");
 			canvas->SetTickTempl('x',"%g"); //Set the tick type
 			canvas->Axis("xy"); //Build an X-Y crossing axis
-#else
-			gr->Axis(min,max,axisCross);
-			gr->AdjustTicks("x");
-			gr->SetXTT("%g"); //Set the tick type
-			gr->Axis("xy"); //Build an X-Y crossing axis
-#endif
 			//---
 
 			//Loop through the plots, drawing them as needed
 			for(unsigned int ui=0;ui<plottingData.size();ui++)
 			{
+				if(plottingData[ui]->getPlotMode() != PLOT_MODE_1D)
+					continue;
+
 				Plot1D *curPlot;
 				curPlot=(Plot1D*)plottingData[ui];
 
@@ -994,17 +892,15 @@ void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 				if(!curPlot->visible)
 					continue;
 
-				curPlot->drawRegions(gr,colourFixer,min,max);
-				curPlot->drawPlot(gr,colourFixer);
+				curPlot->drawRegions(gr,min,max);
+				curPlot->drawPlot(gr);
 				
 				if(drawLegend)
 				{
-					//Fake an mgl colour code
-					char colourCode[2];
-					colourCode[0]=colourFixer.getNextBestColour(
-							curPlot->r,curPlot->g,curPlot->b);
-					colourCode[1]='\0';
-					gr->AddLegend(curPlot->title.c_str(),colourCode);
+					float r,g,b;
+					curPlot->getColour(r,g,b);
+					std::string mglColStr= mglColourCode(r,g,b);
+					gr->AddLegend(curPlot->getTitle().c_str(),mglColStr.c_str());
 				}
 			}
 
@@ -1017,7 +913,7 @@ void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 				vector<pair<size_t,size_t> > overlapId;
 				vector<pair<float,float> > overlapXCoords;
 
-				char colourCode=colourFixer.getNextBestColour(1.0f,0.0f,0.0f);
+				string colourCode=mglColourCode(1.0f,0.0f,0.0f);
 				getRegionOverlaps(overlapId,overlapXCoords);
 
 				float rMinY,rMaxY;
@@ -1043,19 +939,47 @@ void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 						continue;
 
 
-#ifdef USE_MGL2
 					gr->FaceZ(mglPoint(rMinX,rMinY,-1),rMaxX-rMinX,rMaxY-rMinY,
-							&colourCode);
-#else
-					gr->FaceZ(rMinX,rMinY,-1,rMaxX-rMinX,rMaxY-rMinY,
-							&colourCode);
-#endif
+							colourCode.c_str());
 				}
 
 			}
 
 			break;
 		}
+		case PLOT_MODE_2D:
+		{
+
+			gr->SetFunc("","");
+			gr->SetRanges(min,max);
+			gr->SetOrigin(min);
+			
+			gr->Axis();
+			bool wantColourbar=false;
+			for(unsigned int ui=0;ui<plottingData.size();ui++)
+			{
+				if(!plottingData[ui]->visible)
+					continue;
+				Plot2DFunc *curPlot;
+				curPlot=(Plot2DFunc*)plottingData[ui];
+
+				if(curPlot->getType() == PLOT_2D_DENS)
+				{
+					wantColourbar=true;
+				}
+
+				//If a plot is not visible, it cannot own a region
+				//nor have a legend in this run.
+				if(!curPlot->visible)
+					continue;
+				
+				curPlot->drawPlot(gr);
+				
+			}
+			if(wantColourbar)
+					gr->Colorbar();
+			break;
+		}
 		default:
 			ASSERT(false);
 	}
@@ -1064,25 +988,10 @@ void PlotWrapper::drawPlot(mglGraph *gr, bool &haveUsedLog) const
 	gr->Label('x',sX.c_str());
 	gr->Label('y',sY.c_str(),0);
 
-	if(haveMultiTitles)
-	{
-#ifdef USE_MGL2
-		if(drawLegend)
-			gr->Legend();
-#else
-		gr->SetLegendBox(false);
-		//I have NO idea what this size value is about,
-		//I just kept changing the number until it looked nice.
-		//the library default is -0.85 (why negative??)
-		const float LEGEND_SIZE=-1.1f;
-
-		//Legend at top right (0x3), in default font "rL" at specified size
-		if(drawLegend)
-			gr->Legend(0x3,"rL",LEGEND_SIZE);
-#endif
-	}
+	if(haveMultiTitles && drawLegend)
+		gr->Legend();
 	
-	overlays.draw(gr,colourFixer,min,max,haveUsedLog);
+	overlays.draw(gr,min,max,haveUsedLog);
 }
 
 void PlotWrapper::hideAll()
@@ -1174,7 +1083,7 @@ void PlotWrapper::getRegion(unsigned int plotId, unsigned int regionId, PlotRegi
 
 unsigned int PlotWrapper::plotType(unsigned int plotId) const
 {
-	return plottingData[plotIDHandler.getPos(plotId)]->plotType;
+	return plottingData[plotIDHandler.getPos(plotId)]->getPlotMode();
 }
 
 
@@ -1224,16 +1133,93 @@ void PlotWrapper::overrideLastVisible(vector< pair<const void *,unsigned int>  >
 
 //-----------
 
+PlotBase::PlotBase()
+{
+	parentObject=0;
+	parentPlotIndex=(unsigned int)-1;
+	visible=true;
+}
+
+
+void PlotBase::getColour(float &rN, float &gN, float &bN) const
+{
+	rN=r;
+	gN=g;
+	bN=b;
+}
+
+void PlotBase::getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const
+{
+	xMin=minX;
+	xMax=maxX;
+	yMin=minY;
+	yMax=maxY;
+
+	ASSERT(yMin <=yMax);
+}
+
+void PlotBase::setStrings(const std::string &x, const std::string &y, const std::string &t)
+{
+
+	xLabel = x;
+	yLabel = y;
+	title = t;
+	
+}
+
+void PlotBase::copyBase(PlotBase *target) const
+{
+	target->plotType=plotType;
+	target->minX=minX;
+	target->maxX=maxX;
+	target->minY=minY;
+	target->maxY=maxY;
+	target->r=r;
+	target->g=g;
+	target->b=b;
+	target->visible=visible;
+	target->plotMode=plotMode;
+	target->xLabel=xLabel;
+	target->yLabel=yLabel;
+	target->title=title;
+	target->titleAsRawDataLabel=titleAsRawDataLabel;
+	target->parentObject=parentObject;
+	target->regionGroup=regionGroup;
+	target->parentPlotIndex=parentPlotIndex;
+
+}
+
+unsigned int PlotBase::getType() const
+{
+	return plotType;
+}
+
+unsigned int PlotBase::getMode() const
+{
+	switch(plotType)
+	{
+		case PLOT_LINE_LINES:
+		case PLOT_LINE_BARS:
+		case PLOT_LINE_STEPS:
+		case PLOT_LINE_STEM:
+		case PLOT_LINE_POINTS:
+			return PLOT_MODE_1D;
+
+		case PLOT_2D_DENS:
+		case PLOT_2D_SCATTER:
+			return PLOT_MODE_2D;	
+	}
+	ASSERT(false);
+}
 
 Plot1D::Plot1D()
 {
 	//Set the default plot properties
-	visible=(true);
-	traceType=PLOT_TRACE_LINES;
-	plotType=PLOT_TYPE_ONED;
-	xLabel=(strToWStr(""));
-	yLabel=(strToWStr(""));
-	title=(strToWStr(""));
+	plotType=PLOT_LINE_LINES;
+	plotMode=PLOT_MODE_1D;
+	xLabel="";
+	yLabel="";
+	title="";
 	r=(0);g=(0);b=(1);
 }
 
@@ -1247,28 +1233,12 @@ PlotBase *Plot1D::clone() const
 	p->yValues=yValues;
 	p->errBars=errBars;
 
-	//TODO Move to base
-	p->plotType=plotType;
-	p->minX=minX;
-	p->maxX=maxX;
-	p->minY=minY;
-	p->maxY=maxY;
-	p->r=r;
-	p->g=g;
-	p->b=b;
-	p->visible=visible;
-	p->traceType=traceType;
-	p->xLabel=xLabel;
-	p->yLabel=yLabel;
-	p->title=title;
-	p->titleAsRawDataLabel=titleAsRawDataLabel;
-	p->parentObject=parentObject;
-	p->regionGroup=regionGroup;
-	p->parentPlotIndex=parentPlotIndex;
+	copyBase(p);
 
 	return p;
 }
 
+
 void Plot1D::setData(const vector<float> &vX, const vector<float> &vY, 
 		const vector<float> &vErr)
 {
@@ -1342,71 +1312,109 @@ void Plot1D::setData(const vector<std::pair<float,float> > &v,const vector<float
 		yValues[ui]=v[ui].second;
 	}
 
-	errBars.resize(vErr.size());
-	std::copy(vErr.begin(),vErr.end(),errBars.begin());
 
+	computeDataBounds(xValues,minX,maxX);
+	if(vErr.empty())
+	{
+		computeDataBounds(yValues,minY,maxY);
+	}
+	else
+	{
+		errBars.resize(vErr.size());
+		std::copy(vErr.begin(),vErr.end(),errBars.begin());
+		computeDataBounds(yValues,vErr,minX,maxX);
+	}
+}
+void PlotBase::computeDataBounds(const vector<float> &d, const vector<float> &vErr,
+						float &minV,float &maxV) 
+{
+	//Compute minima and maxima of plot data, and keep a copy of it
+	float maxThis=-std::numeric_limits<float>::max();
+	float minThis=std::numeric_limits<float>::max();
 	
+	for(unsigned int ui=0;ui<d.size();ui++)
+	{
+		minThis=std::min(minThis,d[ui]-vErr[ui]);
+		maxThis=std::max(maxThis,d[ui]+vErr[ui]);
+	}
 
+	minV=minThis;
+	maxV=maxThis;
+}
+	
+void PlotBase::computeDataBounds(const vector<float> &d, float &minV,float &maxV) 
+{
 	//Compute minima and maxima of plot data, and keep a copy of it
 	float maxThis=-std::numeric_limits<float>::max();
 	float minThis=std::numeric_limits<float>::max();
 
-	// --------- X Values ---
-	for(unsigned int ui=0;ui<v.size();ui++)
+	// ---------  Values ---
+	for(unsigned int ui=0;ui<d.size();ui++)
 	{
-		minThis=std::min(minThis,v[ui].first);
-		maxThis=std::max(maxThis,v[ui].first);
+		minThis=std::min(minThis,d[ui]);
+		maxThis=std::max(maxThis,d[ui]);
 	}
-	minX=minThis;
-	maxX=maxThis;
+	minV=minThis;
+	maxV=maxThis;
 	//------------
 
+}
 
-	// Y values, taking into account any error bars
-	//------------------
-	minThis=std::numeric_limits<float>::max();
-	maxThis=-std::numeric_limits<float>::max();
-	if(vErr.size())
+void PlotBase::computeDataBounds(const vector<pair<float,float> > &d, 
+				float &minX,float &maxX, float &minY, float &maxY)
+{
+	//Compute minima and maxima of plot data, and keep a copy of it
+	float maxThisX=-std::numeric_limits<float>::max();
+	float minThisX=std::numeric_limits<float>::max();
+
+	// ---------  Values ---
+	for(unsigned int ui=0;ui<d.size();ui++)
 	{
-		ASSERT(vErr.size() == v.size());
-		for(unsigned int ui=0;ui<v.size();ui++)
-		{
-			minThis=std::min(minThis,v[ui].second-vErr[ui]);
-			maxThis=std::max(maxThis,v[ui].second+vErr[ui]);
-		}
+		minThisX=std::min(minThisX,d[ui].first);
+		maxThisX=std::max(maxThisX,d[ui].first);
 	}
-	else
-	{
-		for(unsigned int ui=0;ui<v.size();ui++)
-		{
-			minThis=std::min(minThis,v[ui].second);
-			maxThis=std::max(maxThis,v[ui].second);
-		}
+	minX=minThisX;
+	maxX=maxThisX;
+	//------------
+	
+	//Compute minima and maxima of plot data, and keep a copy of it
+	float maxThisY=-std::numeric_limits<float>::max();
+	float minThisY=std::numeric_limits<float>::max();
 
+	// ---------  Values ---
+	for(unsigned int ui=0;ui<d.size();ui++)
+	{
+		minThisY=std::min(minThisY,d[ui].second);
+		maxThisY=std::max(maxThisY,d[ui].second);
 	}
-	minY=minThis;
-	maxY=maxThis; 
-	//------------------
+	minY=minThisY;
+	maxY=maxThisY;
+	//------------
+
 }
 
-void Plot1D::getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const
+void PlotBase::setColour(float rN, float gN, float bN)
 {
-	xMin=minX;
-	xMax=maxX;
-	yMin=minY;
-	yMax=maxY;
-
-	ASSERT(yMin <=yMax);
+	ASSERT( rN <=1.0f&& rN >=0.0f);
+	ASSERT( gN <=1.0f&& gN >=0.0f);
+	ASSERT( bN <=1.0f&& bN >=0.0f);
+	
+	r=rN;
+	g=gN;
+	b=bN;
 }
 
-bool Plot1D::empty() const
+bool Plot1D::isEmpty() const
 {
 	ASSERT(xValues.size() == yValues.size());
 	return xValues.empty();
 }
 
-void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
+void Plot1D::drawPlot(mglGraph *gr) const
 {
+#ifdef DEBUG
+	checkConsistent();
+#endif
 	bool showErrs;
 
 	mglData xDat,yDat,eDat;
@@ -1453,40 +1461,41 @@ void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
 	
 	//Obtain a colour code to use for the plot, based upon
 	// the actual colour we wish to use
-	char colourCode[2];
-	colourCode[0]=fixer.getNextBestColour(r,g,b);
-	colourCode[1]='\0';
+	string colourCode;
+	colourCode=mglColourCode(r,g,b);
 	//---
 
 
 	//Plot the appropriate form	
-	switch(traceType)
+	switch(plotMode)
 	{
-		case PLOT_TRACE_LINES:
+		case PLOT_LINE_LINES:
 			//Unfortunately, when using line plots, mathgl moves the data points to the plot boundary,
 			//rather than linear interpolating them back along their paths. I have emailed the author.
 			//for now, we shall have to put up with missing lines :( Absolute worst case, I may have to draw them myself.
 			gr->SetCut(true);
-			
-			gr->Plot(xDat,yDat,colourCode);
+		
+			gr->Plot(xDat,yDat,colourCode.c_str());
 			if(showErrs)
-				gr->Error(xDat,yDat,eDat,colourCode);
+				gr->Error(xDat,yDat,eDat,colourCode.c_str());
 			gr->SetCut(false);
 			break;
-		case PLOT_TRACE_BARS:
-			gr->Bars(xDat,yDat,colourCode);
+		case PLOT_LINE_BARS:
+			gr->Bars(xDat,yDat,colourCode.c_str());
 			break;
-		case PLOT_TRACE_STEPS:
+		case PLOT_LINE_STEPS:
 			//Same problem as for line plot. 
 			gr->SetCut(true);
-			gr->Step(xDat,yDat,colourCode);
+			gr->Step(xDat,yDat,colourCode.c_str());
 			gr->SetCut(false);
 			break;
-		case PLOT_TRACE_STEM:
-			gr->Stem(xDat,yDat,colourCode);
+		case PLOT_LINE_STEM:
+			gr->SetCut(true);
+			gr->Stem(xDat,yDat,colourCode.c_str());
+			gr->SetCut(false);
 			break;
 
-		case PLOT_TRACE_POINTS:
+		case PLOT_LINE_POINTS:
 		{
 			std::string s;
 			s = colourCode;
@@ -1518,7 +1527,7 @@ void Plot1D::drawPlot(mglGraph *gr,MGLColourFixer &fixer) const
 }
 
 void Plot1D::getRawData(std::vector<std::vector< float> > &rawData,
-				std::vector<std::wstring> &labels) const
+				std::vector<std::string> &labels) const
 {
 
 	vector<float> tmp,dummy;
@@ -1547,23 +1556,16 @@ void Plot1D::getRawData(std::vector<std::vector< float> > &rawData,
 		
 		rawData.push_back(dummy);
 		rawData.back().swap(tmp);
-		labels.push_back(stlStrToStlWStr(TRANS("error")));
+		labels.push_back(string(TRANS("error")));
 	}
 }
 
 
-void Plot1D::clear( bool preserveVisiblity)
-{
-	regionGroup.clear();
-}
-
-void Plot1D::drawRegions(mglGraph *gr,MGLColourFixer &fixer,
+void Plot1D::drawRegions(mglGraph *gr,
 		const mglPoint &min,const mglPoint &max) const
 {
 	//Mathgl palette colour name
-	char colourCode[2];
-	colourCode[1]='\0';
-
+	string colourCode;
 
 	for(unsigned int uj=0;uj<regionGroup.regions.size();uj++)
 	{
@@ -1577,17 +1579,11 @@ void Plot1D::drawRegions(mglGraph *gr,MGLColourFixer &fixer,
 		//Prevent drawing inverted regionGroup.regions
 		if(rMaxX > rMinX && rMaxY > rMinY)
 		{
-			colourCode[0] = fixer.getNextBestColour(regionGroup.regions[uj].r,
+			colourCode = mglColourCode(regionGroup.regions[uj].r,
 						regionGroup.regions[uj].g,
 						regionGroup.regions[uj].b);
-			colourCode[1] = '\0';
-#ifdef USE_MGL2
 			gr->FaceZ(mglPoint(rMinX,rMinY,-1),rMaxX-rMinX,rMaxY-rMinY,
-					colourCode);
-#else
-			gr->FaceZ(rMinX,rMinY,-1,rMaxX-rMinX,rMaxY-rMinY,
-					colourCode);
-#endif
+					colourCode.c_str());
 					
 		}
 	}
@@ -1595,6 +1591,206 @@ void Plot1D::drawRegions(mglGraph *gr,MGLColourFixer &fixer,
 
 //--
 
+//2D plotting code
+Plot2DFunc::Plot2DFunc()
+{
+	plotMode = PLOT_MODE_2D;
+	plotType=PLOT_2D_DENS;
+}
+
+void Plot2DFunc::setData(const Array2D<float> &a,
+		float xLow,float xHigh, float yLow, float yHigh) 
+{
+	xyValues=a;
+	minX=xLow;
+	maxX=xHigh;
+	minY=yLow;
+	maxY=yHigh;
+}
+
+
+bool Plot2DFunc::isEmpty() const
+{
+	return xyValues.empty();
+}
+
+PlotBase * Plot2DFunc::clone() const
+{
+	Plot2DFunc *pb = new Plot2DFunc;
+
+	pb->xyValues=xyValues;
+
+	copyBase(pb);
+
+	return pb;
+}
+
+void Plot2DFunc::drawPlot(mglGraph *graph) const
+{
+#ifdef DEBUG
+	checkConsistent();
+#endif
+	size_t w,h;
+	w=xyValues.width();
+	h=xyValues.height();
+	
+	mglData xyData(w,h);
+
+	#pragma omp parallel for
+	for(size_t ui=0;ui<w;ui++)
+	{
+		for(size_t uj=0;uj<h;uj++)
+		{
+			xyData[uj*w+ui]=xyValues[ui][uj];
+		}
+	}
+
+	mglData xAxis(w),yAxis(h);
+	xAxis.Fill(minX,maxX);
+	yAxis.Fill(minY,maxY);
+
+	graph->Axis("xy");
+	graph->SetCut(false);
+	graph->Dens(xAxis,yAxis,xyData);
+	graph->SetCut(true);
+}
+
+void Plot2DFunc::getRawData(std::vector<std::vector<float> >  &rawData,
+			std::vector<std::string> &labels) const
+{
+
+	xyValues.unpack(rawData);
+	labels.resize(rawData.size(),title);
+
+}
+
+//--
+
+Plot2DScatter::Plot2DScatter()
+{
+	plotType=PLOT_2D_SCATTER;
+}
+
+void Plot2DScatter::setData(const vector<pair<float,float> > &f) 
+{
+	 points	=f;
+	computeDataBounds(f,minX,maxX,minY,maxY);
+}
+
+void Plot2DScatter::setData(const vector<pair<float,float> > &f, const vector<float> &inten) 
+{
+	points	=f;
+	intensity=inten;
+	computeDataBounds(f,minX,maxX,minY,maxY);
+}
+
+bool Plot2DScatter::isEmpty() const
+{
+	return points.empty();
+}
+
+PlotBase *Plot2DScatter::clone() const
+{
+	Plot2DScatter *pb = new Plot2DScatter;
+
+	pb->points=points;
+
+	copyBase(pb);
+
+	return pb;
+}
+
+void Plot2DScatter::drawPlot(mglGraph *graph) const
+{
+	
+	mglData xDat, yDat,sizeDat;
+
+	float *bufX,*bufY;
+	bufX = new float[points.size()];
+	if(!bufX) 
+		return;
+	bufY = new float[points.size()];
+	if(!bufY)
+	{
+		delete[] bufX;
+		return;
+	}
+
+	for(unsigned int ui=0;ui<points.size();ui++)
+	{
+		bufX[ui]=points[ui].first;
+		bufY[ui] = points[ui].second;
+	}
+
+	//TODO: Implement scatter intesity	
+	xDat.Set(bufX,points.size());
+	yDat.Set(bufY,points.size());
+	
+	delete[] bufX;
+	delete[] bufY;
+
+	if(intensity.empty())
+	{
+		float *bufSize = new float[points.size()];
+		for(unsigned int ui=0;ui<points.size();ui++)
+			bufSize[ui]=1;
+		sizeDat.Set(bufSize,points.size());
+		delete[] bufSize;
+	}
+	else
+	{
+		sizeDat.Set(intensity);
+	}
+	
+	string colourCode;
+	colourCode=mglColourCode(r,g,b);
+	
+	graph->SetCut(false);
+	graph->Mark(xDat,yDat,sizeDat,"+",colourCode.c_str());
+	graph->SetCut(true);
+
+	
+}
+void Plot2DScatter::getRawData(std::vector<std::vector<float> >  &rawData,
+			std::vector<std::string> &labels) const
+{
+
+	if(intensity.size())
+	{
+		rawData.resize(3);
+		for(unsigned int ui=0;ui<3;ui++)
+			rawData[ui].resize(points.size());
+
+		for(unsigned int ui=0;ui<points.size();ui++)
+		{
+			rawData[0][ui] = points[ui].first;
+			rawData[1][ui] = points[ui].second;
+			rawData[2][ui] = intensity[ui];
+		}
+		
+		labels.resize(3);
+		labels[2]=TRANS("Amplitude");
+	}
+	else
+	{
+		rawData.resize(2);
+		for(unsigned int ui=0;ui<2;ui++)
+			rawData[ui].resize(points.size());
+
+		for(unsigned int ui=0;ui<points.size();ui++)
+		{
+			rawData[0][ui] = points[ui].first;
+			rawData[1][ui] = points[ui].second;
+		}
+
+		labels.resize(2);
+	}
+
+	labels[0] = xLabel;
+	labels[1] = yLabel;
+}
+
+//--
 bool RegionGroup::getRegionIdAtPosition(float x, float y, unsigned int &id) const
 {
 	for(unsigned int ui=0;ui<regions.size();ui++)
@@ -1791,18 +1987,17 @@ void PlotWrapper::setRegionGroup(size_t plotId,RegionGroup &r)
 }
 
 
-void PlotOverlays::draw(mglGraph *gr,MGLColourFixer &fixer, 
+void PlotOverlays::draw(mglGraph *gr,
 		const mglPoint &boundMin, const mglPoint &boundMax,bool logMode ) const
 {
 
 	if(!isEnabled)
 		return;
 
-	char colourCode[2];
+	string colourCode;
 
 	//Draw the overlays in black
-	colourCode[0] = fixer.getNextBestColour(0.0,0.0,0.0);
-	colourCode[1]='\0';
+	colourCode = mglColourCode(0.0,0.0,0.0);
 	
 	for(size_t ui=0;ui<overlayData.size();ui++)
 	{
@@ -1826,21 +2021,14 @@ void PlotOverlays::draw(mglGraph *gr,MGLColourFixer &fixer,
 		//Rescale to plot size
 		for(size_t uj=0;uj<overlayData[ui].coordData.size();uj++)
 		{
-			if(logMode)
-			{
-				//Compute log10(probability*maximum) = 
-				//	log10(probability) + log10(maximum)
-				// maximum = 10^boundMax.y
-
-				bufY[uj]=log10(bufY[uj]) +boundMax.y*0.95;
-				bufY[uj]=std::max(bufY[uj],0.0f);
-			}
-			else
-			{
-				bufY[uj]*=boundMax.y/maxV*0.95;
-			}
+			bufY[uj]*=boundMax.y/maxV*0.95;
 		}
 
+		mglData xDat,yDat;
+		xDat.Set(bufX);
+		yDat.Set(bufY);
+
+		//TODO: Deprecate me. Upstream now allows single stems
 		//Draw stems. can't use stem plot due to mathgl bug whereby single stems
 		// will not be drawn
 		for(size_t uj=0;uj<overlayData[ui].coordData.size();uj++)
@@ -1848,22 +2036,22 @@ void PlotOverlays::draw(mglGraph *gr,MGLColourFixer &fixer,
 			if(bufX[uj]> boundMin.x && bufX[uj]< boundMax.x && 
 					boundMin.y < bufY[uj])
 			{
-				gr->Line (mglPoint(bufX[uj],std::max(0.0f,(float)boundMin.y)),
-					mglPoint(bufX[uj],bufY[uj]),colourCode,100);
-
 				//Print labels near to the text
 				const float STANDOFF_FACTOR=1.05;
-#ifdef USE_MGL2
 				gr->Puts(mglPoint(bufX[uj],bufY[uj]*STANDOFF_FACTOR),
 					overlayData[ui].title.c_str());
-#else
-				//Font size in mathgl uses negative values to set a relative font size
-				gr->Text(mglPoint(bufX[uj],bufY[uj]*STANDOFF_FACTOR),
-					overlayData[ui].title.c_str(),"",-0.6);
-
-#endif
 			}
 		}
+
+		//Draw stems.
+		gr->Stem(xDat,yDat,"k");
 	}
 }
 
+#ifdef DEBUG
+void PlotBase::checkConsistent() const
+{
+	ASSERT(parentObject);
+	ASSERT(parentPlotIndex != (unsigned int)-1);
+}
+#endif
diff --git a/src/backend/plot.h b/src/backend/plot.h
index 6270ee8..d31fd2b 100644
--- a/src/backend/plot.h
+++ b/src/backend/plot.h
@@ -21,7 +21,7 @@
 
 
 #include "backend/filter.h"
-
+#include "common/array2D.h"
 #include <map>
 
 
@@ -32,28 +32,39 @@
 
 //Use config header to determine if we need to enable mgl2 support
 #include "../config.h"
-#ifdef USE_MGL2
 #include <mgl2/mgl.h>
-#else
-#include <mgl/mgl.h>
-#endif
 
 //mathgl shadows std::isnan
 #undef isnan
 
 
-enum
+//Plot style/mode enum
+enum 
 {
-	PLOT_TYPE_ONED,
-	PLOT_TYPE_MIXED,
-	PLOT_TYPE_ENUM_END //not a plot, just end of enum
+	PLOT_LINE_LINES=0,
+	PLOT_LINE_BARS,
+	PLOT_LINE_STEPS,
+	PLOT_LINE_STEM,
+	PLOT_LINE_POINTS,
+	PLOT_LINE_NONE, // not a plot, just marker for enum break
+	PLOT_2D_DENS,
+	PLOT_2D_SCATTER,
+	PLOT_TYPE_ENUM_END
 };
 
-
-
+//This is the plot mode,
+// it can be determined as a function of the
+// plot-style/mode enum
+enum
+{
+	PLOT_MODE_1D,
+	PLOT_MODE_2D,
+	PLOT_MODE_MIXED, //special marker - different types of plots, when looking at multiple plots
+	PLOT_MODE_ENUM_END //not a plot, just end of enum
+};
 
 //!Return a human readable string for a given plot type
-std::string plotString(unsigned int traceType);
+std::string plotString(unsigned int plotMode);
 
 //!Return a human readable string for the plot error mode
 std::string plotErrmodeString(unsigned int errMode);
@@ -64,26 +75,6 @@ unsigned int plotID(const std::string &plotString);
 //!Return the error mode type, given the human readable string
 unsigned int plotErrmodeID(const std::string &s);
 		
-//!Nasty hack class to change mathgl API from named char palette to rgb specification
-class MGLColourFixer
-{
-	private:
-		vector<float> rs,gs,bs;
-		static int maxCols;
-	public:
-		//Restore the MGL colour strings
-		void reset();
-		//Return the exact colour, if there is one
-		char haveExactColour(float r, float g, float b) const;
-		//Get the best colour that is available
-		// returns the char to give to mathgl; may be exact,
-		// maybe nearest match, depending upon number of colours used
-		// and mgl palette size
-		char getNextBestColour(float r, float g, float b);
-
-		static unsigned int getMaxColours();
-};
-
 
 //!Data class  for holding info about non-overlapping 
 // interactive rectilinear "zones" overlaid on plots 
@@ -137,7 +128,6 @@ class PlotRegion
 };
 
 //Handles an array of regions, for drawing and editing of the array
-
 class RegionGroup
 {
 	private:
@@ -188,6 +178,8 @@ struct  OVERLAY_DATA
 	bool enabled;
 };
 
+//!Thse are 1D-stem style overlays that can be used
+// to draw onto the plot
 class PlotOverlays
 {
 	private:
@@ -199,7 +191,7 @@ class PlotOverlays
 		//Add a new overlay to the plot
 		void add(const OVERLAY_DATA &overlay) {overlayData.push_back(overlay);}
 		//Draw the overlay on the current plot
-		void draw(mglGraph *g,MGLColourFixer &fixer, 
+		void draw(mglGraph *g,
 			const mglPoint &boundMin, const mglPoint &boundMax,bool logMode) const;
 		//Enable the specified overlay
 		void setEnabled(size_t offset,bool isEnabled) 
@@ -218,31 +210,53 @@ class PlotOverlays
 //!Base class for data plotting
 class PlotBase
 {
+	protected:
+		//!Sub type of plot (eg lines, bars for 1D)
+		unsigned int plotMode;
+		//!xaxis label
+		std::string xLabel;
+		//!y axis label
+		std::string yLabel;
+		//!Plot title
+		std::string title;
+		
+		//plot colour (for single coloured plots)
+		float r,g,b;
+		
+		//The type of plot (ie what class is it?)	
+		unsigned int plotType;
+		
+		void copyBase(PlotBase *target) const;
+
+		//Find the upper and lower limit of a given dataset
+		static void computeDataBounds(const vector<float> &d, float &minV,float &maxV) ;
+		
+		//Find the upper and lower limit of a given dataset
+		static void computeDataBounds(const vector<float> &d, const vector<float> &errorBar,
+								float &minV,float &maxV);
+
+		//Find the upper and lower limit of a given dataset
+		static void computeDataBounds(const vector<pair<float,float> > &d, 
+					float &minVx,float &maxVx,float &minVy, float &maxVy);
 	public:
-		PlotBase(){};
+		PlotBase();
 		virtual ~PlotBase(){};
 
 		virtual PlotBase *clone() const = 0;
 
-		//The type of plot (ie what class is it?)	
-		unsigned int plotType;
-		
-		//!Bounding box for plot -  may exceed plot data area
+	
+		//return the plot type
+		unsigned int getType() const;
+
+		//return the plot mode, which is derived
+		// uniquely from the plot type
+		unsigned int getMode() const;
+
+		//!Bounding box for plot 
 		float minX,maxX,minY,maxY;
 
-		//!Colour of trace
-		float r,g,b;
 		//!Is trace visible?
 		bool visible;
-		//!Type of plot (lines, bars, sticks, etc)
-		unsigned int traceType;
-		//!xaxis label
-		std::wstring xLabel;
-		//!y axis label
-		std::wstring yLabel;
-		//!Plot title
-		std::wstring title;
-
 		//!Use the plot title for Y data label when exporting raw data
 		// (true), or use the yLabel
 		bool titleAsRawDataLabel;
@@ -258,25 +272,45 @@ class PlotBase
 		RegionGroup regionGroup;
 
 	
-		//True if the plot has data
-		virtual bool empty() const=0;
+		//True if the plot has no data
+		virtual bool isEmpty() const=0;
 
 		//Draw the plot onto a given MGL graph
-		virtual void drawPlot(mglGraph *graph, MGLColourFixer &fixer) const=0;
+		virtual void drawPlot(mglGraph *graph) const=0;
 
-		//!Scan for the data bounds.
+		//!Return the true data bounds for this plot
 		virtual void getBounds(float &xMin,float &xMax,
-					float &yMin,float &yMax) const = 0;
+					float &yMin,float &yMax) const;
+		
 
 		//Retrieve the raw data associated with this plot.
 		virtual void getRawData(vector<vector<float> > &f,
-				std::vector<std::wstring> &labels) const=0;
+				std::vector<std::string> &labels) const=0;
+
+		//set the plot axis strings (x,y and title)
+		void setStrings(const std::string &x, 
+			const std::string &y,const std::string &t);
+
+		void setColour(float rNew, float gNew, float bNew);
+
+		std::string getXLabel() const { return xLabel;}
+		std::string getTitle() const { return title;}
+		std::string getYLabel() const { return yLabel;}
+
+		//Plot mode is, eg 2D or 1D plot
+		unsigned int getPlotMode() const { return plotMode;}
+		//FIXME: Deprecate me. Plot mode should be intrinsic
+		void setPlotMode(unsigned int newMode) { plotMode= newMode;}
 
 
+		void getColour(float &r, float &g, float &b) const ;
+
+#ifdef DEBUG
+		void checkConsistent() const;
+#endif
 };
 
-//!1D Function f(x) Plot with ranges
-// data must be a pure Function.
+//!1D Function f(x) 
 class Plot1D : public PlotBase
 {
 	private: 	
@@ -288,11 +322,9 @@ class Plot1D : public PlotBase
 		
 	public:
 		Plot1D();
-		virtual bool empty() const;
+		virtual bool isEmpty() const;
 		virtual PlotBase *clone() const;
 			
-		void getBounds(float &xMin,float &xMax,float &yMin,float &yMax) const;
-
 		//!Set the plot data from a pair and symmetric Y error
 		void setData(const vector<std::pair<float,float> > &v);
 		void setData(const vector<std::pair<float,float> > &v,const vector<float> &symYErr);
@@ -305,21 +337,19 @@ class Plot1D : public PlotBase
 		//!Move a region to a new location. 
 		void moveRegion(unsigned int region, unsigned int method, float newPos);
 
-		void clear(bool preserveVisibility);
-		
 		
 		//Draw the plot onto a given MGL graph
-		virtual void drawPlot(mglGraph *graph,MGLColourFixer &fixer) const;
+		virtual void drawPlot(mglGraph *graph) const;
 
 		//Draw the associated regions		
-		void drawRegions(mglGraph *graph, MGLColourFixer &fixer,
-				const mglPoint &min, const mglPoint &max) const;
+		void drawRegions(mglGraph *graph,
+			const mglPoint &min, const mglPoint &max) const;
 
 
 		//!Retrieve the raw data associated with the currently visible plots. 
 		//note that this is the FULL data not the zoomed data for the current user bounds
 		void getRawData(std::vector<std::vector<float> >  &rawData,
-				std::vector<std::wstring> &labels) const;
+				std::vector<std::string> &labels) const;
 		
 		//!Retrieve the ID of the non-overlapping region in X-Y space
 		bool getRegionIdAtPosition(float x, float y, unsigned int &id) const;
@@ -339,6 +369,54 @@ class Plot1D : public PlotBase
 
 		bool wantLogPlot() const { return logarithmic;};
 		void setLogarithmic(bool p){logarithmic=p;};
+
+};
+
+//!2D function, f(x,y). 
+class Plot2DFunc : public PlotBase
+{
+	private: 	
+		//2D array, for f(x,y) plots 
+		Array2D<float> xyValues;
+	public:
+		Plot2DFunc();
+		virtual bool isEmpty() const;
+		virtual PlotBase *clone() const;
+			
+		//Draw the plot onto a given MGL graph
+		virtual void drawPlot(mglGraph *graph) const;
+
+		//!Retrieve the raw data associated with the currently visible plots. 
+		//note that this is the FULL data not the zoomed data for the current user bounds
+		void getRawData(std::vector<std::vector<float> >  &rawData,
+				std::vector<std::string> &labels) const;
+	
+		void setData(const Array2D<float> &a, float xLow, float xHigh, float yLow, float yHigh) ;
+
+};
+
+//!2D scatter plot, {x,y}_i
+class Plot2DScatter : public PlotBase
+{
+	private:
+		vector<pair<float,float> > points;
+		vector<float > intensity;
+	public:
+		Plot2DScatter();
+		virtual bool isEmpty() const;
+		virtual PlotBase *clone() const;
+			
+		//Draw the plot onto a given MGL graph
+		virtual void drawPlot(mglGraph *graph) const;
+
+		//!Retrieve the raw data associated with the currently visible plots. 
+		//note that this is the FULL data not the zoomed data for the current user bounds
+		void getRawData(std::vector<std::vector<float> >  &rawData,
+				std::vector<std::string> &labels) const;
+
+		//reset the data stored in the plot
+		void setData(const vector<pair<float,float> > &pts);
+		void setData(const vector<pair<float,float> > &pts ,const vector<float> &intens);
 };
 
 //Wrapper class for containing multiple plots 
@@ -378,6 +456,8 @@ class PlotWrapper
 		//!Do we want to highlight positions where regions overlap?
 		bool highlightRegionOverlaps;
 
+
+		void getAppliedBounds(mglPoint &min,mglPoint &max) const;
 	public:
 		//"stick" type overlays for marking amplitudes on top of the plot
 		PlotOverlays overlays;
@@ -397,7 +477,7 @@ class PlotWrapper
 		void getPlotIDs(vector<unsigned int> &ids) const ;
 
 		//Retrieve the title of the plot
-		std::wstring getTitle(size_t plotId) const;
+		std::string getTitle(size_t plotId) const;
 
 
 		void setEnableHighlightOverlap(bool enable=true) { highlightRegionOverlaps=enable;}
@@ -435,9 +515,6 @@ class PlotWrapper
 				const char *x, const char *y, const char *t);
 		void setStrings(unsigned int plotID,const std::string &x, 
 				const std::string &y,const std::string &t);
-		//!Set the parent information for a given plot
-		void setParentData(unsigned int plotID,
-				const void *parentObj, unsigned int plotIndex);
 
 		//TODO: Type hack - should return const Filter *
 		//!Get the parent object fo rthis plot
@@ -511,14 +588,14 @@ class PlotWrapper
 							std::vector< pair<float,float> > &coords) const;
 
 		//!Retrieve the raw data associated with the selected plots.
-		void getRawData(vector<vector<vector<float> > >  &data, std::vector<std::vector<std::wstring> >  &labels) const;
+		void getRawData(vector<vector<vector<float> > >  &data, std::vector<std::vector<std::string> >  &labels) const;
 	
 
 		//!obtain the type of a plot, given the plot's uniqueID
 		unsigned int plotType(unsigned int plotId) const;
 
 		//Retrieve the types of visible plots
-		unsigned int getVisibleType() const;
+		unsigned int getVisibleMode() const;
 
 		//!Obtain limit of motion for a given region movement type
 		void findRegionLimit(unsigned int plotId, unsigned int regionId,
diff --git a/src/backend/state.cpp b/src/backend/state.cpp
index 8c3ab8f..be6f70a 100644
--- a/src/backend/state.cpp
+++ b/src/backend/state.cpp
@@ -270,7 +270,7 @@ bool AnalysisState::save(const char *cpFilename, std::map<string,string> &fileMa
 	return true;
 }
 
-bool AnalysisState::load(const char *cpFilename, std::ostream &errStream, bool merge) 
+bool AnalysisState::load(const char *cpFilename, std::ostream &errStream ) 
 {
 	clear();
 
@@ -302,8 +302,7 @@ bool AnalysisState::load(const char *cpFilename, std::ostream &errStream, bool m
 	
 
 	//By default, lets not use relative paths
-	if(!merge)
-		useRelativePathsForSave=false;
+	useRelativePathsForSave=false;
 
 	//Lets do some parsing goodness
 	//ahh parsing - verbose and boring
@@ -770,89 +769,38 @@ bool AnalysisState::load(const char *cpFilename, std::ostream &errStream, bool m
 		}
 	}
 
-	if(!merge)
-	{
-		//Now replace it with the new data
-		activeTree.swap(newFilterTree);
-		std::swap(stashedTrees,newStashes);
-	}
-	else
-	{
-		//If we are merging, then there is a chance
-		//of a name-clash. We avoid this by trying to append -merge continuously
-		for(unsigned int ui=0;ui<newStashes.size();ui++)
-		{
-			//protect against overload (very unlikely)
-			unsigned int maxCount;
-			maxCount=100;
-			while(hasFirstInPairVec(stashedTrees,newStashes[ui]) && --maxCount)
-				newStashes[ui].first+=TRANS("-merge");
-
-			if(maxCount)
-				stashedTrees.push_back(newStashes[ui]);
-			else
-				errStream << TRANS(" Unable to merge stashes correctly. This is improbable, so please report this.") << endl;
-		}
-
-		activeTree.addFilterTree(newFilterTree,0);
-		undoTrees.clear();
-		redoTrees.clear();
-	}
+	//Now replace it with the new data
+	activeTree.swap(newFilterTree);
+	std::swap(stashedTrees,newStashes);
 
 	activeTree.initFilterTree();
 	
 	//Wipe the existing cameras, and then put the new cameras in place
-	if(!merge)
-		savedCameras.clear();
+	savedCameras.clear();
 	
 	//Set a default camera as needed. We don't need to track its unique ID, as this is
 	//"invisible" to the UI
-	if(!savedCameras.size())
-	{
-		Camera *c=new CameraLookAt();
-		savedCameras.push_back(c);
-		activeCamera=0;
-	}
+	Camera *c=new CameraLookAt();
+	savedCameras.push_back(c);
+	activeCamera=0;
 
 	//spin through
 	for(unsigned int ui=0;ui<newCameraVec.size();ui++)
 	{
-		if(merge)
+		//If there is no userstring, then its a  "default"
+		// camera (one that does not show up to the users,
+		// and cannot be erased from the scene)
+		// set it directly. Otherwise, its a user camera.
+		if(newCameraVec[ui]->getUserString().size())
 		{
-			//Don't merge the default camera (which has no name)
-			if(newCameraVec[ui]->getUserString().empty())
-				continue;
-
-			//Keep trying new names appending "-merge" each time to obtain a new, and hopefully unique name
-			// Abort after many times
-			unsigned int maxCount;
-			maxCount=100;
-			while(camNameExists(newCameraVec[ui]->getUserString()) && --maxCount)
-			{
-				newCameraVec[ui]->setUserString(newCameraVec[ui]->getUserString()+"-merge");
-			}
-
-			//If we have any attempts left, then it worked
-			if(maxCount)
-				savedCameras.push_back(newCameraVec[ui]);
+			savedCameras.push_back(newCameraVec[ui]);
+			activeCamera=ui;
 		}
 		else
 		{
-			//If there is no userstring, then its a  "default"
-			// camera (one that does not show up to the users,
-			// and cannot be erased from the scene)
-			// set it directly. Otherwise, its a user camera.
-			if(newCameraVec[ui]->getUserString().size())
-			{
-				savedCameras.push_back(newCameraVec[ui]);
-				activeCamera=ui;
-			}
-			else
-			{
-				ASSERT(savedCameras.size());
-				delete savedCameras[0];
-				savedCameras[0]=newCameraVec[ui];
-			}
+			ASSERT(savedCameras.size());
+			delete savedCameras[0];
+			savedCameras[0]=newCameraVec[ui];
 		}
 
 	}
@@ -889,15 +837,69 @@ bool AnalysisState::load(const char *cpFilename, std::ostream &errStream, bool m
 
 	//If we are merging then the default state has been altered
 	// if we are not merging, then it is overwritten
-	if(merge)
-		setModifyLevel(STATE_MODIFIED_DATA);
-	else
-		setModifyLevel(STATE_MODIFIED_NONE);
+	setModifyLevel(STATE_MODIFIED_NONE);
 
 	//Perform sanitisation on results
 	return true;
 }
 
+bool AnalysisState::merge(const AnalysisState &otherState)
+{
+
+	setModifyLevel(STATE_MODIFIED_DATA);
+
+	//If we are merging, then there is a chance
+	//of a name-clash. We avoid this by trying to append -merge continuously
+	vector<std::pair<string,FilterTree> > newStashes;
+	newStashes.resize(otherState.stashedTrees.size());
+	for(size_t ui=0;ui<otherState.stashedTrees.size();ui++)
+		newStashes[ui]=otherState.stashedTrees[ui];
+	for(unsigned int ui=0;ui<newStashes.size();ui++)
+	{
+		//protect against overload (very unlikely)
+		unsigned int maxCount;
+		maxCount=100;
+		while(hasFirstInPairVec(stashedTrees,newStashes[ui]) && --maxCount)
+			newStashes[ui].first+=TRANS("-merge");
+
+		if(maxCount)
+			stashedTrees.push_back(newStashes[ui]);
+		else
+		{
+			WARN(false," Unable to merge stashes correctly. This is improbable, so please report this.");
+		}
+	}
+	
+	FilterTree f = otherState.activeTree;
+	activeTree.addFilterTree(f,0);
+	
+	//wipe our undo/redo trees, as we can no longer rely on them
+	undoTrees.clear();
+	redoTrees.clear();
+
+	const vector<Camera *> &newCameraVec = otherState.savedCameras;	
+	for(unsigned int ui=0;ui<newCameraVec.size();ui++)
+	{
+		//Don't merge the default camera (which has no name)
+		if(newCameraVec[ui]->getUserString().empty())
+			continue;
+
+		//Keep trying new names appending "-merge" each time to obtain a new, and hopefully unique name
+		// Abort after many times
+		unsigned int maxCount;
+		maxCount=100;
+		while(camNameExists(newCameraVec[ui]->getUserString()) && --maxCount)
+		{
+			newCameraVec[ui]->setUserString(newCameraVec[ui]->getUserString()+"-merge");
+		}
+
+		//If we have any attempts left, then it worked
+		if(maxCount)
+			savedCameras.push_back(newCameraVec[ui]->clone());
+	}
+}
+
+
 bool AnalysisState::camNameExists(const std::string &s) const
 {
 	for(size_t ui=0; ui<savedCameras.size(); ui++) 
@@ -1173,7 +1175,7 @@ bool testStateReload()
 	someState.clear();
 
 	std::ofstream strm;
-	TEST(someState.load(saveString.c_str(),strm,false),"State load");
+	TEST(someState.load(saveString.c_str(),strm),"State load");
 
 	TEST(someState.getStashCount() == 1,"Stash save+load");
 	std::pair<string,FilterTree> stashOut;
diff --git a/src/backend/state.h b/src/backend/state.h
index 3ea33e1..3ebcb9e 100644
--- a/src/backend/state.h
+++ b/src/backend/state.h
@@ -143,11 +143,8 @@ class AnalysisState
 		// - returns true on success, false on fail
 		// - errStream will have human readable messages in 
 		//	the case that there is a failure
-		// - set merge to true, if should attempt to merge 
-		//	the two states together
 		bool load(const char *cpFilename, 
-				std::ostream &errStream, 
-				bool merge) ;
+				std::ostream &errStream);
 
 		//save an XML-ised representation of the analysis sate
 		//	- mapping provides the on-disk to local name mapping to use when saving
@@ -156,6 +153,8 @@ class AnalysisState
 		bool save(const char *cpFilename, std::map<string,string> &fileMapping,
 				bool writePackage) const ;
 
+		//Combine a separate state file into this one, avoiding clashes
+		bool merge(const AnalysisState &srcState);
 
 		//Return the current state's filename
 		string getFilename() const { return fileName; }
diff --git a/src/backend/tree.hh b/src/backend/tree.hh
old mode 100755
new mode 100644
diff --git a/src/backend/viscontrol.cpp b/src/backend/viscontrol.cpp
index 1f00d31..fbd804f 100644
--- a/src/backend/viscontrol.cpp
+++ b/src/backend/viscontrol.cpp
@@ -20,6 +20,7 @@
 
 #include "wx/wxcommon.h"
 #include "wx/wxcomponents.h"
+#include "wx/propertyGridUpdater.h"
 #include "gl/scene.h"
 
 
@@ -196,6 +197,13 @@ const Filter* VisController::getFilterById(size_t filterId) const
 	return filterMap.at(filterId);
 }
 
+size_t VisController::getPlotID(size_t position) const
+{ 
+	ASSERT(plotMap.size());
+	ASSERT(plotMap.find(position)!=plotMap.end());
+	return plotMap.find(position)->second;
+}
+
 size_t VisController::getIdByFilter(const Filter *f) const 
 {
 	for(map<size_t,Filter *>::const_iterator it=filterMap.begin();it!=filterMap.end();++it)
@@ -292,10 +300,10 @@ unsigned int VisController::refreshFilterTree(bool doUpdateScene)
 				textConsole->AppendText(wxT("============\n\n\n"));
 
 			lastFilt=consoleMessages[ui].first;
-			textConsole->AppendText(wxStr(lastFilt->getUserString()));
+			textConsole->AppendText((lastFilt->getUserString()));
 			textConsole->AppendText(wxT("\n============\n"));
 		}
-		textConsole->AppendText(wxStr(consoleMessages[ui].second));
+		textConsole->AppendText((consoleMessages[ui].second));
 		textConsole->AppendText(wxT("\n"));
 	}
 
@@ -371,8 +379,9 @@ void VisController::updateWxTreeCtrl(wxTreeCtrl *t, const Filter *visibleFilt)
 	upWxTreeCtrl(filterTree,t,filterMap,persistentFilters,visibleFilt);
 }
 
-void VisController::updateFilterPropGrid(wxCustomPropGrid *g,size_t filterId) const	
+void VisController::updateFilterPropGrid(wxPropertyGrid *g,size_t filterId, const std::string &stateStr) const
 {
+
 	//The filterID can never be set to zero,
 	//except for the root item, as set by
 	//upWxTreeCtrl
@@ -384,9 +393,18 @@ void VisController::updateFilterPropGrid(wxCustomPropGrid *g,size_t filterId) co
 
 	ASSERT(targetFilter);
 	
-	updateFilterPropertyGrid(g,targetFilter);
+	updateFilterPropertyGrid(g,targetFilter,stateStr);
 }
 
+void VisController::updateCameraPropGrid(wxPropertyGrid *g, size_t camId) const
+{
+	ASSERT(g);
+
+	const Camera *c;
+	c= currentState.getCam(camId);
+
+	updateCameraPropertyGrid(g,c);
+}
 
 bool VisController::setCamProperties(size_t camID,unsigned int key, const std::string &value)
 {
@@ -559,7 +577,6 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 	//rate-limit the number of drawables to show in the scene
 	throttleSceneInput(sceneData);
 
-
 	//-- Build buffer of new objects to send to scene
 	for(list<vector<const FilterStreamData *> > ::iterator it=sceneData.begin(); 
 							it!=sceneData.end(); ++it)
@@ -622,74 +639,112 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 					
 					//The plot should have some data in it.
 					ASSERT(plotData->getNumBasicObjects());
-					//The plot should have a parent filter
-					ASSERT(plotData->parent);
 					//The plot should have an index, so we can keep
 					//filter choices between refreshes (where possible)
 					ASSERT(plotData->index !=(unsigned int)-1);
 					//Construct a new plot
 					unsigned int plotID;
 
-					switch(plotData->plotMode)
+					
+					//No other plot mode is currently implemented.
+					ASSERT(plotData->plotMode == PLOT_MODE_1D);
+					
+					//Create a 1D plot
+					Plot1D *plotNew= new Plot1D;
+
+					plotNew->setData(plotData->xyData);
+					plotNew->setLogarithmic(plotData->logarithmic);
+					plotNew->titleAsRawDataLabel=plotData->useDataLabelAsYDescriptor;
+					
+					//Construct any regions that the plot may have
+					for(unsigned int ui=0;ui<plotData->regions.size();ui++)
+					{
+						//add a region to the plot,
+						//using the region data stored
+						//in the plot stream
+						plotNew->regionGroup.addRegion(plotData->regionID[ui],
+							plotData->regionTitle[ui],	
+							plotData->regions[ui].first,
+							plotData->regions[ui].second,
+							plotData->regionR[ui],
+							plotData->regionG[ui],
+							plotData->regionB[ui],plotData->regionParent);
+					}
+
+					//transfer the axis labels
+					plotNew->setStrings(plotData->xLabel,
+						plotData->yLabel,plotData->dataLabel);
+					
+					//set the appearance of the plot
+					//plotNew->setTraceStyle(plotStyle);
+					plotNew->setColour(plotData->r,plotData->g,plotData->b);
+					
+					
+					plotNew->parentObject=plotData->parent;
+					plotNew->parentPlotIndex=plotData->index;
+					
+					plotID=targetPlots->addPlot(plotNew);
+
+					plotLabels.push_back(make_pair(plotID,plotData->dataLabel));
+					
+					break;
+				}
+				//TODO: Merge back into STREAM_TYPE_PLOT
+				case STREAM_TYPE_PLOT2D:
+				{
+					const Plot2DStreamData *plotData;
+					plotData=((Plot2DStreamData *)((*it)[ui]));
+					//The plot should have some data in it.
+					ASSERT(plotData->getNumBasicObjects());
+					//The plot should have an index, so we can keep
+					//filter choices between refreshes (where possible)
+					ASSERT(plotData->index !=(unsigned int)-1);
+					unsigned int plotID;
+		
+					PlotBase *plotNew;
+					switch(plotData->plotType) 
 					{
-						case PLOT_MODE_1D:
+						case PLOT_2D_DENS:
+						{
+							//Create a 2D plot
+							plotNew= new Plot2DFunc;
+
+							//set the plot info
+							((Plot2DFunc*)plotNew)->setData(plotData->xyData,
+										plotData->xMin, plotData->xMax, 
+										plotData->yMin,plotData->yMax);
+						
+							break;
+						}
+						case PLOT_2D_SCATTER:
 						{
-							//Create a 1D plot
-							Plot1D *plotNew= new Plot1D;
-
-							plotNew->setData(plotData->xyData);
-							plotNew->setLogarithmic(plotData->logarithmic);
-							plotNew->titleAsRawDataLabel=plotData->useDataLabelAsYDescriptor;
-							
-							//Construct any regions that the plot may have
-							for(unsigned int ui=0;ui<plotData->regions.size();ui++)
-							{
-								//add a region to the plot,
-								//using the region data stored
-								//in the plot stream
-								plotNew->regionGroup.addRegion(plotData->regionID[ui],
-									plotData->regionTitle[ui],	
-									plotData->regions[ui].first,
-									plotData->regions[ui].second,
-									plotData->regionR[ui],
-									plotData->regionG[ui],
-									plotData->regionB[ui],plotData->regionParent);
-							}
-
-							plotID=targetPlots->addPlot(plotNew);
+							//Create a 2D plot
+							plotNew= new Plot2DScatter;
+
+							//set the plot info
+							if(plotData->scatterIntensity.size())
+								((Plot2DScatter*)plotNew)->setData(plotData->scatterData,plotData->scatterIntensity);
+							else
+								((Plot2DScatter*)plotNew)->setData(plotData->scatterData);
+							//FIXME: scatter intesity data??
 							break;
 						}
 						default:
 							ASSERT(false);
 					}
-
-				
-					//set the appearance of the plot
-					// -----
-					targetPlots->setTraceStyle(plotID,plotData->plotStyle);
-					targetPlots->setColours(plotID,plotData->r,
-								plotData->g,plotData->b);
-
-					std::wstring xL,yL,titleW;
-					std::string x,y,t;
-
-					xL=stlStrToStlWStr(plotData->xLabel);
-					yL=stlStrToStlWStr(plotData->yLabel);
-					titleW=stlStrToStlWStr(plotData->dataLabel);
-
-					x=stlWStrToStlStr(xL);
-					y=stlWStrToStlStr(yL);
-					t=stlWStrToStlStr(titleW);
-
-					targetPlots->setStrings(plotID,x,y,t);
+					//transfer the axis labels
+					plotNew->setStrings(plotData->xLabel,
+						plotData->yLabel,plotData->dataLabel);
+					
+					//transfer the parent info
+					plotNew->parentObject=plotData->parent;
+					plotNew->parentPlotIndex=plotData->index;
+					
+					plotID=targetPlots->addPlot(plotNew);
+					
 					// -----
-				
-					//set the data origin
-					targetPlots->setParentData(plotID,plotData->parent,
-								plotData->index);
 
 					plotLabels.push_back(make_pair(plotID,plotData->dataLabel));
-					
 					break;
 				}
 				case STREAM_TYPE_DRAW:
@@ -813,14 +868,13 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 	//Update the plotting UI contols
 	//-----------
 	plotSelList->Clear(); // erase wx list
-
+	plotMap.clear();
 	for(size_t ui=0;ui<plotLabels.size();ui++)
 	{
 		//Append the plot to the list in the user interface
-		wxListUint *l = new wxListUint(plotLabels[ui].first);
-		plotSelList->Append(wxStr(plotLabels[ui].second),l);
+		plotSelList->Append((plotLabels[ui].second));
+		plotMap[ui] = plotLabels[ui].first;
 	}
-	plotLabels.clear();
 
 	//If there is only one spectrum, select it
 	if(plotSelList->GetCount() == 1 )
@@ -831,6 +885,10 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 		//to set the selection
 		targetPlots->bestEffortRestoreVisibility();
 
+	}
+
+	for(unsigned int ui=0; ui<plotSelList->GetCount();ui++)
+	{
 #if defined(__WIN32__) || defined(__WIN64__)
 		//Bug under windows. SetSelection(wxNOT_FOUND) does not work for multi-selection list boxes
 		plotSelList->SetSelection(-1, false);
@@ -839,12 +897,9 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 #endif
 		for(unsigned int ui=0; ui<plotSelList->GetCount();ui++)
 		{
-			wxListUint *l;
-			unsigned int plotID;
-
 			//Retrieve the uniqueID
-			l=(wxListUint*)plotSelList->GetClientObject(ui);
-			plotID = l->value;
+			unsigned int plotID;
+			plotID=plotMap[ui];
 			if(targetPlots->isPlotVisible(plotID))
 				plotSelList->SetSelection(ui);
 		}
@@ -908,18 +963,19 @@ unsigned int VisController::updateScene(list<vector<const FilterStreamData *> >
 			displayList->endList();
 			targetScene->addDrawable(displayList);
 		}
-
-		delete displayList;
+		else
+			delete displayList;
 	}
 	else
 	{
 		for(unsigned int ui=0;ui<drawIons.size(); ui++)
 			targetScene->addDrawable(drawIons[ui]);
 	}
-	
+
+	//add all drawable objects (not ions)	
 	for(size_t ui=0;ui<sceneDrawables.size();ui++)
 		targetScene->addDrawable(sceneDrawables[ui]);
-
+	
 	sceneDrawables.clear();
 	targetScene->computeSceneLimits();
 	targetScene->addSelectionDevices(devices);
@@ -979,37 +1035,6 @@ bool VisController::setCam(unsigned int offset)
 	return true;
 }
 
-void VisController::updateCamPropertyGrid(wxCustomPropGrid *g,unsigned int offset) const
-{
-
-	//Erase the grid
-	g->clearKeys();
-
-	//Abort if there are no cameras
-	if(!currentState.getNumCams())
-		return;
-
-	//Obtain the properties of the currently active camera
-	CameraProperties p;
-	currentState.getCam(offset)->getProperties(p);
-
-	//Set the property grid
-	g->setNumGroups(p.data.size());
-	//Create the keys for the property grid to do its thing
-	for(unsigned int ui=0;ui<p.data.size();ui++)
-	{
-		for(unsigned int uj=0;uj<p.data[ui].size();uj++)
-		{
-			//TODO: ADD TOOLTIP
-			g->addKey(p.data[ui][uj].first, ui,p.keys[ui][uj],
-				p.types[ui][uj],p.data[ui][uj].second,string(""));
-		}
-	}
-
-	//Let the property grid layout what it needs to
-	g->propertyLayout();
-}
-
 bool VisController::reparentFilter(size_t filter, size_t newParent)
 {
 	//Save current filter state to undo stack
@@ -1138,14 +1163,20 @@ bool VisController::loadState(const char *cpFilename, std::ostream &errStream, b
 
 	//Load into a temporary state
 	// and if successful, transfer to full state
-	AnalysisState state;
-	bool result=state.load(cpFilename,errStream,merge);
+	AnalysisState tmpState;
+	bool result=tmpState.load(cpFilename,errStream);
 
 	if(!result)
 		return false;
-
-	currentState=state;
-
+	
+	if(merge)
+	{
+		currentState.merge(tmpState);
+	}
+	else
+	{
+		currentState=tmpState;
+	}
 	//Synchronise scene and viscontrol components to 
 	// current state
 
@@ -1217,8 +1248,8 @@ bool VisController::loadState(const char *cpFilename, std::ostream &errStream, b
 	//Try to restore the working directory as needed
 	std::string wd;
 	wd=currentState.getWorkingDir();
-	if(wd.size() && wxDirExists(wxStr(wd)))
-		wxSetWorkingDirectory(wxStr(currentState.getWorkingDir()));
+	if(wd.size() && wxDirExists((wd)))
+		wxSetWorkingDirectory((currentState.getWorkingDir()));
 
 	currentState.setStateModified(false);
 	return true;
@@ -1349,7 +1380,7 @@ void VisController::getStashes(std::vector<std::pair<std::string,unsigned int >
 void VisController::updateRawGrid() const
 {
 	vector<vector<vector<float> > > plotData;
-	vector<std::vector<std::wstring> > labels;
+	vector<std::vector<std::string> > labels;
 	//grab the data for the currently visible plots
 	targetPlots->getRawData(plotData,labels);
 
@@ -1373,8 +1404,8 @@ void VisController::updateRawGrid() const
 		for(unsigned int uj=0;uj<labels[ui].size();uj++)
 		{
 			std::string s;
-			s=stlWStrToStlStr(labels[ui][uj]);
-			targetRawGrid->SetColLabelValue(curCol,wxStr(s));
+			s=(labels[ui][uj]);
+			targetRawGrid->SetColLabelValue(curCol,(s));
 			curCol++;
 		}
 
@@ -1389,7 +1420,7 @@ void VisController::updateRawGrid() const
 			{
 				std::string tmpStr;
 				stream_cast(tmpStr,plotData[ui][uj][uk]);
-				targetRawGrid->SetCellValue(uk,startCol,wxStr(tmpStr));
+				targetRawGrid->SetCellValue(uk,startCol,(tmpStr));
 			}
 			startCol++;
 		}
@@ -1433,7 +1464,7 @@ void VisController::updateConsole(const std::vector<std::string> &v, const Filte
 	{
 		std::string s;
 		s = f->getUserString() + string(" : ") + v[ui];
-		textConsole->AppendText(wxStr(s));
+		textConsole->AppendText((s));
 		textConsole->AppendText(wxT("\n"));
 
 	}
diff --git a/src/backend/viscontrol.h b/src/backend/viscontrol.h
index 6b348e0..107770a 100644
--- a/src/backend/viscontrol.h
+++ b/src/backend/viscontrol.h
@@ -24,7 +24,6 @@
 
 class VisController;
 class wxGrid;
-class wxCustomPropGrid;
 class wxTreeCtrl;
 
 class Scene;
@@ -33,6 +32,7 @@ class Scene;
 #include "backend/plot.h"
 #include "backend/animator.h"
 #include "state.h"
+#include "filter.h"
 
 #include "backend/APT/APTFileIO.h"
 
@@ -99,7 +99,6 @@ class VisController
 		// this is used when loading a state file to prevent from bringing older selection state into current plots
 		bool deferClearPlotVisibility;
 
-		void clear();
 	
 
 		//!Retreive the updates to the filter tree from the scene
@@ -135,6 +134,9 @@ class VisController
 		// the wxTree control
 		std::vector<const Filter *> persistentFilters;
 
+		//Map plot position to ID
+		std::map<size_t, size_t> plotMap;
+
 
 	public:
 		VisController();
@@ -228,7 +230,7 @@ class VisController
 		//Move a filter from one part of the tree to another
 		bool reparentFilter(size_t filterID, size_t newParentID);
 
-		//!Set the properties using a key-value result (as obtained from updatewxCustomPropGrid)
+		//!Set the properties using a key-value result 
 		/*
 		 * The return code tells whether to reject or accept the change. 
 		 * need update tells us if the change to the filter resulted in a change to the scene
@@ -264,7 +266,7 @@ class VisController
 		void setScene(Scene *theScene);
 		//!Set the backend plot
 		void setPlotWrapper(PlotWrapper *thePlots){targetPlots=thePlots;};
-		
+			
 		PlotWrapper *getPlotWrapper(){return targetPlots;};
 		//!Set the listbox for plot selection
 		void setPlotList(wxListBox *box){plotSelList=box;};
@@ -272,17 +274,18 @@ class VisController
 		
 		//!Set the backend grid control for raw data
 		void setRawGrid(wxGrid *theRawGrid){targetRawGrid=theRawGrid;};
-	
+
+		//Get a plot ID from the listbox position
+		size_t getPlotID(size_t position) const ;
 	
 		//!Write out the filters into a wxtreecontrol.
 		// optional argument is the fitler to keep visible in the control
 		void updateWxTreeCtrl(wxTreeCtrl *t,const Filter *f=0);
-		//!Update a wxCustomPropGrid with the properties for a given filter
-		void updateFilterPropGrid(wxCustomPropGrid *g,size_t filterId) const;
-			
-
-
-
+		//!Update a wxPropertyGrid with the properties for a given filter
+		void updateFilterPropGrid(wxPropertyGrid *g,size_t filterId, const std::string &stateString="") const; 
+		//!Update a wxPropertyGrid with the properties for a given filter
+		void updateCameraPropGrid(wxPropertyGrid *g,size_t cameraId) const; 
+		
 		//!Set the camera to use in the scene
 		bool setCam(unsigned int uniqueID) ;
 
@@ -292,13 +295,10 @@ class VisController
 		//!Add a new camera to the scene
 		unsigned int addCam(const std::string &camName);
 
-		//!Update a wxtGrid with the properties for a given filter
-		void updateCamPropertyGrid(wxCustomPropGrid *g,unsigned int camId) const;
-		
 		//!Return the number of cameras
 		unsigned int numCams() const ;
 
-		//!Set the properties using a key-value result (as obtaed from updatewxCustomPropGrid)
+		//!Set the properties using a key-value result 
 		/*! The return code tells whether to reject or accept the change. 
 		 */
 		bool setCamProperties(size_t camId, 
@@ -456,6 +456,11 @@ class VisController
 		void getAnimationState(PropertyAnimator &pA, 
 				std::vector<pair<string,size_t> > &pathMapping) const;
 
+		//wipe the state. Does not perform a refresh  need to do this manually
+		void clear();
+
+		//Return the number of filters that are currently in the state
+		size_t getNumFilters() const { return filterTree.size();}
 #ifdef DEBUG
 		//Check that the tree conrol is synced up to the filter map correctly
 		void checkTree(wxTreeCtrl *t);
diff --git a/src/common/array2D.h b/src/common/array2D.h
new file mode 100644
index 0000000..65f0660
--- /dev/null
+++ b/src/common/array2D.h
@@ -0,0 +1,223 @@
+/*
+ *  Array2D.h: This file was part of RawTherapee, but is
+ *  used as a general-purpose array module.
+ *
+ *  Copyright (c) 2011 Jan Rinze Peterzon (janrinze at gmail.com)
+ *
+ *  this program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  this program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ *  Declaration of flexible 2D arrays
+ *
+ *  Usage:
+ *
+ *  	Array2D<type> name (X-size,Y-size);
+ *		Array2D<type> name (X-size,Y-size type ** data);
+ *
+ *		creates an array which is valid within the normal C/C++ scope "{ ... }"
+ *
+ *      access to elements is a simple as:
+ *
+ *      	Array2D<float> my_array (10,10); // creates 10x10 array of floats
+ *      	value =  my_array[3][5];
+ *      	my_array[4][6]=value;
+ *
+ *      or copy an existing 2D array
+ *
+ *      	float ** mydata;
+ *      	Array2D<float> my_array (10,10,mydata);
+ *
+ *
+ *		Useful extra pointers
+ *
+ *			<type> ** my_array		gives access to the pointer for access with [][]
+ *			<type> *  my_array		gives access to the flat stored data.
+ *
+ *		Advanced usage:
+ *			Array2D<float> my_array				; // empty container.
+ *			my_array(10,10) 					; // resize to 10x10 array
+ *			my_array(10,10,ARRAY2D_CLEAR_DATA)  ; // resize to 10x10 and clear data
+ *
+ */
+#ifndef ARRAY2D_H_
+#define ARRAY2D_H_
+
+#include <cstring>
+#include <cstdio>
+
+template<typename T>
+class Array2D {
+
+private:
+	unsigned int x, y;
+	T ** ptr;
+	T * data;
+	void ar_realloc(unsigned int w, unsigned int h) {
+		if ((ptr) && ((h > y) || (4 * h < y))) {
+			delete[] ptr;
+			ptr = NULL;
+		}
+		if ((data) && (((h * w) > (x * y)) || ((h * w) < ((x * y) / 4)))) {
+			delete[] data;
+			data = NULL;
+		}
+		if (ptr == NULL)
+			ptr = new T*[h];
+		if (data == NULL)
+			data = new T[h * w];
+
+		x = w;
+		y = h;
+		#pragma omp parallel for
+		for (unsigned int i = 0; i < h; i++)
+			ptr[i] = data + w * i;
+	}
+public:
+
+	// use as empty declaration, resize before use!
+	// very useful as a member object
+	Array2D() :
+		x(0), y(0), ptr(NULL), data(NULL) {
+	}
+
+	// creator type1
+	Array2D(unsigned int w, unsigned int h) {
+		data = new T[h * w];
+		x = w;
+		y = h;
+		ptr = new T*[h];
+		#pragma omp parallel for
+		for (unsigned int i = 0; i < h; i++)
+			ptr[i] = data + i * w;
+	}
+
+	// creator type 2
+	Array2D(unsigned int w, unsigned int h, T ** source ) {
+		// when by reference
+		// TODO: improve this code with ar_realloc()
+			data = new T[h * w];
+		x = w;
+		y = h;
+		ptr = new T*[h];
+		#pragma omp parallel for
+		for (unsigned int i = 0; i < h; i++) {
+			ptr[i] = data + i * w;
+			for (unsigned int j = 0; j < w; j++)
+				ptr[i][j] = source[i][j];
+		}
+	}
+
+	// destructor
+	~Array2D() {
+
+		if (data)
+			delete[] data;
+		if (ptr)
+			delete[] ptr;
+	}
+
+	Array2D(const Array2D &other)
+	{
+		*this=other;
+	}
+	
+	// use with indices
+	T * operator[](unsigned int index) const {
+        ASSERT((index>=0) && (index < y));
+		return ptr[index];
+	}
+
+	// use as pointer to T**
+	operator T**() const {
+		return ptr;
+	}
+
+	// use as pointer to data
+	operator T*() const {
+		return data;
+	}
+
+
+	// useful within init of parent object
+	// or use as resize of 2D array
+	void operator()(unsigned int w, unsigned int h ) {
+		ar_realloc(w,h);
+	}
+
+	// import from flat data
+	void operator()(unsigned int w, unsigned int h, T* copy) {
+		ar_realloc(w,h);
+		memcpy(data, copy, w * h * sizeof(T));
+	}
+	unsigned int width() const {
+		return x;
+	}
+	unsigned int height() const {
+		return y;
+	}
+
+	bool empty() const
+	{
+		return data == NULL;
+	}
+
+	operator bool() const {
+		return (x > 0 && y > 0);
+	}
+
+
+	void resize(unsigned int newX, unsigned int newY)
+	{
+		ar_realloc(newX,newY);	
+	}
+	
+	unsigned int size() const
+	{
+		return x*y;
+	}
+	void clear() 
+	{
+		delete data;
+		data=NULL;
+	}
+
+	void unpack(std::vector<std::vector<T> > &data) const
+	{
+		data.resize(y);
+#pragma omp parallel for
+		for(unsigned int ui=0;ui<y; ui++)
+		{
+			data[ui].resize(x);
+			for(unsigned int uj=0;uj<x;uj++)
+				data[ui][uj]=ptr[ui][uj];
+		}
+	}
+
+	Array2D<T> & operator=( const Array2D<T> & rhs) {
+		if (this != &rhs)
+
+		{
+			ar_realloc(rhs.x, rhs.y);
+			// we could have been created from a different
+			// array format where each row is created by 'new'
+			#pragma omp parallel for
+			for (unsigned int i=0;i<y;i++)
+				memcpy(ptr[i],rhs.ptr[i],x*sizeof(T));
+		}
+		return *this;
+	}
+
+};
+#endif /* Array2D_H_ */
diff --git a/src/common/basics.cpp b/src/common/basics.cpp
index 061d074..85062fb 100644
--- a/src/common/basics.cpp
+++ b/src/common/basics.cpp
@@ -49,21 +49,7 @@ using std::vector;
 using std::list;
 
 
-//Name of the  DTD file for state loading
-const char *DTD_NAME="threeDepict-state.dtd";
-//Program name
-const char *PROGRAM_NAME = "3Depict";
-//Program version
-const char *PROGRAM_VERSION = "0.0.16";
-//Path to font for Default FTGL  font
-const char *FONT_FILE= "FreeSans.ttf";
-
-const char *TEXT_LOAD_ERR_STRINGS[] = { "",
-       					NTRANS("Error opening file"),
-       					NTRANS("Error whilst reading file contents"),
-					NTRANS("Error interpreting field in file"),
-					NTRANS("Inconsistent number of columns found")
-					};
+
 
 //default font to use.
 std::string defaultFontFile;
@@ -310,7 +296,334 @@ string veryFuzzyTimeSince( time_t origTime, time_t nowTime)
 	return TRANS("moments ago");
 }
 
+ColourRGBA::ColourRGBA()
+{
+}
+
+ColourRGBA::ColourRGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) 
+{
+	data[0]=r;
+	data[1]=g;
+	data[2]=b;
+	data[3]=a;
+}
+
+
+ColourRGBA::ColourRGBA(unsigned char r, unsigned char g, unsigned char b) 
+{
+	data[0]=r;
+	data[1]=g;
+	data[2]=b;
+}
+
+unsigned char ColourRGBA::at(unsigned int idx) const
+{
+	ASSERT(idx< 4);
+	return data[idx];
+}
+
+unsigned char ColourRGBA::r() const
+{
+    return data[0];
+}
+
+unsigned char ColourRGBA::g() const
+{
+    return data[1];
+}
+
+unsigned char ColourRGBA::b() const
+{
+    return data[2];
+}
+
+unsigned char ColourRGBA::a() const
+{
+    return data[3];
+}
+
+bool ColourRGBA::parse(const std::string &str)	
+{
+	//Input string is in 2 char hex form, 3 or 4 colour, with # leading. RGB order
+	//lowercase string.
+	if(str.size() != 9 && str.size() != 7)
+		return false;
+
+	if(str[0] != '#')
+		return false;
+
+	string rS,gS,bS,aS;
+	rS=str.substr(1,2);
+	gS=str.substr(3,2);
+	bS=str.substr(5,2);
+
+	if(!isxdigit(rS[0]) || !isxdigit(rS[1]))
+		return false;
+	if(!isxdigit(gS[0]) || !isxdigit(gS[1]))
+		return false;
+	if(!isxdigit(bS[0]) || !isxdigit(bS[1]))
+		return false;
+
+	unsigned char r,g,b,a;
+	hexStrToUChar(str.substr(1,2),r);	
+	hexStrToUChar(str.substr(3,2),g);	
+	hexStrToUChar(str.substr(5,2),b);	
+	//3 colour must have a=255.
+	if(str.size() == 7)
+		a = 255;
+	else
+	{
+		aS=str.substr(7,2);
+		if(!isxdigit(aS[0]) || !isxdigit(aS[1]))
+			return false;
+		hexStrToUChar(str.substr(7,2),a);	
+	}
+	
+	data[0]=r;
+	data[1]=g;
+	data[2]=b;
+	data[3]=a;
+	return true;
+}
+
+std::string ColourRGBA::rgbaString() const
+{
+	std::string s="#", tmp;
+	ucharToHexStr(data[0],tmp);
+	s+=tmp;
+	ucharToHexStr(data[1],tmp);
+	s+=tmp;
+	ucharToHexStr(data[2],tmp);
+	s+=tmp;
+	ucharToHexStr(data[3],tmp);
+	s+=tmp;
+
+	return s;
+}
+
+std::string ColourRGBA::rgbString() const
+{
+	string tmp,s;
+	s="#";
+	ucharToHexStr(data[0],tmp);
+	s+=tmp;
+	ucharToHexStr(data[1],tmp);
+	s+=tmp;
+	ucharToHexStr(data[2],tmp);
+	s+=tmp;
+
+	return s;
+}
+
+RGBf ColourRGBA::toFloat() const
+{
+	RGBf ret;
+	ret.red=(float)data[0]/255.0f;
+	ret.green=(float)data[1]/255.0f;
+	ret.blue=(float)data[2]/255.0f;
+
+	return ret;
+}
+
+ColourRGBAf ColourRGBA::toRGBAf() const
+{
+	ColourRGBAf tmp;
+		
+	for(unsigned int ui=0;ui<4;ui++)
+	{
+		tmp[ui] = (float)data[ui]/255.0f;
+	}
+
+	return tmp;
+}
+
+void ColourRGBA::fromRGBf(const RGBf &oth) 
+{
+	data[0]=oth.red*255.0f;
+	data[1]=oth.green*255.0f;
+	data[2]=oth.blue*255.0f;
+	data[3]=255.0f;
+}
+
+bool ColourRGBA::operator==(const ColourRGBA &oth) const
+{
+	for(unsigned int ui=0;ui<4;ui++)
+	{
+		if(data[ui] != oth.data[ui])
+			return false;
+	}
+	return true;
+}
+
+bool ColourRGBA::operator==(const ColourRGBAf &oth) const
+{
+	for(unsigned int ui=0;ui<4;ui++)
+	{
+		if(data[ui] != oth.at(ui))
+			return false;
+	}
+	return true;
+}
+
+bool ColourRGBA::operator==(const RGBf &oth) const
+{
+	return (data[0]/255.0f == oth.red && data[1]/255.0f == oth.green && data[2]/255.0f == oth.blue);
+		
+}
+
+bool ColourRGBA::operator!=(const ColourRGBA &oth) const
+{
+	return !(*this == oth);
+}
+
+bool ColourRGBA::operator!=(const ColourRGBAf &oth) const
+{
+	return !(*this == oth);
+}
+
+
+ColourRGBAf::ColourRGBAf()
+{
+}
+
+ColourRGBAf::ColourRGBAf(float r, float g, float b, float a) 
+{
+	ASSERT(r >=0 && r <=1.0f); 
+	ASSERT(g >=0 && g <=1.0f); 
+	ASSERT(b >=0 && b <=1.0f); 
+	ASSERT(a >=0 && a <=1.0f); 
+	data[0]=r;
+	data[1]=g;
+	data[2]=b;
+	data[3]=a;
+}
+
+
+ColourRGBAf::ColourRGBAf(float r, float g, float b) 
+{
+	ASSERT(r >=0 && r <=1.0f); 
+	ASSERT(g >=0 && g <=1.0f); 
+	ASSERT(b >=0 && b <=1.0f); 
+	data[0]=r;
+	data[1]=g;
+	data[2]=b;
+	data[3]=1.0f;
+}
+float ColourRGBAf::r() const
+{
+    return data[0];
+}
+
+float ColourRGBAf::g() const
+{
+    return data[1];
+}
+
+float ColourRGBAf::b() const
+{
+    return data[2];
+}
+
+float ColourRGBAf::a() const
+{
+    return data[3];
+}
+
+void ColourRGBAf::r(float v)
+{
+	ASSERT(v >=0.0f && v <=1.0f);
+	data[0]=v;
+}
+
+void ColourRGBAf::g(float v)
+{
+	ASSERT(v >=0.0f && v <=1.0f);
+	data[1]=v;
+}
+
+void ColourRGBAf::b(float v)
+{
+	ASSERT(v >=0.0f && v <=1.0f);
+	data[2]=v;
+}
+
+void ColourRGBAf::a(float v)
+{
+	ASSERT(v >=0.0f && v <=1.0f);
+	data[3]=v;
+}
+float &ColourRGBAf::operator[](unsigned int idx) 
+{
+	ASSERT(idx < 4);
+	return data[idx];
+}
+
+float ColourRGBAf::at(unsigned int idx) const
+{
+	return data[idx];
+}
+
+		
+ColourRGBAf ColourRGBAf::interpolate(float delta, const ColourRGBAf &other)
+{
+	ColourRGBAf result;
+
+	for(unsigned int ui=0;ui<3;ui++)
+		result[ui] = data[ui] + (other.data[ui] - data[ui])*delta;
+	return result;
+}
+
+ColourRGBA ColourRGBAf::toColourRGBA() const
+{
+	ColourRGBA tmp(data[0]*255.0f,data[1]*255.0f,
+			data[2]*255.0f,data[3]*255.0f);
+	return tmp;
+}
+
+RGBf ColourRGBAf::toRGBf() const
+{
+	RGBf tmp;
+	tmp.red=data[0];
+	tmp.green=data[1];
+	tmp.blue=data[2];
+	return tmp;
+}
+
+
+void ColourRGBAf::operator=(const RGBf &oth)
+{
+	data[0]= oth.red;
+	data[1]= oth.green;
+	data[2]= oth.blue;
+	data[3]= 1.0f;
+}
+
+
+bool ColourRGBAf::operator==(const ColourRGBA &oth) const
+{
+	for(unsigned int ui=0;ui<3;ui++)
+	{
+		if(data[ui] != (float)oth.at(ui)/255.0f)
+			return false;
+	}
+
+	return true;
+}
+
+bool ColourRGBAf::operator==(const ColourRGBAf &oth) const
+{
+	for(unsigned int ui=0;ui<3;ui++)
+	{
+		if(data[ui] != (float)oth.data[ui])
+			return false;
+	}
 
+	return true;
+}
+bool ColourRGBAf::operator!=(const ColourRGBAf  &oth) const
+{
+	return !(*this == oth);
+}
 void BoundCube::getBound(Point3D &retBound, unsigned int minMax) const
 {
 	retBound=Point3D(bounds[0][minMax],
@@ -367,6 +680,17 @@ void BoundCube::setBounds(const std::vector<Point3D> &points)
 #endif
 }
 
+void BoundCube::setBounds(const Point3D &p, float r)
+{
+	for(unsigned int dim=0;dim<3;dim++)
+	{
+		bounds[dim][0] = p[dim] - r;
+		bounds[dim][1] = p[dim] + r;
+		valid[dim][0]=true;
+		valid[dim][1]=true;
+	}
+}
+
 void BoundCube::getVertices(std::vector<Point3D> &points, bool centre) const
 {
 	points.resize(8);
@@ -610,6 +934,38 @@ bool BoundCube::intersects(const Point3D &pt, float sqrRad)
 	return (nearPt.sqrDist(pt) <=sqrRad);
 }
 
+BoundCube BoundCube::makeUnion(const BoundCube &bC) const
+{
+	BoundCube res;
+	for(unsigned int dim=0;dim<3;dim++)
+	{
+		float a,b;
+		a=bounds[dim][0]; b=bC.bounds[dim][0];
+		res.setBound(dim,0,std::max(a,b));
+		a=bounds[dim][1]; b=bC.bounds[dim][1];
+		res.setBound(dim,1,std::min(a,b));
+	}
+
+	return res;
+}
+
+unsigned int BoundCube::segmentTriple(unsigned int dim, float slice) const
+{
+	ASSERT(dim < 3);
+
+	//check lower
+	if( slice < bounds[dim][0])
+		return 0;
+	
+	//check upper
+	if( slice >=bounds[dim][1])
+		return 2;
+
+	return 1;
+
+}
+
+
 Point3D BoundCube::getCentroid() const
 {
 #ifdef DEBUG
@@ -1147,36 +1503,27 @@ bool isValidXML(const char *filename)
 	return true;
 }
 
+#if !defined(__WIN32__) && !defined(__WIN64)
 	
-//FIXME: Why negative?
 bool isNotDirectory(const char *filename)
 {
-#if !defined(__WIN32__) && !defined(__WIN64__)
 	struct stat statbuf;
 
 	if(stat(filename,&statbuf) == -1)
 		return false;
 
 	return (statbuf.st_mode !=S_IFDIR);
-#else
-
-	WARN(false, "Untested function. calling win api");
-	DWORD fileAttribs;
-	fileAttribs=GetFileAttributes((LPCWSTR)filename);
-	if(fileAttribs == INVALID_FILE_ATTRIBUTES)
-		return false;
-
-	return !(fileAttribs & FILE_ATTRIBUTE_DIRECTORY);
-#endif
 }
 
 bool rmFile(const std::string &filename)
 {
-#if !defined(__WIN32__) && !defined(__WIN64__)
 	return remove(filename.c_str()) == 0;
-#else
-	WARN(false, "Untested function. calling win api");
-	return DeleteFile((LPCWSTR)filename.c_str());
-#endif
 }
+#elif defined(__WIN32) || defined(__WIN64)
+bool rmFile(const std::string &filename)
+{ 
+	return DeleteFile((const wchar_t*)filename.c_str()) == 0;
+}
+#endif
+
 #endif
diff --git a/src/common/basics.h b/src/common/basics.h
index d0f5d5f..5067d40 100644
--- a/src/common/basics.h
+++ b/src/common/basics.h
@@ -36,10 +36,6 @@ class K3DTree;
 
 bool dummyCallback(bool);
 
-extern const char *DTD_NAME;
-extern const char *PROGRAM_NAME;
-extern const char *PROGRAM_VERSION;
-extern const char *FONT_FILE;
 
 
 //Set new locale code. Must be followed by a popLocale call before completion
@@ -95,7 +91,6 @@ enum
 	ERR_FILE_ENUM_END // not an error, just end of enum
 };
 
-extern const char *TEXT_LOAD_ERR_STRINGS[];
 
 //Perform a a<-b<-c<-a rotation of data
 template<class T>
@@ -359,8 +354,16 @@ public:
     void setBounds( const Point3D &p, const Point3D &q);
     //!Obtain bounds from an array of Point3Ds
     void setBounds(const std::vector<Point3D> &ptArray);
+
+    //!Set bounds via cube that contains given sphere
+    void setBounds(const Point3D &p, float radius);
+
+    //Set & set-like operations
     //!Checks if a point intersects a sphere of centre Pt, radius^2 sqrRad
     bool intersects(const Point3D &pt, float sqrRad);
+   
+    //Create a union of two bounding cubes, which is itself a cube 
+    BoundCube makeUnion(const BoundCube &b) const;
     //Check to see if the point is contained in, or part of the walls
     //of the cube
     bool containsPt(const Point3D &pt) const;
@@ -370,6 +373,8 @@ public:
     //!Is this bounding cube completely contained within a sphere centred on pt of sqr size sqrRad?
     bool containedInSphere(const Point3D &pt, float sqrRad) const;
 
+
+    unsigned int segmentTriple(unsigned int dim, float slice) const;
     //!Returns maximum distnace to box corners (which is an upper bound on max box distance). 
     //Bounding box must be valid.
     float getMaxDistanceToBox(const Point3D &pt) const;
@@ -397,72 +402,97 @@ public:
     friend class K3DTreeMk2;
 };
 
+//!Data holder for colour as float
+typedef struct RGBf
+{
+	float red;
+	float green;
+	float blue;
+} RGBf;
 
+class ColourRGBAf;
 
-
-//OK, this is a bit tricky. We override the operators to call
-//a callback, so the UI updates keep happening, even inside the STL function
-//----
-template<class T>
-class GreaterWithCallback 
+//Colour storage class. Uses uchar internally
+class ColourRGBA
 {
-	private:
-		bool (*callback)(bool);
-		//!Reduction frequency (use callback every k its)
-		unsigned int redMax;
-		//!Current reduction counter
-		unsigned int reduction;
-		//!pointer to progress value
-		unsigned int *prgPtr;
 	public:
-		//!Second argument is a "reduction" value to set the number of calls
-		//to the random functor before initiating a callback
-		GreaterWithCallback( bool (*ptr)(bool),unsigned int red) : callback(ptr), redMax(red), reduction(red)
-	{};
+		unsigned char data[4];
+	public:
+		ColourRGBA();
+		ColourRGBA(unsigned char , unsigned char, unsigned char);
+		ColourRGBA(unsigned char , unsigned char, unsigned char, unsigned char);
+		unsigned char r() const;
+		unsigned char g() const;
+		unsigned char b() const;
+		unsigned char a() const;
+		
+		//Parse a colour string, such as #aabbccdd into its RGBA 8-bit components. alpha value (last) can be omitted. Will assume 255.
+		bool parse(const std::string &);
+
+		//Convert an RGB its 
+		// hexadecimal colour string
+		// format is "#rrggbb" such as "#11ee00"
+		std::string rgbString() const;
+		//Convert RGB to hex colour string, with alpha channel
+		std::string rgbaString() const;
+
+		//convert data from RGB/[0->255] integers to [0->1] float.
+		// alpha channel is not used
+		RGBf toFloat() const;
+
+		void fromRGBAf(const ColourRGBAf &);
+		ColourRGBAf toRGBAf() const;
+		
+		void fromRGBf(const RGBf &);
 
-		bool operator()(const T &a, const T &b) 
-		{
-			if(!reduction--)
-			{
-				reduction=redMax;
-				//Execute callback
-				(*callback)(false);
-			}
+		bool operator==(const ColourRGBA &oth) const;
+		bool operator==(const ColourRGBAf &oth) const;
+		bool operator==(const RGBf &oth) const;
+		
+		bool operator!=(const ColourRGBA &oth) const;
+		bool operator!=(const ColourRGBAf &oth) const;
+		
+		unsigned char at(unsigned int idx) const;
 
-			return a < b;
-		}
 };
 
-
-template<class T>
-class EqualWithCallback 
+//Colour storage class. Uses float internally
+class ColourRGBAf
 {
 	private:
-		bool (*callback)(bool);
-		//!Reduction frequency (use callback every k its)
-		unsigned int redMax;
-		//!Current reduction counter
-		unsigned int reduction;
+		float data[4];
 	public:
-		//!Second argument is a "reduction" value to set the number of calls
-		//to the random functor before initiating a callback
-		EqualWithCallback( bool (*ptr)(bool),unsigned int red) : callback(ptr), redMax(red), reduction(red)
-			{ };
-
-		bool operator()(const T &a, const T &b) 
-		{
-			if(!reduction--)
-			{
-				reduction=redMax;
-				//Execute callback
-				(*callback)(false);
-			}
-
-			return a ==b;
-		}
+		ColourRGBAf();
+		ColourRGBAf(float, float, float);
+		ColourRGBAf(float, float, float,float);
+		float r() const;
+		float g() const;
+		float b() const;
+		float a() const;
+		
+		void r(float);
+		void g(float);
+		void b(float);
+		void a(float);
+
+
+		ColourRGBAf interpolate(float delta, const ColourRGBAf &other);
+		//convert to a ColourRGBA (uchar representation)
+		//TODO : Rename me!
+		ColourRGBA toColourRGBA() const; 
+		RGBf toRGBf() const; 
+		bool operator==(const ColourRGBA &oth) const;
+		bool operator!=(const ColourRGBA &oth) const;
+		bool operator==(const ColourRGBAf &oth) const;
+		bool operator!=(const ColourRGBAf &oth) const;
+		
+		//TODO: Deprecate me!
+		bool operator==(const RGBf &oth) const;
+		
+		void operator=(const RGBf &oth);
+		float &operator[](unsigned int idx) ;
+		float at(unsigned int idx) const;
 };
-//----
-
 
 //Randomly select subset. Subset will be (somewhat) sorted on output
 template<class T> size_t randomSelect(std::vector<T> &result, const std::vector<T> &source, 
@@ -503,10 +533,7 @@ template<class T> size_t randomSelect(std::vector<T> &result, const std::vector<
 			ticks[ui]=(size_t)(rng.genUniformDev()*(source.size()-1));
 
 		//Remove duplicates. Intersperse some callbacks to be nice
-		GreaterWithCallback<size_t> gFunctor(callback,50000);
-		std::sort(ticks.begin(),ticks.end(),gFunctor);
-		EqualWithCallback<size_t> eqFunctor(callback,50000);
-
+		std::sort(ticks.begin(),ticks.end());
 		std::vector<size_t>::iterator newLast;
 		newLast=std::unique(ticks.begin(),ticks.end());	
 		ticks.erase(newLast,ticks.end());
@@ -526,8 +553,8 @@ template<class T> size_t randomSelect(std::vector<T> &result, const std::vector<
 	
 			}
 
-			std::sort(ticks.begin(),ticks.end(),gFunctor);
-			newLast=std::unique(ticks.begin(),ticks.end(),eqFunctor);	
+			std::sort(ticks.begin(),ticks.end());
+			newLast=std::unique(ticks.begin(),ticks.end());	
 			ticks.erase(newLast,ticks.end());
 		}
 
@@ -556,7 +583,7 @@ template<class T> size_t randomSelect(std::vector<T> &result, const std::vector<
 		else
 		{
 			//Sort the ticks properly (mostly sorted anyway..)
-			std::sort(ticks.begin(),ticks.end(),gFunctor);
+			std::sort(ticks.begin(),ticks.end());
 
 			unsigned int curTick=0;
 			for(size_t ui=0;ui<source.size(); ui++)
@@ -677,13 +704,12 @@ template<class T> size_t randomDigitSelection(std::vector<T> &result, const size
 			ticks[ui]=(size_t)(rng.genUniformDev()*(max-1));
 
 		//Remove duplicates. Intersperse some callbacks to be nice
-		GreaterWithCallback<size_t> gFunctor(callback,50000);
-		std::sort(ticks.begin(),ticks.end(),gFunctor);
-		EqualWithCallback<size_t> eqFunctor(callback,50000);
-		
+		std::sort(ticks.begin(),ticks.end());
+		(*callback)(false);
 		std::vector<size_t>::iterator itLast;
-		itLast=std::unique(ticks.begin(),ticks.end(),eqFunctor);	
+		itLast=std::unique(ticks.begin(),ticks.end());	
 		ticks.erase(itLast,ticks.end());
+		(*callback)(false);
 		
 		//Top up with unique entries
 		while(ticks.size() < numTicksNeeded)
@@ -698,9 +724,11 @@ template<class T> size_t randomDigitSelection(std::vector<T> &result, const size
 	
 			}
 
-			std::sort(ticks.begin(),ticks.end(),gFunctor);
-			itLast=std::unique(ticks.begin(),ticks.end(),eqFunctor);	
+			std::sort(ticks.begin(),ticks.end());
+			(*callback)(false);
+			itLast=std::unique(ticks.begin(),ticks.end());	
 			ticks.erase(itLast,ticks.end());
+			(*callback)(false);
 		}
 
 
@@ -730,7 +758,7 @@ template<class T> size_t randomDigitSelection(std::vector<T> &result, const size
 		else
 		{
 			//Sort the ticks properly (mostly sorted anyway..)
-			std::sort(ticks.begin(),ticks.end(),gFunctor);
+			std::sort(ticks.begin(),ticks.end());
 			
 			unsigned int curTick=0;
 			for(size_t ui=0;ui<numTicksNeeded; ui++)
diff --git a/src/common/translation.h b/src/common/constants.cpp
similarity index 50%
copy from src/common/translation.h
copy to src/common/constants.cpp
index 1a7eea7..61d3da9 100644
--- a/src/common/translation.h
+++ b/src/common/constants.cpp
@@ -1,5 +1,5 @@
 /*
- * common/translation.h  - Program gettext translation macros
+ * common/constants.cpp  - Common constants used across program
  * Copyright (C) 2013  D Haley
  * 
  * This program is free software: you can redistribute it and/or modify
@@ -15,26 +15,17 @@
  * You should have received a copy of the GNU General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-
-#ifndef TRANSLATION_H
-#define TRANSLATION_H
-
-#include <locale>
-
-
-#if defined(__APPLE__) || defined(__WIN32__) || defined(__WIN64__)
-#include <libintl.h>
-#endif
-
-//!Gettext translation macro
-#define TRANS(x) (gettext(x))
-
-//!Gettext null-translation macro (mark for translation, but do nothing)
-#define NTRANS(x) (x)
-
-//!Wx friendly gettext translation macro
-#define wxTRANS(x) (wxString(gettext(x),*wxConvCurrent))
-
-#define wxNTRANS(x) wxT(x)
-
-#endif
+#include "constants.h"
+#include "translation.h"
+
+//pattern to use when looking for rangefiles
+const char *RANGEFILE_WX_CONSTANT= NTRANS("Range Files (*.rng; *.env; *.rrng)|*.rng;*.env;*.rrng;*.RRNG;*.RNG;*.ENV|RNG File (*.rng)|*.rng;*.RNG|Environment File (*.env)|*.env;*.ENV|RRNG Files (*.rrng)|*.rrng;*.RRNG|All Files (*)|*");
+
+//Name of the  DTD file for state loading
+const char *DTD_NAME="threeDepict-state.dtd";
+//Program name
+const char *PROGRAM_NAME = "3Depict";
+//Program version
+const char *PROGRAM_VERSION = "0.0.17";
+//Path to font for Default FTGL  font
+const char *FONT_FILE= "FreeSans.ttf";
diff --git a/src/common/constants.h b/src/common/constants.h
index ed33513..56208fe 100644
--- a/src/common/constants.h
+++ b/src/common/constants.h
@@ -18,6 +18,8 @@
 #ifndef COMMONCONSTANTS_H
 #define COMMONCONSTANTS_H
 
+#include "translation.h"
+
 //C-style Array size macro
 #define THREEDEP_ARRAYSIZE(f) (sizeof (f) / sizeof(*f))
 //C++1x availabilty (as far as we are concerned)
@@ -30,25 +32,6 @@
 const unsigned int OPENMP_MIN_DATASIZE=1000;
 
 
-enum
-{
-  PLOT_TRACE_LINES=0,
-  PLOT_TRACE_BARS,
-  PLOT_TRACE_STEPS,
-  PLOT_TRACE_STEM,
-  PLOT_TRACE_POINTS,
-  PLOT_TRACE_ENDOFENUM
-};
-
-//Plot types
-enum
-{
-	PLOT_MODE_1D,
-	PLOT_MODE_2D,
-	PLOT_MODE_ENUM_END
-};
-
-
 //Plot error types
 enum
 {
@@ -73,6 +56,7 @@ enum
 	PROPERTY_TYPE_STRING,
 	PROPERTY_TYPE_POINT3D,
 	PROPERTY_TYPE_CHOICE,
+	PROPERTY_TYPE_FILE,
 	PROPERTY_TYPE_ENUM_END //Not a prop, just end of enum
 };
 
@@ -97,4 +81,11 @@ struct PLOT_ERROR
 	unsigned int edgeMode;
 };
 
+extern const char *RANGEFILE_WX_CONSTANT;
+
+extern const char *DTD_NAME;
+extern const char *PROGRAM_NAME;
+extern const char *PROGRAM_VERSION;
+extern const char *FONT_FILE;
+
 #endif
diff --git a/src/common/stringFuncs.cpp b/src/common/stringFuncs.cpp
index b109b06..cd0ffdc 100644
--- a/src/common/stringFuncs.cpp
+++ b/src/common/stringFuncs.cpp
@@ -334,73 +334,6 @@ std::string choiceString(std::vector<std::pair<unsigned int, std::string> > comb
 	return s;
 }
 
-bool parseColString(const std::string &str,
-	unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a)
-{
-	//Input string is in 2 char hex form, 3 or 4 colour, with # leading. RGB order
-	//lowercase string.
-	if(str.size() != 9 && str.size() != 7)
-		return false;
-
-	if(str[0] != '#')
-		return false;
-
-	string rS,gS,bS,aS;
-	rS=str.substr(1,2);
-	gS=str.substr(3,2);
-	bS=str.substr(5,2);
-
-	if(!isxdigit(rS[0]) || !isxdigit(rS[1]))
-		return false;
-	if(!isxdigit(gS[0]) || !isxdigit(gS[1]))
-		return false;
-	if(!isxdigit(bS[0]) || !isxdigit(bS[1]))
-		return false;
-
-	hexStrToUChar(str.substr(1,2),r);	
-	hexStrToUChar(str.substr(3,2),g);	
-	hexStrToUChar(str.substr(5,2),b);	
-	//3 colour must have a=255.
-	if(str.size() == 7)
-		a = 255;
-	else
-	{
-		aS=str.substr(7,2);
-		if(!isxdigit(aS[0]) || !isxdigit(aS[1]))
-			return false;
-		hexStrToUChar(str.substr(7,2),a);	
-	}
-	return true;
-}
-
-void genColString(unsigned char r, unsigned char g, 
-			unsigned char b, unsigned char a, std::string &s)
-{
-	s="#";
-	string tmp;
-	ucharToHexStr(r,tmp);
-	s+=tmp;
-	ucharToHexStr(g,tmp);
-	s+=tmp;
-	ucharToHexStr(b,tmp);
-	s+=tmp;
-	ucharToHexStr(a,tmp);
-	s+=tmp;
-
-}
-
-void genColString(unsigned char r, unsigned char g, 
-			unsigned char b, std::string &s)
-{
-	string tmp;
-	s="#";
-	ucharToHexStr(r,tmp);
-	s+=tmp;
-	ucharToHexStr(g,tmp);
-	s+=tmp;
-	ucharToHexStr(b,tmp);
-	s+=tmp;
-}
 
 //Strip "whitespace"
 std::string stripWhite(const std::string &str)
@@ -457,6 +390,16 @@ std::string lowercase(std::string s)
 	return s;
 }
 
+std::string uppercase(std::string s)
+{
+	for(unsigned int ui=0;ui<s.size();ui++)
+	{
+		if(isascii(s[ui]) && islower(s[ui]))
+			s[ui] = toupper(s[ui]);
+	}
+	return s;
+}
+
 //Split strings around a delimiter
 void splitStrsRef(const char *cpStr, const char delim,std::vector<string> &v )
 {
diff --git a/src/common/stringFuncs.h b/src/common/stringFuncs.h
index 9d48c35..878a5df 100644
--- a/src/common/stringFuncs.h
+++ b/src/common/stringFuncs.h
@@ -34,6 +34,10 @@ std::string boolStrEnc(bool b);
 //	Whitespace is stripped from either end. If string cannot be understood, returns false
 bool boolStrDec(const std::string &s,bool &result);
 
+void ucharToHexStr(unsigned char c, std::string &s);
+
+void hexStrToUChar(const std::string &s, unsigned char &c);
+//TODO : Eliminate this function.
 //!Generate string that can be parsed by wxPropertyGrid for combo control
 //String format is CHOICEID:id1|string 1,id2|string 2,id3|string 3,.....,idN|string_N
 // where id1->idN are integers
@@ -61,22 +65,12 @@ std::string stripWhite(const std::string &str);
 std::string stripChars(const std::string &Str, const char *chars);
 //!Return a lowercase version for a given string
 std::string lowercase(std::string s);
+//!Return a uppercase version for a given string
+std::string uppercase(std::string s);
 
 //Drop empty entries from a string of vector
 void stripZeroEntries(std::vector<std::string> &s);
 
-
-//Parse a colour string, such as #aabbccdd into its RGBA 8-bit components
-bool parseColString(const std::string &str,
-	unsigned char &r, unsigned char &g, unsigned char &b, unsigned char &a);
-
-//Convert an RGBA 8-bit/channel quadruplet into its hexadecimal colour string
-void genColString(unsigned char r, unsigned char g, 
-			unsigned char b, unsigned char a, std::string &s);
-//Convert an RGB 8-bit/channel quadruplet into its hexadecimal colour string
-void genColString(unsigned char r, unsigned char g, 
-			unsigned char b, std::string &s);
-
 //Check to see if a given string is a valid version number string,
 // consisting of decmials and ints (eg 0.1.2.3.4)
 bool isVersionNumberString(const std::string &s);
diff --git a/src/common/translation.h b/src/common/translation.h
index 1a7eea7..8593603 100644
--- a/src/common/translation.h
+++ b/src/common/translation.h
@@ -32,9 +32,4 @@
 //!Gettext null-translation macro (mark for translation, but do nothing)
 #define NTRANS(x) (x)
 
-//!Wx friendly gettext translation macro
-#define wxTRANS(x) (wxString(gettext(x),*wxConvCurrent))
-
-#define wxNTRANS(x) wxT(x)
-
 #endif
diff --git a/src/gl/cameras.cpp b/src/gl/cameras.cpp
index aac6789..7d368d7 100644
--- a/src/gl/cameras.cpp
+++ b/src/gl/cameras.cpp
@@ -587,71 +587,70 @@ void CameraLookAt::move(float moveLRAngle, float moveUDAngle)
 
 void CameraLookAt::getProperties(CameraProperties &p) const
 {
-	p.data.clear();
-	p.types.clear();
-	p.keys.clear();
-
-	std::vector<std::pair<string,string> > s;
-	std::vector<unsigned int> type,keys;
-
-	if(lock)
-		s.push_back(std::make_pair(TRANS("Lock"),"1"));
-	else
-		s.push_back(std::make_pair(TRANS("Lock"),"0"));
-
-	type.push_back(PROPERTY_TYPE_BOOL);
-	keys.push_back(CAMERA_KEY_LOOKAT_LOCK);
-
-	string ptStr;
-	stream_cast(ptStr,origin);
-	s.push_back(std::make_pair(TRANS("Origin"), ptStr));
-	type.push_back(PROPERTY_TYPE_POINT3D);
-	keys.push_back(CAMERA_KEY_LOOKAT_ORIGIN);
-	
-	stream_cast(ptStr,target);
-	s.push_back(std::make_pair(TRANS("Target"), ptStr));
-	type.push_back(PROPERTY_TYPE_POINT3D);
-	keys.push_back(CAMERA_KEY_LOOKAT_TARGET);
-	
-	stream_cast(ptStr,upDirection);
-	s.push_back(std::make_pair(TRANS("Up Dir."), ptStr));
-	type.push_back(PROPERTY_TYPE_POINT3D);
-	keys.push_back(CAMERA_KEY_LOOKAT_UPDIRECTION);
-
+	p.clear();
+
+	CameraProperty cp;
+
+	p.addGroup();
+
+	cp.name=TRANS("Lock");
+	cp.data=boolStrEnc(lock);
+	cp.type=PROPERTY_TYPE_BOOL;
+	cp.key=CAMERA_KEY_LOOKAT_LOCK;
+	p.addEntry(cp);
+
+	//Add origin
+	cp.name=TRANS("Origin"); 
+	stream_cast(cp.data,origin);
+	cp.type=PROPERTY_TYPE_POINT3D;
+	cp.key=CAMERA_KEY_LOOKAT_ORIGIN;
+	p.addEntry(cp);
+
+	//Add camea target pt
+	stream_cast(cp.data,target);
+	cp.name=TRANS("Target");
+	cp.type=PROPERTY_TYPE_POINT3D;
+	cp.key=CAMERA_KEY_LOOKAT_TARGET;
+	p.addEntry(cp);
+
+	stream_cast(cp.data,upDirection);
+	cp.name=TRANS("Up Dir.");
+	cp.type=PROPERTY_TYPE_POINT3D;
+	cp.key=CAMERA_KEY_LOOKAT_UPDIRECTION;
+	p.addEntry(cp);
+
+	//add camera projection options
 	std::vector<std::pair<unsigned int,string> > choices;
 	string tmp;
-	
-
 	tmp=TRANS("Perspective");
 	choices.push_back(make_pair((unsigned int)PROJECTION_MODE_PERSPECTIVE,tmp));
 	tmp=TRANS("Orthogonal");
 	choices.push_back(make_pair((unsigned int)PROJECTION_MODE_ORTHOGONAL,tmp));
-	tmp= choiceString(choices,projectionMode);
 	
-	s.push_back(std::make_pair(TRANS("Projection"), tmp));
-	type.push_back(PROPERTY_TYPE_CHOICE);
-	keys.push_back(CAMERA_KEY_LOOKAT_PROJECTIONMODE);
+	cp.data=choiceString(choices,projectionMode);
+	cp.name=TRANS("Projection");
+	cp.type=PROPERTY_TYPE_CHOICE;
+	cp.key=CAMERA_KEY_LOOKAT_PROJECTIONMODE;
+	p.addEntry(cp);
 
 	switch(projectionMode)
 	{
 		case PROJECTION_MODE_PERSPECTIVE:
-			stream_cast(tmp,fovAngle);
-			s.push_back(std::make_pair(TRANS("Field of View (deg)"), tmp));
-			type.push_back(PROPERTY_TYPE_REAL);
-			keys.push_back(CAMERA_KEY_LOOKAT_FOV);
+			stream_cast(cp.data,fovAngle);
+			cp.name=TRANS("Field of View (deg)");
+			cp.type=PROPERTY_TYPE_REAL;
+			cp.key=CAMERA_KEY_LOOKAT_FOV;
 			break;
 		case PROJECTION_MODE_ORTHOGONAL:
-			stream_cast(tmp,orthoScale);
-			s.push_back(std::make_pair(TRANS("View size"), tmp));
-			type.push_back(PROPERTY_TYPE_REAL);
-			keys.push_back(CAMERA_KEY_LOOKAT_ORTHOSCALE);
+			stream_cast(cp.data,orthoScale);
+			cp.name=TRANS("View size");
+			cp.type=PROPERTY_TYPE_REAL;
+			cp.key=CAMERA_KEY_LOOKAT_ORTHOSCALE;
 			break;
-
+		default:
+			ASSERT(false);
 	}
-
-	p.data.push_back(s);
-	p.keys.push_back(keys);
-	p.types.push_back(type);
+	p.addEntry(cp);
 }
 
 bool CameraLookAt::setProperty(unsigned int key, const string &value)
diff --git a/src/gl/cameras.h b/src/gl/cameras.h
index 1158fce..6dd25c8 100644
--- a/src/gl/cameras.h
+++ b/src/gl/cameras.h
@@ -56,19 +56,27 @@ enum
 	CAMERA_KEY_LOOKAT_ORTHOSCALE
 };
 
+class CameraProperty
+{
+	public:
+		unsigned int type;
+		unsigned int key;
+		std::string data;
+		std::string name;
+};
+
 class CameraProperties 
 {
 	public:
-		//Filter property data, one per output, each is value then name
-		std::vector<std::vector<std::pair< std::string, std::string > > > data;
-		//Data types for each single element
-		std::vector<std::vector<unsigned int>  > types;
-		
-		//!Key numbers for filter. Must be unique per set
-		std::vector<std::vector<unsigned int> > keys;
-	
+		std::vector<std::vector<CameraProperty>  > props;
+		void clear() { props.clear();};	
+		void addGroup() {props.resize(props.size()+1);}
+		void addEntry(CameraProperty &p) { ASSERT(props.size()); props.back().push_back(p);}
 };
 
+
+
+
 //!An abstract base class for a camera
 class Camera
 {
diff --git a/src/gl/drawables.cpp b/src/gl/drawables.cpp
index b5bc147..543c98f 100644
--- a/src/gl/drawables.cpp
+++ b/src/gl/drawables.cpp
@@ -38,11 +38,13 @@ float DrawableObj::backgroundG;
 float DrawableObj::backgroundB;
 
 bool DrawableObj::useAlphaBlend;
-TexturePool *DrawableObj::texPool;
+TexturePool *DrawableObj::texPool=0;
 
 unsigned int DrawableObj::winX;
 unsigned int DrawableObj::winY;
 
+DrawTexturedQuad DrawPointLegendOverlay::dQuad;
+bool DrawPointLegendOverlay::quadSet=false;
 //==
 
 
@@ -229,6 +231,36 @@ DrawableObj::DrawableObj() : active(true), haveChanged(true), canSelect(false),
 DrawableObj::~DrawableObj()
 {
 }
+	
+	
+float DrawableObj::getHighContrastValue() const
+{
+	//Perform luminence check on background to try to create most appropriate
+	// colour
+	//-------
+	// TODO: I have this in a few places now, need to refactor into a single colour class
+
+	//weights
+ 	const float CHANNEL_LUM_WEIGHTS[3] = { 0.299f,0.587f,0.114f};
+	float totalBright=backgroundR*CHANNEL_LUM_WEIGHTS[0] +
+			backgroundG*CHANNEL_LUM_WEIGHTS[1] +
+			backgroundB*CHANNEL_LUM_WEIGHTS[2];
+
+	float contrastCol;
+	if(totalBright > 0.5f)
+	{
+		//"bright" scene, use black text
+		contrastCol=0.0f;
+	}
+	else
+	{
+		//"Dark" background, use white text
+		contrastCol=1.0f;
+	}
+
+	return contrastCol;
+
+}
 
 void DrawableObj::explode(std::vector<DrawableObj *> &simpleObjects)
 {
@@ -248,7 +280,7 @@ void DrawableObj::clearTexPool()
 {
 	ASSERT(texPool);
 	delete texPool;
-
+	texPool=0;
 }
 
 Point3D DrawableObj::getCentroid() const
@@ -508,6 +540,12 @@ void DrawQuad::setVertices(const Point3D *v)
 		vertices[ui]=v[ui];
 }
 
+void DrawQuad::setVertex(unsigned int v, const Point3D &p)
+{
+	ASSERT(v <4);
+	vertices[v] = p;
+}
+
 Point3D DrawQuad::getOrigin() const
 {
 	return Point3D::centroid(vertices,4);
@@ -537,16 +575,24 @@ void DrawQuad::recomputeParams(const vector<Point3D> &vecs,
 	}
 }
 
-DrawTexturedQuad::DrawTexturedQuad() :textureData(0), textureId((unsigned int)-1)
+DrawTexturedQuad::DrawTexturedQuad() :textureData(0), textureId((unsigned int)-1), noColour(false)
 {
 }
 
-DrawTexturedQuad::~DrawTexturedQuad()
+DrawTexturedQuad::DrawTexturedQuad(const DrawTexturedQuad &oth)
 {
-	if(textureData)
-		delete[] textureData;
+	ASSERT(false);
+}
 
-	texPool->closeTexture(textureId);
+DrawTexturedQuad::~DrawTexturedQuad()
+{
+	//hack to work around static construct/destruct.
+	// normally we use the texture pool do to everything
+	if(texPool && textureId != -1)
+	{
+		texPool->closeTexture(textureId);
+		textureId=-1;
+	}
 }
 
 void DrawTexturedQuad::draw() const
@@ -554,14 +600,15 @@ void DrawTexturedQuad::draw() const
 	ASSERT(glIsTexture(textureId));
 	
 	glEnable(GL_TEXTURE_2D);
-	glBindTexture(GL_TEXTURE_2D,textureId);
 	glPushAttrib(GL_CULL_FACE);
 	glDisable(GL_CULL_FACE);
 	
 	
 	glBindTexture(GL_TEXTURE_2D,textureId);
 
-	glColor4f(1.0f,1.0f,1.0f,1.0f);
+	if(!noColour)
+		glColor4f(1.0f,1.0f,1.0f,1.0f);
+	
 	const float COORD_SEQ_X[]={ 0,0,1,1};
 	const float COORD_SEQ_Y[]={ 0,1,1,0};
 	glBegin(GL_QUADS);
@@ -601,23 +648,25 @@ void DrawTexturedQuad::resize(size_t numX, size_t numY,
 
 }
 
-void DrawTexturedQuad::rebindTexture()
+void DrawTexturedQuad::rebindTexture(unsigned int mode)
 {
 	ASSERT(texPool);
 	ASSERT(textureData);
 	if(textureId == (unsigned int)-1)
 		texPool->genTexID(textureId);
-	
-	//Construc the texture
+
+	ASSERT(!(mode == GL_RGB && channels !=3 ));
+	ASSERT(!(mode == GL_RGBA && channels !=4 ));
+
+	//Construct the texture
 	glBindTexture(GL_TEXTURE_2D,textureId);
 	glPixelStorei(GL_UNPACK_ALIGNMENT,1);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
 	glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); 
-	ASSERT(channels == 3);
 
-	glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,nX,nY,
-		0,GL_RGB,GL_UNSIGNED_BYTE,textureData);
+	glTexImage2D(GL_TEXTURE_2D,0,mode,nX,nY,
+		0,mode,GL_UNSIGNED_BYTE,textureData);
 
 
 
@@ -626,7 +675,7 @@ void DrawTexturedQuad::rebindTexture()
 void DrawTexturedQuad::setData(size_t x, size_t y, unsigned char *entry)
 {
 	ASSERT(textureData);
-	ASSERT(channels == 3);
+	ASSERT(x < nX && y < nY);
 
 	for(size_t ui=0;ui<channels;ui++)
 		textureData[(y*nX + x)*channels + ui] = entry[ui]; 	
@@ -1232,7 +1281,6 @@ void DrawGLText::draw() const
 			axis.fz=rotateAxis[2];
 
 
-//			cerr << "Gl rotate (1):" << rotateAxis << " , " << angle << endl;
 			glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]);
 			quat_rot(&tmp,&axis,angle); //angle is in radiians
 
@@ -1250,7 +1298,6 @@ void DrawGLText::draw() const
 			rotateAxis = newUp.crossProd(Point3D(0,-1,0));
 			rotateAxis.normalise();
 			glRotatef(angle*180.0f/M_PI,rotateAxis[0],rotateAxis[1],rotateAxis[2]);
-			//cerr << "Gl rotate (2):" << rotateAxis << " , " << angle << endl;
 		}
 
 		//Ensure that the text is not back-culled (i.e. if the
@@ -1640,28 +1687,31 @@ void DrawRectPrism::recomputeParams(const vector<Point3D> &vecs,
 	}
 }
 
-DrawTexturedQuadOverlay::DrawTexturedQuadOverlay()  
+DrawableOverlay::~DrawableOverlay()
 {
 }
 
-DrawTexturedQuadOverlay::~DrawTexturedQuadOverlay()
+DrawTexturedQuadOverlay::DrawTexturedQuadOverlay()  
+:  textureId(-1),textureOK(false)
 {
-	texPool->closeTexture(textureId);
 }
 
-void DrawTexturedQuadOverlay::setSize(float s)
+DrawTexturedQuadOverlay::~DrawTexturedQuadOverlay()
 {
-	length=s;
+	texPool->closeTexture(textureId);
 }
 
-
 void DrawTexturedQuadOverlay::draw() const
 {
 	if(!textureOK)
 		return;
 
+	ASSERT(height == width);
+
 	ASSERT(glIsTexture(textureId));
 	
+	//TODO: Is this redundant? might be already handled
+	// by scene?
 	glMatrixMode(GL_PROJECTION);	
 	glPushMatrix();
 	glLoadIdentity();
@@ -1679,13 +1729,13 @@ void DrawTexturedQuadOverlay::draw() const
 	glColor3f(1.0f,1.0f,1.0f);
 	glBegin(GL_QUADS);
 		glTexCoord2f(0.0f,0.0f);
-		glVertex3f(position[0]-length/2.0,position[1]-length/2.0,0.0);
+		glVertex3f(position[0]-height/2.0,position[1]-height/2.0,0.0);
 		glTexCoord2f(0.0f,1.0f);
-		glVertex3f(position[0]-length/2.0,position[1]+length/2.0,0.0);
+		glVertex3f(position[0]-height/2.0,position[1]+height/2.0,0.0);
 		glTexCoord2f(1.0f,1.0f);
-		glVertex3f(position[0]+length/2.0,position[1]+length/2.0,0.0);
+		glVertex3f(position[0]+height/2.0,position[1]+height/2.0,0.0);
 		glTexCoord2f(1.0f,0.0f);
-		glVertex3f(position[0]+length/2.0,position[1]-length/2.0,0.0);
+		glVertex3f(position[0]+height/2.0,position[1]-height/2.0,0.0);
 	glEnd();
 
 	glDisable(GL_TEXTURE_2D);	
@@ -1707,11 +1757,6 @@ bool DrawTexturedQuadOverlay::setTexture(const char *textureFile)
 	return textureOK;
 }
 
-void DrawTexturedQuadOverlay::getBoundingBox(BoundCube &b) const
-{
-	b.setInvalid();
-}
-
 DrawAnimatedOverlay::DrawAnimatedOverlay()
 {
 	fadeIn=0.0f;
@@ -1738,12 +1783,6 @@ bool DrawAnimatedOverlay::setTexture(const vector<string> &texFiles,
 	return textureOK;
 }
 
-void DrawAnimatedOverlay::setSize(float newLen)
-{
-	length=newLen;
-}
-
-
 void DrawAnimatedOverlay::draw() const
 {
 	if(!textureOK)
@@ -1784,16 +1823,18 @@ void DrawAnimatedOverlay::draw() const
 	glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MULT); 
 	
 	// Draw overlay quad 
+	ASSERT(width == height); // width/height should be the same
 	glColor4f(1.0f,1.0f,1.0f,alphaVal);
+
 	glBegin(GL_QUADS);
 		glTexCoord3f(0.0f,0.0f,texCoordZ);
-		glVertex3f(position[0]-length/2.0,position[1]-length/2.0,0.0);
+		glVertex3f(position[0]-width/2.0,position[1]-width/2.0,0.0);
 		glTexCoord3f(0.0f,1.0f,texCoordZ);
-		glVertex3f(position[0]-length/2.0,position[1]+length/2.0,0.0);
+		glVertex3f(position[0]-width/2.0,position[1]+width/2.0,0.0);
 		glTexCoord3f(1.0f,1.0f,texCoordZ);
-		glVertex3f(position[0]+length/2.0,position[1]+length/2.0,0.0);
+		glVertex3f(position[0]+width/2.0,position[1]+width/2.0,0.0);
 		glTexCoord3f(1.0f,0.0f,texCoordZ);
-		glVertex3f(position[0]+length/2.0,position[1]-length/2.0,0.0);
+		glVertex3f(position[0]+width/2.0,position[1]-width/2.0,0.0);
 	glEnd();
 
 	glDisable(GL_TEXTURE_3D);	
@@ -1806,10 +1847,7 @@ void DrawAnimatedOverlay::draw() const
 	glMatrixMode(GL_MODELVIEW);
 }
 
-void DrawAnimatedOverlay::getBoundingBox(BoundCube &b) const
-{
-	b.setInvalid();
-}
+
 
 DrawColourBarOverlay::DrawColourBarOverlay() 
 {
@@ -1834,8 +1872,8 @@ DrawColourBarOverlay::DrawColourBarOverlay(const DrawColourBarOverlay &oth)
 	height=oth.height;
 	width=oth.width;
 	
-	tlX=oth.tlX;
-	tlY=oth.tlY;
+	position[0]=oth.position[0];
+	position[1]=oth.position[1];
 };
 
 void DrawColourBarOverlay::draw() const
@@ -1851,52 +1889,30 @@ void DrawColourBarOverlay::draw() const
 		//Set the quad colour for bar element
 		glColor4f(rgb[rgb.size()-(ui+1)].v[0],
 				rgb[rgb.size()-(ui+1)].v[1],
-				rgb[rgb.size()-(ui+1)].v[2],1.0);
+				rgb[rgb.size()-(ui+1)].v[2],a);
 
 		//draw this quad (bar element)
-		glVertex3f(tlX,tlY+(float)ui*elemHeight,0);
-		glVertex3f(tlX,tlY+(float)(ui+1)*elemHeight,0);
-		glVertex3f(tlX+barWidth,tlY+(float)(ui+1)*elemHeight,0);
-		glVertex3f(tlX+barWidth,tlY+(float)(ui)*elemHeight,0);
+		glVertex2f(position[0],position[1]+(float)ui*elemHeight);
+		glVertex2f(position[0],position[1]+(float)(ui+1)*elemHeight);
+		glVertex2f(position[0]+barWidth,position[1]+(float)(ui+1)*elemHeight);
+		glVertex2f(position[0]+barWidth,position[1]+(float)(ui)*elemHeight);
 	}
 
 	glEnd();
 
-	//Perform luminence check on background to try to create most appropriate
-	// colour
-	//-------
-	// TODO: I have this in a few places now, need to refactor into a single colour class
-
-	//weights
- 	const float CHANNEL_LUM_WEIGHTS[3] = { 0.299f,0.587f,0.114f};
-	float totalBright=backgroundR*CHANNEL_LUM_WEIGHTS[0] +
-			backgroundG*CHANNEL_LUM_WEIGHTS[1] +
-			backgroundB*CHANNEL_LUM_WEIGHTS[2];
-
-	float textGrey;
-	if(totalBright > 0.5f)
-	{
-		//"bright" scene, use black text
-		textGrey=0.0f;
-	}
-	else
-	{
-		//"Dark" background, use white text
-		textGrey=1.0f;
-	}
-	
 
 	//-------
 
+	float textGrey=getHighContrastValue();
 	//Draw ticks on colour bar
 	glBegin(GL_LINES);
-		glColor4f(textGrey,textGrey,textGrey,1.0f);
+		glColor4f(textGrey,textGrey,textGrey,a);
 		//Top tick
-		glVertex3f(tlX,tlY,0);
-		glVertex3f(tlX+width,tlY,0);
+		glVertex2f(position[0],position[1]);
+		glVertex2f(position[0]+width,position[1]);
 		//Bottom tick
-		glVertex3f(tlX,tlY+height,0);
-		glVertex3f(tlX+width,tlY+height,0);
+		glVertex2f(position[0],position[1]+height);
+		glVertex2f(position[0]+width,position[1]+height);
 	glEnd();
 
 
@@ -1922,7 +1938,7 @@ void DrawColourBarOverlay::draw() const
 	font->FaceSize(3);
 	glDisable(GL_CULL_FACE);
 	glPushMatrix();
-	glTranslatef(tlX+width,tlY,0);
+	glTranslatef(position[0]+width,position[1],0);
 	string s;
 	stream_cast(s,max);
 	//Note negative sign to flip from y-down screen (opengl) to text dir
@@ -1933,7 +1949,7 @@ void DrawColourBarOverlay::draw() const
 	glPopMatrix();
 
 	glPushMatrix();
-	glTranslatef(tlX+width,tlY+height,0);
+	glTranslatef(position[0]+width,position[1]+height,0);
 	stream_cast(s,min);
 	//Note negative sign to flip from y-down screen (opengl) to text dir
 	//(y up)
@@ -1962,9 +1978,154 @@ void DrawColourBarOverlay::setColourVec(const vector<float> &r,
 
 }
 
-void DrawColourBarOverlay::getBoundingBox(BoundCube &b) const
+DrawPointLegendOverlay::DrawPointLegendOverlay() : enabled(true)
 {
-	b.setInvalid();
+	a=1.0f;
+
+	std::string tmpStr =getDefaultFontFile();
+	font = new FTGLPolygonFont(tmpStr.c_str());
+
+	//check to see if we need to init the texture quad
+	if(!quadSet &&  texPool)
+	{
+
+		dQuad.setUseColouring(false);
+
+		//Create a ciruclar texture
+		const unsigned int N_CHANNELS=4;
+		unsigned int LEG_TEX_SIZE = 256; 
+		unsigned char colourWhite[N_CHANNELS]= { 255,255,255,255 };
+		unsigned char colourBlack[N_CHANNELS]= { 0,0,0,0 };
+
+		//TODO: Convert to single channel texture, to save space?
+		// DrawQuad does not support single channel at this time
+		dQuad.resize(LEG_TEX_SIZE,LEG_TEX_SIZE,N_CHANNELS);
+		const float HALF_CIRCLE_R2 = 0.25; 
+		#pragma omp parallel for
+		for(unsigned int nX=0;nX<LEG_TEX_SIZE;nX++)
+		{
+			float fx;
+			fx= (float) nX/(float)LEG_TEX_SIZE - 0.5;
+			for(unsigned int nY=0;nY<LEG_TEX_SIZE;nY++)
+			{
+				float fy;
+				fy = (float) nY/(float)LEG_TEX_SIZE -0.5;
+				if( fx*fx + fy*fy < HALF_CIRCLE_R2) 
+					dQuad.setData(nX,nY,colourWhite);
+				else
+					dQuad.setData(nX,nY,colourBlack);
+			}
+
+		}
+
+		dQuad.rebindTexture(GL_RGBA);
+
+		quadSet=true;
+
+	}
+}
+
+DrawPointLegendOverlay::~DrawPointLegendOverlay()
+{
+}
+
+DrawableObj *DrawPointLegendOverlay::clone() const
+{
+	DrawPointLegendOverlay *dp = new DrawPointLegendOverlay(*this);
+
+	return dp;
+}
+
+DrawPointLegendOverlay::DrawPointLegendOverlay(const DrawPointLegendOverlay &oth)
+{
+	string f;
+	f=getDefaultFontFile();
+	
+	font = new FTGLPolygonFont(f.c_str());
+	a=oth.a;
+	legendItems = oth.legendItems;
+	enabled = oth.enabled;
+
+	height=oth.height;
+	width=oth.width;
+	
+	position[0]=oth.position[0];
+	position[1]=oth.position[1];
+	quadSet=oth.quadSet;
+}
+
+void DrawPointLegendOverlay::draw() const
+{
+
+	if(!enabled || legendItems.empty())
+		return;
+
+	ASSERT(winX >0 && winY > 0);
+	float curX = position[0];
+	float curY = position[1];
+
+	float delta = std::max(std::min(1.0f/legendItems.size(),0.02f),0.05f);
+	float size = delta*0.9f; 
+	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+
+	float maxTextWidth=0;
+
+	
+	font->FaceSize(1);
+	for(unsigned int ui=0; ui<legendItems.size();ui++)
+	{
+		for(;ui<legendItems.size();ui++)
+		{
+
+			//Draw textured quad (circle)
+			//--
+			dQuad.setVertex(0,Point3D(curX,curY,0));
+			dQuad.setVertex(1,Point3D(curX+size,curY,0));
+			dQuad.setVertex(2,Point3D(curX+size,curY+size,0));
+			dQuad.setVertex(3,Point3D(curX,curY+size,0));
+
+			const RGBFloat *f;
+			f = &legendItems[ui].second;
+			glColor3f(f->v[0],f->v[1],f->v[2]);
+			dQuad.draw();
+
+
+			//--
+
+			//Draw text, if possible
+			if( font && !font->Error())
+			{
+				float textGrey=getHighContrastValue();
+				glColor3f(textGrey,textGrey,textGrey);
+				float fminX,fminY,fminZ;
+				float fmaxX,fmaxY,fmaxZ;
+				font->BBox(legendItems[ui].first.c_str(),fminX,
+						fminY,fminZ,fmaxX,fmaxY,fmaxZ);
+				glPushMatrix();
+				glTranslatef(curX+1.5*size,curY+0.85*size,0.0f);
+				glScalef(size,-size,0);
+				font->Render(legendItems[ui].first.c_str());
+				glPopMatrix();
+				maxTextWidth=std::max(fmaxX-fminX,maxTextWidth);
+			}
+			
+			
+			curY+=delta;
+		}
+
+		curX+=maxTextWidth + size;
+		curY=position[1] + 0.5*delta;
+	}
+	glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+}
+
+void DrawPointLegendOverlay::addItem(const std::string &s, float r, float g, float b)
+{
+	RGBFloat rgb;
+	rgb.v[0]=r;
+	rgb.v[1]= g;
+	rgb.v[2]= b;
+	legendItems.push_back(make_pair(s,rgb));
 }
 
 
@@ -2132,7 +2293,6 @@ void DrawField3D::draw() const
 		drawBox(field->getMinBounds(),field->getMaxBounds(),
 			boxColourR, boxColourG,boxColourB,alphaUse);
 	}
-	//Draw the projections
 }
 
 void DrawField3D::setAlpha(float newAlpha)
diff --git a/src/gl/drawables.h b/src/gl/drawables.h
index aad4671..9d0e1de 100644
--- a/src/gl/drawables.h
+++ b/src/gl/drawables.h
@@ -19,9 +19,6 @@
 #ifndef DRAWABLES_H
 #define DRAWABLES_H
 
-#include "textures.h"
-#include "cameras.h"
-#include "isoSurface.h"
 
 //STL includes
 
@@ -37,6 +34,10 @@
 
 #include <sys/time.h>
 
+#include "textures.h"
+#include "cameras.h"
+#include "isoSurface.h"
+
 //TODO: Work out if there is any way of obtaining the maximum 
 //number of items that can be drawn in an opengl context
 //For now Max it out at 10 million (~120MB of vertex data)
@@ -102,6 +103,7 @@ enum
 	DRAW_TYPE_FIELD3D,
 	DRAW_TYPE_ISOSURFACE,
 	DRAW_TYPE_AXIS,
+	DRAW_TYPE_LEGENDOVERLAY,
 };
 
 //TODO: It seems unnecessary to have multiple types for the bind
@@ -151,7 +153,10 @@ class DrawableObj
 
 		static bool useAlphaBlend;
 	
+		//Size of the opengl window
 		static unsigned int winX,winY;
+
+		float getHighContrastValue() const;
 	public: 
 		//!Can be selected from openGL viewport interactively?
 		bool canSelect;
@@ -462,6 +467,7 @@ class DrawQuad : public DrawableObj
 
 class DrawTexturedQuad : public DrawQuad
 {
+	private:
 	//TODO: Move this back
 	// into the texture pool
 		unsigned char *textureData;
@@ -473,9 +479,16 @@ class DrawTexturedQuad : public DrawQuad
 		// to opengl
 		unsigned int textureId;
 		
+		//!FTGL font instance
+		FTFont *font;
+		
+		//disallow resetting base colour to white 
+		bool noColour;
+		
 	public:
 		DrawTexturedQuad();
 		~DrawTexturedQuad();
+		DrawTexturedQuad(const DrawTexturedQuad &d);
 
 		//Resize the texture contents, destroying any existing contents
 		void resize(size_t nx, size_t nY, unsigned int nChannels);
@@ -484,81 +497,12 @@ class DrawTexturedQuad : public DrawQuad
 		//Set the specified pixel in the texture to this value 
 		void setData(size_t x, size_t y, unsigned char *entry);
 		//Send the texture to the video card. 
-		void rebindTexture();	
-};
-
-
-class DrawAnimatedOverlay : public DrawQuad
-{
-	private:
-		size_t nX,nY,nZ;
-
-		//ID of the texture to use when drawing, -1 if not bound
-		// to opengl
-		unsigned int textureId;
-
-		float position[2];
-
-		timeval animStartTime;
-
-		bool textureOK;
-
-		//Time delta before repeating animation
-		float repeatInterval;
+		void rebindTexture(unsigned int mode=GL_RGB);	
 		
-		//Length to use for the quad to represent icon
-		float length;
-
-		//Time before showing the image
-		float delayBeforeShow;
-
-		//Time for fadein after show
-		float fadeIn;
-
-	public:
-		DrawAnimatedOverlay();
-		~DrawAnimatedOverlay();
-
-		virtual unsigned int getType() const {return DRAW_TYPE_ANIMATEDOVERLAY;}
-
-		//!This is an overlay
-		bool isOverlay() const {return true;};
-
-
-		//!Set the texture position in XY (z is ignored)
-		void setPos(float xp,float yp)
-		{
-			position[0]=xp;
-			position[1]=yp;
-		};
-
-		void setSize(float size);
-
-		//Set the time between repeats for the animation
-		void setRepeatTime(float timeV) { repeatInterval=timeV;}
-
-		//Set the time before the texture appears
-		void setShowDelayTime(float showDelayTime) 
-			{ ASSERT(showDelayTime >=0.0f);  delayBeforeShow = showDelayTime;}
-
-		//Set the time during which the alpha value will be ramped up.
-		// activated after the delay time (ie time before 100% visible is fadeInTime + 
-		//	delayTime.
-		void setFadeInTime(float fadeInTime)
-			{ ASSERT(fadeInTime >=0.0f); fadeIn=fadeInTime;}
-
-		//!Set the texture by name
-		bool setTexture(const vector<string> &textureFiles, float timeRepeat=1.0f);
-
-		void resetTime() ;
-
-		//!Draw object
-		void draw() const;
+		void setUseColouring(bool useColouring) {noColour= !useColouring;};
+};
 
-		void getBoundingBox(BoundCube &b) const ;
 
-		bool isOK() const { return textureOK; }
-};
 
 //!A sphere drawing 
 class DrawSphere : public DrawableObj
@@ -909,21 +853,39 @@ struct RGBFloat
 	float v[3];
 };
 
-class DrawColourBarOverlay : public DrawableObj
+//Abstract class as base for overlays
+class DrawableOverlay : public DrawableObj
+{
+	protected:
+		//alpha (transparancy) value
+		float a;
+		//!Height and width of overlay (total)
+		float height,width;
+		//Fractional coordinates for the  top left of the overlay
+		float position[2];
+	public:
+		DrawableOverlay() {} ;
+		//Declared as pure virtual to force ABC
+		virtual ~DrawableOverlay() =0;
+		void setAlpha(float alpha) { a=alpha;};
+		void setSize(float widthN, float heightN) {height=heightN, width=widthN;} 
+		void setSize(float size) {width=height=size;};
+		void setPosition(float newTLX,float newTLY) { position[0]=newTLX; position[1]=newTLY;}
+
+		void getBoundingBox(BoundCube &b) const {b.setInvalid();};
+		//!This is an overlay
+		bool isOverlay() const {return true;};
+};
+
+class DrawColourBarOverlay : public DrawableOverlay
 {
 	private:
 		FTFont *font;
 
 		//!Colours for each element
 		vector<RGBFloat> rgb;
-		//alpha (transparancy) value
-		float a;
 		//!Minimum and maximum values for the colour bar (for ticks)
 		float min,max;
-		//!Height and width of bar (total)
-		float height,width;
-		//!top left of bar
-		float tlX,tlY;
 
 	public:
 	
@@ -933,63 +895,114 @@ class DrawColourBarOverlay : public DrawableObj
 		
 
 		virtual unsigned int getType() const {return DRAW_TYPE_COLOURBAR;}
-		
-	
-		void getBoundingBox(BoundCube &b) const ;
 
-		//!This is an overlay
-		bool isOverlay() const {return true;};
 		void setColourVec(const vector<float> &r,
 					const vector<float> &g,
 					const vector<float> &b);
 		//!Draw object
 		void draw() const;
 
-		void setAlpha(float alpha) { a=alpha;};
-		void setSize(float widthN, float heightN) {height=heightN, width=widthN;} 
-		void setPosition(float newTLX,float newTLY) { tlX=newTLX; tlY=newTLY;}
 		void setMinMax(float minNew,float maxNew) { min=minNew;max=maxNew;};
 		
 };
 
 //!A class to hande textures to draw
-class DrawTexturedQuadOverlay : public DrawableObj
+class DrawTexturedQuadOverlay : public DrawableOverlay
 {
 	private:
 		unsigned int textureId;
-		//Fractional coordinates for the 
-		float position[2];
 	
-		//Length of the rectangle to use for the icon
-		float length;
-
 		bool textureOK;
+
 	public:
 		DrawTexturedQuadOverlay();
 		~DrawTexturedQuadOverlay();
-		
-		virtual unsigned int getType() const {return DRAW_TYPE_TEXTUREDOVERLAY;}
 
-		//!This is an overlay
-		bool isOverlay() const {return true;};
+		virtual unsigned int getType() const {return DRAW_TYPE_TEXTUREDOVERLAY;}
 	
 		static void setWindowSize(unsigned int x, unsigned int y){winX=x;winY=y;};	
+		//!Set the texture by name
+		bool setTexture(const char *textureFile);
+		//!Draw object
+		void draw() const;
+};
+
+
+//!Multi-frame texture - Animated overlay
+class DrawAnimatedOverlay : public DrawableOverlay
+{
+	private:
+		//ID of the texture to use when drawing, -1 if not bound
+		// to opengl
+		unsigned int textureId;
+
+		timeval animStartTime;
+
+		bool textureOK;
 
-		//!Set the texture position in XY (z is ignored)
-		void setPos(float xp,float yp){position[0]=xp; position[1]=yp;};
+		//Time delta before repeating animation
+		float repeatInterval;
+		
+		//Time before showing the image
+		float delayBeforeShow;
 
-		void setSize(float size);
+		//Time for fadein after show
+		float fadeIn;
+
+	public:
+		DrawAnimatedOverlay();
+		~DrawAnimatedOverlay();
+
+		virtual unsigned int getType() const {return DRAW_TYPE_ANIMATEDOVERLAY;}
+
+		//Set the time between repeats for the animation
+		void setRepeatTime(float timeV) { repeatInterval=timeV;}
+
+		//Set the time before the texture appears
+		void setShowDelayTime(float showDelayTime) 
+			{ ASSERT(showDelayTime >=0.0f);  delayBeforeShow = showDelayTime;}
+
+		//Set the time during which the alpha value will be ramped up.
+		// activated after the delay time (ie time before 100% visible is fadeInTime + 
+		//	delayTime.
+		void setFadeInTime(float fadeInTime)
+			{ ASSERT(fadeInTime >=0.0f); fadeIn=fadeInTime;}
 
 		//!Set the texture by name
-		bool setTexture(const char *textureFile);
+		bool setTexture(const vector<string> &textureFiles, float timeRepeat=1.0f);
 
+		void resetTime() ;
 
 		//!Draw object
 		void draw() const;
 
-		void getBoundingBox(BoundCube &b) const ;
+		bool isOK() const { return textureOK; }
 };
 
+class DrawPointLegendOverlay : public DrawableOverlay
+{
+	private:
+	static DrawTexturedQuad dQuad;
+	static bool quadSet;
+
+	FTFont *font;
+	//Items to draw n overlay, and colour to use to draw
+	vector<pair<string,RGBFloat> > legendItems;
+	bool enabled;
+	public:
+		DrawPointLegendOverlay();
+		~DrawPointLegendOverlay();
+		
+		DrawPointLegendOverlay(const DrawPointLegendOverlay &);
+
+		DrawableObj *clone() const;
+		virtual unsigned int getType() const {return DRAW_TYPE_LEGENDOVERLAY;}
+		void draw() const;
+
+		void clear(); 
+		void addItem(const string &s, float r, float g, float b);
+
+};
 
 struct RGBThis
 {
diff --git a/src/gl/glDebug.h b/src/gl/glDebug.h
index 5e464c6..e975a62 100644
--- a/src/gl/glDebug.h
+++ b/src/gl/glDebug.h
@@ -1,3 +1,21 @@
+/*
+ *	glDebug.h - opengl debugging routines
+ *	Copyright (C) 2014, D Haley 
+
+ *	This program is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, either version 3 of the License, or
+ *	(at your option) any later version.
+
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
 #ifndef GLDEBUG_H
 #define GLDEBUG_H
 
@@ -19,14 +37,23 @@
 				} \
 		std::cerr << "glErr Clean " << __FILE__ << ":" << __LINE__ << std::endl; \
 }
+
+inline int glCurStackDepth(int stackDepthSelector)
+{
+	ASSERT(stackDepthSelector == GL_MODELVIEW_STACK_DEPTH || 
+		stackDepthSelector == GL_PROJECTION_STACK_DEPTH ||
+		stackDepthSelector == GL_TEXTURE_STACK_DEPTH );
+	int gldepthdebug;
+	glGetIntegerv (stackDepthSelector,&gldepthdebug);
+	return gldepthdebug;
+}
 	
 
 #define glStackDepths() { \
-		int gldepthdebug[3];glGetIntegerv (GL_MODELVIEW_STACK_DEPTH, gldepthdebug);\
-	       	glGetIntegerv (GL_PROJECTION_STACK_DEPTH, gldepthdebug+1);\
-	       	glGetIntegerv (GL_TEXTURE_STACK_DEPTH, gldepthdebug+2);\
-		std::cerr << "OpenGL Stack Depths: ModelV:" << gldepthdebug[0] << " Pr: "\
-		 << gldepthdebug[1] << " Tex:" << gldepthdebug[2] << std::endl;}
+		std::cerr << "OpenGL Stack Depths: ModelV:" \
+		<< glCurStackDepth(GL_MODELVIEW_STACK_DEPTH) << " Pr: "\
+		<< glCurStackDepth(GL_PROJECTION_STACK_DEPTH) << " Tex:" \
+		<< glCurStackDepth(GL_TEXTURE_STACK_DEPTH)  << std::endl;}
 	
 
 inline void glPrintMatrix(int matrixMode )
diff --git a/src/gl/scene.cpp b/src/gl/scene.cpp
index 361394e..e240e7e 100644
--- a/src/gl/scene.cpp
+++ b/src/gl/scene.cpp
@@ -177,6 +177,23 @@ unsigned int Scene::initDraw()
 	return passes;
 }
 
+bool Scene::hasOverlays() const
+{
+	for(unsigned int ui=0;ui<objects.size();ui++)
+	{
+		if(objects[ui]->isOverlay())
+			return true;
+	}
+	
+	for(unsigned int ui=0;ui<refObjects.size();ui++)
+	{
+		if(refObjects[ui]->isOverlay())
+			return true;
+	}
+
+	return false;
+}
+
 void Scene::updateCam(const Camera *camToUse, bool useIdent=true) const
 {
 	Point3D lightNormal;
@@ -189,7 +206,7 @@ void Scene::updateCam(const Camera *camToUse, bool useIdent=true) const
 
 void Scene::updateProgressOverlay()
 {
-	progressAnimTex.setPos(0.9*winX,0.9*winY);
+	progressAnimTex.setPosition(0.9*winX,0.9*winY);
 	progressAnimTex.setSize(0.1*winX);
 	//Cycle every this many seconds
 	progressAnimTex.setRepeatTime(6.0f);
@@ -294,15 +311,20 @@ void Scene::draw(bool noUpdateCam)
 
 
 	glPopMatrix();
-		
-	//Now draw 2D overlays
-	if(!lockInteract&& lastHovered != (unsigned int)(-1) )
-		drawHoverOverlay();
-	drawOverlays();
+	
+	//Only draw 2D components if we
+	// are using normal camera	
+	if(!noUpdateCam)
+	{
+		//Now draw 2D overlays
+		if(!lockInteract&& lastHovered != (unsigned int)(-1) )
+			drawHoverOverlay();
 
-	//Draw progress, if needed
-	drawProgressAnim();
+		drawOverlays(noUpdateCam);
 
+		//Draw progress, if needed
+		drawProgressAnim();
+	}
 }
 
 void Scene::drawObjectVector(const vector<const DrawableObj*> &drawObjs, bool &lightsOn, bool drawOpaques) const
@@ -351,50 +373,84 @@ void Scene::drawObjectVector(const vector<const DrawableObj*> &drawObjs, bool &l
 
 		}
 		
+
+
+#ifdef DEBUG
+		//Ensure that the gl matrix sizes are correctly restored
+		int curDepth[3];
+		int oldMatMode;
+		curDepth[0] = glCurStackDepth(GL_MODELVIEW_STACK_DEPTH);		
+		curDepth[1] = glCurStackDepth(GL_PROJECTION_STACK_DEPTH);		
+		curDepth[2] = glCurStackDepth(GL_TEXTURE_STACK_DEPTH);		
+		glGetIntegerv( GL_MATRIX_MODE, &oldMatMode);
+#endif
 		drawObjs[ui]->draw();
+
+#ifdef DEBUG
+		ASSERT(curDepth[0] == glCurStackDepth(GL_MODELVIEW_STACK_DEPTH));	
+		ASSERT(curDepth[1] == glCurStackDepth(GL_PROJECTION_STACK_DEPTH));	
+		ASSERT(curDepth[2] == glCurStackDepth(GL_TEXTURE_STACK_DEPTH));		
+		ASSERT(curDepth[0] && curDepth[1] && curDepth[2]);
+		int newMatMode;
+		glGetIntegerv( GL_MATRIX_MODE, &newMatMode);
+		ASSERT(oldMatMode == newMatMode);
+#endif
 	}
 }
 
-void Scene::drawOverlays() const
+void Scene::drawOverlays(bool noUpdateCam) const
 {
 
 	//Custom projection matrix
-	glMatrixMode(GL_PROJECTION);
-	glPushMatrix();
-	glLoadIdentity();
-
 	glDisable(GL_LIGHTING);
+	glDisable(GL_DEPTH_TEST);
 	//Set the opengl camera state back into modelview mode
-	gluOrtho2D(0, outWinAspect, 1.0, 0);
-
-
-
-	glMatrixMode(GL_MODELVIEW);
-	glPushMatrix();
-	glLoadIdentity();
+	if(!noUpdateCam)
+	{
+		//clear projection and o modle matricies
+		glMatrixMode(GL_PROJECTION);
+		glPushMatrix();
+		glLoadIdentity();
+		gluOrtho2D(0, outWinAspect, 1.0, 0);
+
+		glMatrixMode(GL_MODELVIEW);
+		glPushMatrix();
+		glLoadIdentity();
+	}
 
-	glDisable(GL_DEPTH_TEST);
 
 
 	for(unsigned int ui=0;ui<refObjects.size();ui++)
 	{
 		if(refObjects[ui]->isOverlay())
+		{
 			refObjects[ui]->draw();
+		}
 	}
 	
 	for(unsigned int ui=0;ui<objects.size();ui++)
 	{
 		if(objects[ui]->isOverlay())
+		{
 			objects[ui]->draw();
+		}
 	}
 	
 
-	glEnable(GL_DEPTH_TEST);
-	glPopMatrix();
-	glMatrixMode(GL_PROJECTION);
-	glPopMatrix();
+	if(!noUpdateCam)
+	{
+		//op our modelview matrix
+		glPopMatrix();
+		
+		//ppop projection atrix
+		glMatrixMode(GL_PROJECTION);
+		glPopMatrix();
+		//return to modelview mode
+		glMatrixMode(GL_MODELVIEW);
+	}
 
-	glMatrixMode(GL_MODELVIEW);
+	glEnable(GL_DEPTH_TEST);
+	glEnable(GL_LIGHTING);
 }
 
 void Scene::drawHoverOverlay()
@@ -504,14 +560,14 @@ void Scene::drawHoverOverlay()
 				if(foundKeyTex)
 				{
 					//Make room for keyTex
-					binderIcons.setPos((0.93+SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum));
-					keyIcons.setPos(0.93*winX,ICON_SIZE*winY*(1+(float)iconNum));
-					mouseIcons.setPos((0.93-SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum));
+					binderIcons.setPosition((0.93+SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum));
+					keyIcons.setPosition(0.93*winX,ICON_SIZE*winY*(1+(float)iconNum));
+					mouseIcons.setPosition((0.93-SPACING)*winX,ICON_SIZE*winY*(1+(float)iconNum));
 				}
 				else
 				{
-					binderIcons.setPos(0.95*winX,ICON_SIZE*winY*(1+(float)iconNum));
-					mouseIcons.setPos(0.90*winX,ICON_SIZE*winY*(1+(float)iconNum));
+					binderIcons.setPosition(0.95*winX,ICON_SIZE*winY*(1+(float)iconNum));
+					mouseIcons.setPosition(0.90*winX,ICON_SIZE*winY*(1+(float)iconNum));
 				}
 
 				binderIcons.draw();
diff --git a/src/gl/scene.h b/src/gl/scene.h
index 2b1783e..2057216 100644
--- a/src/gl/scene.h
+++ b/src/gl/scene.h
@@ -123,8 +123,6 @@ class Scene
 		///!Draw the hover overlays
 		void drawHoverOverlay();
 
-		//!Draw the normal overlays
-		void drawOverlays() const;
 
 		void drawProgressAnim() const;
 
@@ -153,6 +151,8 @@ class Scene
 		//!Draw the objects in the active window. May adjust cameras and compute bounding as needed.
 		void draw(bool noUpdateCam=false);
 
+		//!Draw the normal overlays
+		void drawOverlays(bool noCamUpdate=false) const;
 	
 		//!clear rendering vectors
 		void clearAll();
@@ -162,7 +162,9 @@ class Scene
 		void clearRefObjs();
 		//!Clear object bindings vector
 		void clearBindings();
-	
+
+		//!Do we have overlay items?
+		bool hasOverlays() const;	
 
 		//!Obtain the scene's light coordinates in camera relative space
 		// requires an array os size 4  (xyzw)
diff --git a/src/gl/textures.h b/src/gl/textures.h
index 7e7162a..b89b0db 100644
--- a/src/gl/textures.h
+++ b/src/gl/textures.h
@@ -22,6 +22,15 @@
 
 #include "common/basics.h"
 
+#ifdef CreateDialog
+#undef CreateDialog
+#endif
+
+#ifdef Yield
+#undef Yield
+#endif
+
+
 #ifdef __APPLE__ 
 #include <OpenGL/gl.h>
 #include <OpenGL/glu.h>
diff --git a/src/gl/tr.cpp b/src/gl/tr.cpp
index 79a1c95..f3a8880 100644
--- a/src/gl/tr.cpp
+++ b/src/gl/tr.cpp
@@ -1,7 +1,24 @@
 //Tile Rendering Library, 
 // http://www.mesa3d.org/brianp/TR.html
-// GNU GPL 2+
 
+/*
+	TR Tile rendering library
+	Copyright (C) 1997 Brian Paul
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
 
 /* $Id: tr.c,v 1.9 1998/01/29 16:56:54 brianp Exp $ */
 
@@ -43,11 +60,11 @@
  * Copyright (C) Brian Paul
  */
 
+#include "common/assertion.h"
 
-#include <assert.h>
 #include <math.h>
-#include <stdlib.h>
-#include <stdio.h>
+#include <cstdlib>
+
 #ifdef WIN32
 #include <windows.h>
 #endif
@@ -112,8 +129,8 @@ static void Setup(TRcontext *tr)
    tr->Rows = (tr->ImageHeight + tr->TileHeightNB - 1) / tr->TileHeightNB;
    tr->CurrentTile = 0;
 
-   assert(tr->Columns >= 0);
-   assert(tr->Rows >= 0);
+   ASSERT(tr->Columns >= 0);
+   ASSERT(tr->Rows >= 0);
 }
 
 
@@ -145,11 +162,11 @@ void trTileSize(TRcontext *tr, GLint width, GLint height, GLint border)
    if (!tr)
       return;
 
-   assert(border >= 0);
-   assert(width >= 1);
-   assert(height >= 1);
-   assert(width >= 2*border);
-   assert(height >= 2*border);
+   ASSERT(border >= 0);
+   ASSERT(width >= 1);
+   ASSERT(height >= 1);
+   ASSERT(width >= 2*border);
+   ASSERT(height >= 2*border);
 
    tr->TileBorder = border;
    tr->TileWidth = width;
@@ -324,8 +341,8 @@ void trBeginTile(TRcontext *tr)
       /* This should never happen */
       abort();
    }
-   assert(tr->CurrentRow < tr->Rows);
-   assert(tr->CurrentColumn < tr->Columns);
+   ASSERT(tr->CurrentRow < tr->Rows);
+   ASSERT(tr->CurrentColumn < tr->Columns);
 
    border = tr->TileBorder;
 
@@ -377,7 +394,7 @@ int trEndTile(TRcontext *tr)
    if (!tr)
       return 0;
 
-   assert(tr->CurrentTile>=0);
+   ASSERT(tr->CurrentTile>=0);
 
    /* be sure OpenGL rendering is finished */
    glFlush();
@@ -484,10 +501,6 @@ void trRasterPos3f(TRcontext *tr, GLfloat x, GLfloat y, GLfloat z)
          glMatrixMode(GL_MODELVIEW);
          glPopMatrix();
       }
-#ifdef DEBUG
-      if (glGetError())
-         printf("GL error!\n");
-#endif
    }
 }
 
diff --git a/src/gl/tr.h b/src/gl/tr.h
index ef5f303..835b41b 100644
--- a/src/gl/tr.h
+++ b/src/gl/tr.h
@@ -1,6 +1,25 @@
 /* $Id: tr.h,v 1.5 1997/07/21 17:34:07 brianp Exp $ */
 
 /*
+	TR Tile rendering library
+	Copyright (C) 1997 Brian Paul
+
+	This program is free software; you can redistribute it and/or modify
+	it under the terms of the GNU General Public License as published by
+	the Free Software Foundation; either version 2 of the License, or
+	(at your option) any later version.
+
+	This program is distributed in the hope that it will be useful,
+	but WITHOUT ANY WARRANTY; without even the implied warranty of
+	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+	GNU General Public License for more details.
+
+	You should have received a copy of the GNU General Public License along
+	with this program; if not, write to the Free Software Foundation, Inc.,
+	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
  * $Log: tr.h,v $
  * Revision 1.5  1997/07/21  17:34:07  brianp
  * added tile borders, incremented version to 1.1
@@ -20,6 +39,8 @@
  */
 
 
+
+
 /*
  * Tiled Rendering library
  * Version 1.1
diff --git a/src/gui/dialogs/ExportPos.cpp b/src/gui/dialogs/ExportPos.cpp
index 6592f26..dc21e1f 100644
--- a/src/gui/dialogs/ExportPos.cpp
+++ b/src/gui/dialogs/ExportPos.cpp
@@ -72,17 +72,17 @@ ExportPosDialog::ExportPosDialog(wxWindow* parent, int id, const wxString& title
 	haveRefreshed=false;
 	exportVisible=true;
 	// begin wxGlade: ExportPosDialog::ExportPosDialog
-	lblExport = new wxStaticText(this, wxID_ANY, wxTRANS("Export:"));
-	radioVisible = new wxRadioButton(this,ID_RADIO_VISIBLE , wxTRANS("Visible"));
-	radioSelection = new wxRadioButton(this,ID_RADIO_SELECTION , wxTRANS("Selected Data"));
+	lblExport = new wxStaticText(this, wxID_ANY, TRANS("Export:"));
+	radioVisible = new wxRadioButton(this,ID_RADIO_VISIBLE , TRANS("Visible"));
+	radioSelection = new wxRadioButton(this,ID_RADIO_SELECTION , TRANS("Selected Data"));
 	treeData = new wxTreeCtrl(this, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER);
-	lblAvailableData = new wxStaticText(this, wxID_ANY, wxTRANS("Available Data"));
+	lblAvailableData = new wxStaticText(this, wxID_ANY, TRANS("Available Data"));
 	listAvailable = new wxListCtrl(this, ID_LIST_AVAILABLE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER|wxLC_VRULES);
 	btnAddData = new wxButton(this, ID_BTN_ADDDATA, wxT(">"));
 	btnAddNode = new wxButton(this,ID_BTN_ADDNODE, wxT(">>"));
 	btnAddAll = new wxButton(this, ID_BTN_ADDALL, wxT(">>>"));
 	panel_2 = new wxPanel(this, wxID_ANY);
-	label_4 = new wxStaticText(this, wxID_ANY, wxTRANS("Selection"));
+	label_4 = new wxStaticText(this, wxID_ANY, TRANS("Selection"));
 	listSelected = new wxListCtrl(this, ID_LIST_SELECTED, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER);
 	btnSave = new wxButton(this, wxID_SAVE, wxEmptyString);
 	btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString);
@@ -107,11 +107,11 @@ ExportPosDialog::ExportPosDialog(wxWindow* parent, int id, const wxString& title
 	//--
 
 	//Add columns to report listviews
-	listSelected->InsertColumn(0,wxTRANS("Index"));
-	listSelected->InsertColumn(1,wxTRANS("Count"));
+	listSelected->InsertColumn(0,TRANS("Index"));
+	listSelected->InsertColumn(1,TRANS("Count"));
 	
-	listAvailable->InsertColumn(0,wxTRANS("Index"));
-	listAvailable->InsertColumn(1,wxTRANS("Count"));
+	listAvailable->InsertColumn(0,TRANS("Index"));
+	listAvailable->InsertColumn(1,TRANS("Count"));
 }
 
 ExportPosDialog::~ExportPosDialog()
@@ -217,13 +217,13 @@ void ExportPosDialog::OnTreeFiltersSelChanged(wxTreeEvent &event)
 					(unsigned char)(ionData->g*255),(unsigned char)(ionData->b*255));
 				//Add the item using the index as a str
 				stream_cast(label,ui);
-				listAvailable->InsertItem(ui,wxStr(label));
+				listAvailable->InsertItem(ui,(label));
 				
 				size_t basicCount;
 				basicCount=ionData->getNumBasicObjects();
 				stream_cast(label,basicCount);
 
-				listAvailable->SetItem(ui,1,wxStr(label));
+				listAvailable->SetItem(ui,1,(label));
 				
 				listAvailable->SetItemBackgroundColour(ui,c);
 
@@ -359,13 +359,13 @@ void ExportPosDialog::updateSelectedList()
 				(unsigned char)(ionData->b*255));
 		//Add the item using the index as a str
 		stream_cast(label,idx);
-		listSelected->InsertItem(idx,wxStr(label));
+		listSelected->InsertItem(idx,(label));
 		
 		size_t basicCount;
 		basicCount=ionData->getNumBasicObjects();
 		stream_cast(label,basicCount);
 
-		listSelected->SetItem(idx,1,wxStr(label));
+		listSelected->SetItem(idx,1,(label));
 		
 		listSelected->SetItemBackgroundColour(idx,c);
 
@@ -454,14 +454,14 @@ void ExportPosDialog::getExportVec(std::vector<const FilterStreamData * > &v) co
 void ExportPosDialog::set_properties()
 {
     // begin wxGlade: ExportPosDialog::set_properties
-    SetTitle(wxTRANS("Export Pos Data"));
+    SetTitle(TRANS("Export Pos Data"));
     // end wxGlade
 
-	treeData->SetToolTip(wxTRANS("Tree of filters, select leaves to show ion data."));
+	treeData->SetToolTip(TRANS("Tree of filters, select leaves to show ion data."));
 	
-	btnAddAll->SetToolTip(wxTRANS("Add all data from all filters"));
-	btnAddNode->SetToolTip(wxTRANS("Add all data from currently selected filter"));
-	btnAddData->SetToolTip(wxTRANS("Add selected data from currently selected filter"));
+	btnAddAll->SetToolTip(TRANS("Add all data from all filters"));
+	btnAddNode->SetToolTip(TRANS("Add all data from currently selected filter"));
+	btnAddData->SetToolTip(TRANS("Add selected data from currently selected filter"));
     radioVisible->SetValue(TRUE);
 }
 
diff --git a/src/gui/dialogs/ExportRngDialog.cpp b/src/gui/dialogs/ExportRngDialog.cpp
index 423583b..800389a 100644
--- a/src/gui/dialogs/ExportRngDialog.cpp
+++ b/src/gui/dialogs/ExportRngDialog.cpp
@@ -37,9 +37,9 @@ ExportRngDialog::ExportRngDialog(wxWindow* parent, int id, const wxString& title
     wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
 {
     // begin wxGlade: ExportRngDialog::ExportRngDialog
-    lblRanges = new wxStaticText(this, wxID_ANY, wxTRANS("Range Sources"));
+    lblRanges = new wxStaticText(this, wxID_ANY, TRANS("Range Sources"));
     listRanges = new wxListCtrl(this, ID_LIST_ACTIVATE, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER);
-    label_3 = new wxStaticText(this, wxID_ANY, wxTRANS("Details"));
+    label_3 = new wxStaticText(this, wxID_ANY, TRANS("Details"));
     gridDetails = new wxGrid(this, wxID_ANY);
     btnOK = new wxButton(this, wxID_SAVE, wxEmptyString);
     btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString);
@@ -50,9 +50,9 @@ ExportRngDialog::ExportRngDialog(wxWindow* parent, int id, const wxString& title
     // end wxGlade
 
     //Add columns to report listviews
-    listRanges->InsertColumn(0,wxTRANS("Source Filter"));
-    listRanges->InsertColumn(1,wxTRANS("Ions"));
-    listRanges->InsertColumn(2,wxTRANS("Ranges"));
+    listRanges->InsertColumn(0,TRANS("Source Filter"));
+    listRanges->InsertColumn(1,TRANS("Ions"));
+    listRanges->InsertColumn(2,TRANS("Ranges"));
 
 }
 
@@ -85,17 +85,17 @@ void ExportRngDialog::updateGrid(unsigned int index)
         	gridDetails->DeleteRows(0,gridDetails->GetNumberRows());
 
 	gridDetails->AppendCols(3);
-	gridDetails->SetColLabelValue(0,wxTRANS("Param"));
-	gridDetails->SetColLabelValue(1,wxTRANS("Value"));
-	gridDetails->SetColLabelValue(2,wxTRANS("Value2"));
+	gridDetails->SetColLabelValue(0,TRANS("Param"));
+	gridDetails->SetColLabelValue(1,TRANS("Value"));
+	gridDetails->SetColLabelValue(2,TRANS("Value2"));
 
 	unsigned int nRows;
 	nRows=rangeData->getRange().getNumIons()+rangeData->getRange().getNumRanges() + 4;
 	gridDetails->AppendRows(nRows);
 
 
-	gridDetails->SetCellValue(0,0,wxTRANS("Ion Name"));
-	gridDetails->SetCellValue(0,1,wxTRANS("Num Ranges"));
+	gridDetails->SetCellValue(0,0,TRANS("Ion Name"));
+	gridDetails->SetCellValue(0,1,TRANS("Num Ranges"));
 	unsigned int row=1;
 	std::string tmpStr;
 
@@ -106,16 +106,16 @@ void ExportRngDialog::updateGrid(unsigned int index)
 	{	
 		//Use format 
 		// ION NAME  | NUMBER OF RANGES
-		gridDetails->SetCellValue(row,0,wxStr(rangeData->getRange().getName(ui)));
+		gridDetails->SetCellValue(row,0,(rangeData->getRange().getName(ui)));
 		stream_cast(tmpStr,rangeData->getRange().getNumRanges(ui));
-		gridDetails->SetCellValue(row,1,wxStr(tmpStr));
+		gridDetails->SetCellValue(row,1,(tmpStr));
 		row++;
 	}
 
 	row++;	
-	gridDetails->SetCellValue(row,0,wxTRANS("Ion"));
-	gridDetails->SetCellValue(row,1,wxTRANS("Range Start"));
-	gridDetails->SetCellValue(row,2,wxTRANS("Range end"));
+	gridDetails->SetCellValue(row,0,TRANS("Ion"));
+	gridDetails->SetCellValue(row,1,TRANS("Range Start"));
+	gridDetails->SetCellValue(row,2,TRANS("Range end"));
 	row++;	
 
 	maxNum=rangeData->getRange().getNumRanges();
@@ -127,13 +127,13 @@ void ExportRngDialog::updateGrid(unsigned int index)
 		rngPair=rangeData->getRange().getRange(ui);
 		ionID=rangeData->getRange().getIonID(ui);
 		gridDetails->SetCellValue(row,0,
-			wxStr(rangeData->getRange().getName(ionID)));
+			(rangeData->getRange().getName(ionID)));
 
 		stream_cast(tmpStr,rngPair.first);
-		gridDetails->SetCellValue(row,1,wxStr(tmpStr));
+		gridDetails->SetCellValue(row,1,(tmpStr));
 
 		stream_cast(tmpStr,rngPair.second);
-		gridDetails->SetCellValue(row,2,wxStr(tmpStr));
+		gridDetails->SetCellValue(row,2,(tmpStr));
 			
 		row++;	
 	}	
@@ -148,8 +148,8 @@ void ExportRngDialog::OnSave(wxCommandEvent &event)
 		EndModal(wxID_CANCEL);
 
 	//create a file chooser for later.
-	wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save pos..."), wxT(""),
-		wxT(""),wxTRANS("ORNL format RNG (*.rng)|*.rng|All Files (*)|*"),wxFD_SAVE);
+	wxFileDialog *wxF = new wxFileDialog(this,TRANS("Save pos..."), wxT(""),
+		wxT(""),TRANS("ORNL format RNG (*.rng)|*.rng|All Files (*)|*"),wxFD_SAVE);
 	//Show, then check for user cancelling export dialog
 	if(wxF->ShowModal() == wxID_CANCEL)
 	{
@@ -166,8 +166,8 @@ void ExportRngDialog::OnSave(wxCommandEvent &event)
 		std::string errString;
 		errString=TRANS("Unable to save. Check output destination can be written to.");
 		
-		wxMessageDialog *wxD  =new wxMessageDialog(this,wxStr(errString)
-						,wxTRANS("Save error"),wxOK|wxICON_ERROR);
+		wxMessageDialog *wxD  =new wxMessageDialog(this,(errString)
+						,TRANS("Save error"),wxOK|wxICON_ERROR);
 		wxD->ShowModal();
 		wxD->Destroy();
 		return;
@@ -217,15 +217,15 @@ void ExportRngDialog::updateRangeList()
 		rangeData=(RangeFileFilter *)rngFilters[ui];
 		std::string tmpStr;
 		long itemIndex;
-	       	itemIndex=listRanges->InsertItem(0, wxStr(rangeData->getUserString())); 
+	       	itemIndex=listRanges->InsertItem(0, (rangeData->getUserString())); 
 		unsigned int nIons,nRngs; 
 		nIons = rangeData->getRange().getNumIons();
 		nRngs = rangeData->getRange().getNumIons();
 
 		stream_cast(tmpStr,nIons);
-		listRanges->SetItem(itemIndex, 1, wxStr(tmpStr)); 
+		listRanges->SetItem(itemIndex, 1, (tmpStr)); 
 		stream_cast(tmpStr,nRngs);
-		listRanges->SetItem(itemIndex, 2, wxStr(tmpStr)); 
+		listRanges->SetItem(itemIndex, 2, (tmpStr)); 
 		
 	}
 }
@@ -233,14 +233,14 @@ void ExportRngDialog::updateRangeList()
 void ExportRngDialog::set_properties()
 {
     // begin wxGlade: ExportRngDialog::set_properties
-    SetTitle(wxTRANS("Export Range"));
+    SetTitle(TRANS("Export Range"));
     gridDetails->CreateGrid(0, 0);
 	gridDetails->SetRowLabelSize(0);
 	gridDetails->SetColLabelSize(0);
 
-    listRanges->SetToolTip(wxTRANS("List of rangefiles in filter tree"));
+    listRanges->SetToolTip(TRANS("List of rangefiles in filter tree"));
     gridDetails->EnableEditing(false);
-    gridDetails->SetToolTip(wxTRANS("Detailed view of selected range"));
+    gridDetails->SetToolTip(TRANS("Detailed view of selected range"));
     // end wxGlade
 }
 
diff --git a/src/gui/dialogs/StashDialog.cpp b/src/gui/dialogs/StashDialog.cpp
index accfc58..23b5987 100644
--- a/src/gui/dialogs/StashDialog.cpp
+++ b/src/gui/dialogs/StashDialog.cpp
@@ -20,6 +20,7 @@
 
 #include "wx/wxcommon.h"
 #include "wx/wxcomponents.h"
+#include "wx/propertyGridUpdater.h"
 #include "common/translation.h"
 
 #include "./backend/viscontrol.h"
@@ -42,19 +43,23 @@ StashDialog::StashDialog(wxWindow* parent, int id, const wxString& title, const
     wxDialog(parent, id, title, pos, size, style)
 {
     // begin wxGlade: StashDialog::StashDialog
-    label_5 = new wxStaticText(this, wxID_ANY, wxTRANS("Stashes"));
+    label_5 = new wxStaticText(this, wxID_ANY, TRANS("Stashes"));
     listStashes = new wxListCtrl(this, ID_LIST_STASH, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER);
     btnRemove = new wxButton(this, wxID_REMOVE, wxEmptyString);
-    label_6 = new wxStaticText(this, wxID_ANY, wxTRANS("Stashed Tree"));
+    label_6 = new wxStaticText(this, wxID_ANY, TRANS("Stashed Tree"));
     treeFilters = new wxTreeCtrl(this, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_HIDE_ROOT);
-    label_7 = new wxStaticText(this, wxID_ANY, wxTRANS("Properties"));
-    gridProperties = new wxCustomPropGrid(this, ID_GRID_FILTER);
+    label_7 = new wxStaticText(this, wxID_ANY, TRANS("Properties"));
+    gridProperties = new wxPropertyGrid(this, ID_GRID_FILTER);
     btnOK = new wxButton(this, wxID_OK, wxEmptyString);
+    
+    //Due to a bug in wx, empty reports throw an assertion
+    // 'unknown list item format", when there are no columns
+    listStashes->InsertColumn(0,TRANS("Stash Name"));
+    listStashes->InsertColumn(1,TRANS("Filter Count"));
 
     set_properties();
     do_layout();
     // end wxGlade
-    gridProperties->CreateGrid(0, 2);
 
 }
 
@@ -71,7 +76,7 @@ BEGIN_EVENT_TABLE(StashDialog, wxDialog)
     EVT_BUTTON(wxID_REMOVE, StashDialog::OnBtnRemove)
     EVT_LIST_ITEM_SELECTED(ID_LIST_STASH, StashDialog::OnListSelected)
     EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, StashDialog::OnTreeSelChange)
-    EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_FILTER,StashDialog::OnGridEditor)
+    EVT_PG_CHANGING(ID_GRID_FILTER,StashDialog::OnGridEditor)
     // end wxGlade
 END_EVENT_TABLE();
 
@@ -83,18 +88,21 @@ void StashDialog::setVisController(VisController *s)
 void StashDialog::set_properties()
 {
     // begin wxGlade: StashDialog::set_properties
-    SetTitle(wxTRANS("Stashed Trees"));
+    SetTitle(TRANS("Stashed Trees"));
     SetSize(wxSize(600, 430));
 
-    btnRemove->SetToolTip(wxTRANS("Erase stashed item"));
-    treeFilters->SetToolTip(wxTRANS("Filter view for current stash"));
-    gridProperties->SetToolTip(wxTRANS("Settings for selected filter in current stash"));
-    listStashes->SetToolTip(wxTRANS("Available stashes"));
+    btnRemove->SetToolTip(TRANS("Erase stashed item"));
+    treeFilters->SetToolTip(TRANS("Filter view for current stash"));
+    gridProperties->SetToolTip(TRANS("Settings for selected filter in current stash"));
+    listStashes->SetToolTip(TRANS("Available stashes"));
     // end wxGlade
 }
 
-void StashDialog::OnGridEditor(wxGridEvent &evt)
+void StashDialog::OnGridEditor(wxPropertyGridEvent &evt)
 {
+	//Silence error mesages
+	evt.SetValidationFailureBehavior(0);
+	
 	evt.Veto();
 }
 
@@ -146,12 +154,11 @@ void StashDialog::updateList()
 	visControl->getStashes(stashes);
 
 	//Clear the existing list
-	listStashes->ClearAll();
+	listStashes->Freeze();
+	listStashes->DeleteAllItems();
 	
 	//Fill it with "stash" entries
 	//Add columns to report listviews
-	listStashes->InsertColumn(0,wxTRANS("Stash Name"),3);
-	listStashes->InsertColumn(1,wxTRANS("Filter Count"),1);
 	for (unsigned int ui=0; ui<stashes.size(); ui++)
 	{
 		string strTmp;
@@ -159,24 +166,24 @@ void StashDialog::updateList()
 		long itemIdx;
 		
 		//First item is the stash name
-		itemIdx = listStashes->InsertItem(ui,wxStr(stashes[ui].first));
+		itemIdx = listStashes->InsertItem(ui,(stashes[ui].first));
 
 		//Second column is num filters
 		
 		visControl->getStashTree(stashes[ui].second,t);
 		stream_cast(strTmp,t.size());
-		listStashes->SetItem(ui,1,wxStr(strTmp));
+		listStashes->SetItem(itemIdx,1,(strTmp));
 
 		//Set the stash ID as the list data item
 		//this is the key to the stash val
 		listStashes->SetItemData(itemIdx,stashes[ui].second);	
 	}
-
+	listStashes->Thaw();
 }
 
 void StashDialog::updateGrid()
 {
-	gridProperties->clear();
+	gridProperties->Clear();
 	if(!treeFilters->GetCount())
 		return;
 	//Get the selection from the current tree
@@ -214,31 +221,9 @@ void StashDialog::updateGrid()
 	}
 	
 	ASSERT(targetFilter);	
-	
-	FilterPropGroup p;
-	targetFilter->getProperties(p);
 
-	gridProperties->clearKeys();
-	gridProperties->setNumGroups(p.numGroups());
-	//Create the keys for the property grid to do its thing
-	for(unsigned int ui=0;ui<p.numGroups();ui++)
-	{
-		vector<FilterProperty> propGrouping;
-		p.getGroup(ui,propGrouping);
+	updateFilterPropertyGrid(gridProperties,targetFilter,"");	
 
-		for(size_t uj=0;uj<propGrouping.size();uj++)
-		{
-			gridProperties->addKey(propGrouping[uj].name,ui,
-				propGrouping[uj].key,
-				propGrouping[uj].type,
-				propGrouping[uj].data,
-				propGrouping[uj].helpText);
-		}
-	}
-
-	//Let the property grid layout what it needs to
-	gridProperties->propertyLayout();
-	
 }
 
 bool StashDialog::getStashIdFromList(unsigned int &stashId)
@@ -326,7 +311,7 @@ void StashDialog::updateTree()
 	
 		//This will use the user label or the type string.	
 		tid=treeFilters->AppendItem(treeIDs.top(),
-			wxStr((*filtIt)->getUserString()));
+			((*filtIt)->getUserString()));
 		
 		treeFilters->SetItemData(tid,new wxTreeUint(pos));
 		pos++;
diff --git a/src/gui/dialogs/StashDialog.h b/src/gui/dialogs/StashDialog.h
index 8be7b5c..fda4183 100644
--- a/src/gui/dialogs/StashDialog.h
+++ b/src/gui/dialogs/StashDialog.h
@@ -23,6 +23,7 @@
 #include <wx/wx.h>
 #include <wx/treectrl.h>
 #include <wx/grid.h>
+#include <wx/propgrid/propgrid.h>
 
 // end wxGlade
 
@@ -67,7 +68,7 @@ protected:
     wxStaticText* label_6;
     wxTreeCtrl* treeFilters;
     wxStaticText* label_7;
-    wxCustomPropGrid* gridProperties;
+    wxPropertyGrid* gridProperties;
     wxButton* btnOK;
     // end wxGlade
 
@@ -77,7 +78,7 @@ public:
     virtual void OnListKeyDown(wxListEvent &event); // wxGlade: <event_handler>
     virtual void OnListSelected(wxListEvent &event); // wxGlade: <event_handler>
     virtual void OnTreeSelChange(wxTreeEvent &event); // wxGlade: <event_handler>
-    virtual void OnGridEditor(wxGridEvent &event);
+    virtual void OnGridEditor(wxPropertyGridEvent &event);
 
     virtual void OnBtnRemove(wxCommandEvent &event);
     void ready();
diff --git a/src/gui/dialogs/animateFilterDialog.cpp b/src/gui/dialogs/animateFilterDialog.cpp
index 3b95109..c98b803 100644
--- a/src/gui/dialogs/animateFilterDialog.cpp
+++ b/src/gui/dialogs/animateFilterDialog.cpp
@@ -19,6 +19,7 @@
 
 #include "animateFilterDialog.h"
 #include "resolutionDialog.h"
+#include "wx/propertyGridUpdater.h"
 
 
 #include "./animateSubDialogs/realKeyFrameDialog.h"
@@ -148,31 +149,31 @@ ExportAnimationDialog::ExportAnimationDialog(wxWindow* parent, int id, const wxS
     splitPaneFilter = new wxSplitterWindow(filterViewPane, ID_SPLIT_FILTERVIEW, wxDefaultPosition, wxDefaultSize, wxSP_3D|wxSP_BORDER);
     filterRightPane = new wxPanel(splitPaneFilter, wxID_ANY);
     filterLeftPane = new wxPanel(splitPaneFilter, wxID_ANY);
-    keyFramesSizer_staticbox = new wxStaticBox(filterRightPane, -1, wxTRANS("Key frames"));
-    outputDataSizer_staticbox = new wxStaticBox(frameViewPane, -1, wxTRANS("Output Data"));
-    filterPropertySizer_staticbox = new wxStaticBox(filterLeftPane, -1, wxTRANS("Filters and properties"));
+    keyFramesSizer_staticbox = new wxStaticBox(filterRightPane, -1, TRANS("Key frames"));
+    outputDataSizer_staticbox = new wxStaticBox(frameViewPane, -1, TRANS("Output Data"));
+    filterPropertySizer_staticbox = new wxStaticBox(filterLeftPane, -1, TRANS("Filters and properties"));
     filterTreeCtrl =new wxTreeCtrl(filterLeftPane,ID_FILTER_TREE_CTRL , wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_EDIT_LABELS);
 
-    propertyGrid = new wxCustomPropGrid(filterLeftPane, ID_PROPERTY_GRID);
+    propertyGrid = new wxPropertyGrid(filterLeftPane, ID_PROPERTY_GRID);
     animationGrid = new wxGrid(filterRightPane, ID_ANIMATION_GRID_CTRL);
     keyFrameRemoveButton = new wxButton(filterRightPane, wxID_REMOVE, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-    labelWorkDir = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Dir : "));
+    labelWorkDir = new wxStaticText(frameViewPane, wxID_ANY, TRANS("Dir : "));
     textWorkDir = new wxTextCtrl(frameViewPane, ID_TEXTBOX_WORKDIR, wxEmptyString);
     buttonWorkDir = new wxButton(frameViewPane, wxID_OPEN, wxEmptyString);
-    checkOutOnlyChanged = new wxCheckBox(frameViewPane, ID_CHECK_ONLYDATACHANGE, wxTRANS("Output only when refresh required"));
+    checkOutOnlyChanged = new wxCheckBox(frameViewPane, ID_CHECK_ONLYDATACHANGE, TRANS("Output only when refresh required"));
     outputDataSepLine = new wxStaticLine(frameViewPane, wxID_ANY);
-    labelDataType = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Data Types:"));
-    checkImageOutput = new wxCheckBox(frameViewPane, ID_CHECK_IMAGE_OUT, wxTRANS("3D Images"));
-    lblImageName = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("File Suffix: "));
+    labelDataType = new wxStaticText(frameViewPane, wxID_ANY, TRANS("Data Types:"));
+    checkImageOutput = new wxCheckBox(frameViewPane, ID_CHECK_IMAGE_OUT, TRANS("3D Images"));
+    lblImageName = new wxStaticText(frameViewPane, wxID_ANY, TRANS("File Suffix: "));
     textImageName = new wxTextCtrl(frameViewPane, ID_TEXTBOX_IMAGEPREFIX, wxEmptyString);
-    labelImageSize = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Size : "));
+    labelImageSize = new wxStaticText(frameViewPane, wxID_ANY, TRANS("Size : "));
     textImageSize = new wxTextCtrl(frameViewPane, ID_TEXTBOX_IMAGESIZE, wxEmptyString, wxDefaultPosition,wxDefaultSize, wxTE_READONLY );
-    buttonImageSize = new wxButton(frameViewPane, ID_BUTTON_IMAGE_RES, wxTRANS("..."));
-    checkPoints = new wxCheckBox(frameViewPane, ID_CHECK_POINT_OUT, wxTRANS("Point data"));
-    checkPlotData = new wxCheckBox(frameViewPane, ID_CHECK_PLOT_OUT, wxTRANS("Plots"));
-    checkVoxelData = new wxCheckBox(frameViewPane, ID_CHECK_VOXEL_OUT, wxTRANS("Voxel data"));
-    checkRangeData = new wxCheckBox(frameViewPane, ID_CHECK_RANGE_OUT, wxTRANS("Range files"));
-    labelRangeFormat = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Format"));
+    buttonImageSize = new wxButton(frameViewPane, ID_BUTTON_IMAGE_RES, TRANS("..."));
+    checkPoints = new wxCheckBox(frameViewPane, ID_CHECK_POINT_OUT, TRANS("Point data"));
+    checkPlotData = new wxCheckBox(frameViewPane, ID_CHECK_PLOT_OUT, TRANS("Plots"));
+    checkVoxelData = new wxCheckBox(frameViewPane, ID_CHECK_VOXEL_OUT, TRANS("Voxel data"));
+    checkRangeData = new wxCheckBox(frameViewPane, ID_CHECK_RANGE_OUT, TRANS("Range files"));
+    labelRangeFormat = new wxStaticText(frameViewPane, wxID_ANY, TRANS("Format"));
     
     //Workaround for wx bug http://trac.wxwidgets.org/ticket/4398
     wxSortedArrayString rangeNames;
@@ -183,12 +184,12 @@ ExportAnimationDialog::ExportAnimationDialog(wxWindow* parent, int id, const wxS
 	//construct translation->comboRange_choices offset.
 	rangeMap[TRANS(str)] = ui;
 	//Add to filter name wxArray
-	wxString wxStrTrans = wxTRANS(str);
+	wxString wxStrTrans = TRANS(str);
 	rangeNames.Add(wxStrTrans);
     }
     comboRangeFormat = new wxChoice(frameViewPane, ID_COMBO_RANGE_TYPE, wxDefaultPosition, wxDefaultSize, rangeNames);
     static_line_1 = new wxStaticLine(frameViewPane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL);
-    labelFrame = new wxStaticText(frameViewPane, wxID_ANY, wxTRANS("Frame"));
+    labelFrame = new wxStaticText(frameViewPane, wxID_ANY, TRANS("Frame"));
     frameSlider = new wxSlider(frameViewPane, ID_FRAME_SLIDER, 0, 0, 1);
     textFrame = new wxTextCtrl(frameViewPane, ID_FRAME_TEXTBOX, wxEmptyString);
     framePropGrid = new wxGrid(frameViewPane, ID_FILTER_PROPERTY_VALUE_GRID);
@@ -201,16 +202,13 @@ ExportAnimationDialog::ExportAnimationDialog(wxWindow* parent, int id, const wxS
     // end wxGlade
  
 
-#if wxCHECK_VERSION(2,9,0)
     //Manually tuned splitter parameters
     splitPaneFilter->SetMinimumPaneSize(220);
     int w, h;
     GetClientSize(&w,&h);
 
     float sashFrac=0.4;
-
     splitPaneFilter->SetSashPosition((int)(sashFrac*w));
-#endif
 
     programmaticEvent=true;
 
@@ -243,8 +241,9 @@ ExportAnimationDialog::~ExportAnimationDialog()
 BEGIN_EVENT_TABLE(ExportAnimationDialog, wxDialog)
     // begin wxGlade: ExportAnimationDialog::event_table
     EVT_TREE_SEL_CHANGED(ID_FILTER_TREE_CTRL, ExportAnimationDialog::OnFilterTreeCtrlSelChanged)
-    EVT_GRID_CMD_EDITOR_SHOWN(ID_PROPERTY_GRID, ExportAnimationDialog::OnFilterGridCellEditorShow)
-    EVT_GRID_CMD_EDITOR_SHOWN(ID_ANIMATION_GRID_CTRL, ExportAnimationDialog::OnFrameGridCellEditorShow)
+    EVT_PG_SELECTED(ID_PROPERTY_GRID, ExportAnimationDialog::OnFilterGridCellSelected)
+    EVT_PG_CHANGING(ID_PROPERTY_GRID, ExportAnimationDialog::OnFilterGridCellChanging)
+    EVT_TREE_SEL_CHANGED(ID_FILTER_TREE_CTRL, ExportAnimationDialog::OnFilterTreeCtrlSelChanged)
     EVT_GRID_CMD_EDITOR_SHOWN(ID_FILTER_TREE_CTRL, ExportAnimationDialog::OnAnimateGridCellEditorShow)
     EVT_SPLITTER_UNSPLIT(ID_SPLIT_FILTERVIEW, ExportAnimationDialog::OnFilterViewUnsplit) 
     EVT_BUTTON(wxID_REMOVE, ExportAnimationDialog::OnButtonKeyFrameRemove)
@@ -273,7 +272,7 @@ void ExportAnimationDialog::setDefImSize(unsigned int w, unsigned int h)
     string sFirst,sSecond;
     stream_cast(sFirst,imageWidth);
     stream_cast(sSecond,imageHeight);
-    textImageSize->SetValue(wxStr(string(sFirst+string("x")+sSecond)));
+    textImageSize->SetValue((string(sFirst+string("x")+sSecond)));
     
     imageSizeOK=true;
 }
@@ -397,7 +396,6 @@ void ExportAnimationDialog::prepare()
 	upWxTreeCtrl(*filterTree,filterTreeCtrl,filterMap,
 			dummyVec,NULL);
 
-	update();
 }
 
 void ExportAnimationDialog::updateFilterViewGrid()
@@ -426,17 +424,17 @@ void ExportAnimationDialog::updateFilterViewGrid()
 		filtProp=filtPropGroup.getPropValue(frameProps.getPropertyKey());
 
 		animationGrid->SetCellValue(ui,CELL_FILTERNAME, 
-				wxStr(filterPtr->getUserString()));
+				(filterPtr->getUserString()));
 		animationGrid->SetCellValue(ui,CELL_PROPERTYNAME, 
-				wxStr(filtProp.name));
+				(filtProp.name));
 		animationGrid->SetCellValue(ui,CELL_KEYINTERPMODE, 
-				wxCStr(INTERP_NAME[frameProps.getInterpMode()]));
+				(INTERP_NAME[frameProps.getInterpMode()]));
 		
 		string str;
 		stream_cast(str,frameProps.getMinFrame());
-		animationGrid->SetCellValue(ui,CELL_STARTFRAME, wxStr(str));
+		animationGrid->SetCellValue(ui,CELL_STARTFRAME, (str));
 		stream_cast(str,frameProps.getMaxFrame());
-		animationGrid->SetCellValue(ui,CELL_ENDFRAME, wxStr(str));
+		animationGrid->SetCellValue(ui,CELL_ENDFRAME, (str));
 	}
 
 	//Check for conflicting rows in the animation dialog,
@@ -505,11 +503,11 @@ void ExportAnimationDialog::updateFrameViewGrid()
 
 		//Modify the grid properties with the appropriate data
 		framePropGrid->SetCellValue(ui,FRAME_CELL_FILTERNAME, 
-				wxStr(filterName));
+				(filterName));
 		framePropGrid->SetCellValue(ui,FRAME_CELL_PROPNAME, 
-				wxStr(propertyName));
+				(propertyName));
 		framePropGrid->SetCellValue(ui,FRAME_CELL_VALUE, 
-				wxStr(animatedValue));
+				(animatedValue));
 	}
 
 }
@@ -531,7 +529,7 @@ void ExportAnimationDialog::updateFrameViewSlider()
 	stream_cast(textMax,propertyAnimator.getMaxFrame());
 
 	textCurrent= (textCurrent + std::string("/") + textMax);
-	textFrame->SetValue( wxStr(textCurrent));
+	textFrame->SetValue( (textCurrent));
 
 	programmaticEvent=false;
 
@@ -594,7 +592,7 @@ void ExportAnimationDialog::OnFrameViewSlider(wxScrollEvent &event)
 	stream_cast(tmp,frameSlider->GetMax());
 	frameText+=tmp;
 
-	textFrame->SetValue( wxStr(frameText));
+	textFrame->SetValue( (frameText));
 
 	currentFrame=sliderVal;
 	updateFrameViewGrid();
@@ -625,34 +623,39 @@ void ExportAnimationDialog::OnFilterTreeCtrlSelChanged(wxTreeEvent &event)
 	{
 		wxTreeItemData *parentData=filterTreeCtrl->GetItemData(id);
 		updateFilterPropertyGrid(propertyGrid, 
-				filterMap[((wxTreeUint *)parentData)->value]);
+				filterMap[((wxTreeUint *)parentData)->value],"");
 	}
 
 	event.Skip();
 }
 
-
-void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
+void ExportAnimationDialog::OnFilterGridCellChanging(wxPropertyGridEvent &event)
 {
+	event.SetValidationFailureBehavior(0);
 	event.Veto();
-	wxTreeItemId id=filterTreeCtrl->GetSelection();;
+}
 
-	if(id ==filterTreeCtrl->GetRootItem() || !id.IsOk())
-		return;
+void ExportAnimationDialog::OnFilterGridCellSelected(wxPropertyGridEvent &event)
+{
+	event.Veto();
 
+	wxTreeItemId tId=filterTreeCtrl->GetSelection();;
 
-	unsigned int key;
-	key=propertyGrid->getKeyFromRow(event.GetRow());
+	if(tId ==filterTreeCtrl->GetRootItem() || !tId.IsOk())
+		return;
 
 	//Get the filter ID value 
 	size_t filterId;
-	wxTreeItemId tId = filterTreeCtrl->GetSelection();
-	if(!tId.IsOk())
-		return;
-
 	wxTreeItemData *tData=filterTreeCtrl->GetItemData(tId);
 	filterId = ((wxTreeUint *)tData)->value;
 
+	//grab tyhe key from the property grid
+	size_t key;
+	std::string keyStr;
+	keyStr=event.GetProperty()->GetName();
+	stream_cast(key,keyStr);
+
+
 	const Filter *f;
 	f=filterMap.at(filterId);
 	
@@ -671,7 +674,7 @@ void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
 	{
 		case PROPERTY_TYPE_BOOL:
 		{
-			wxTextEntryDialog *teD = new wxTextEntryDialog(this,wxTRANS("transition frame"),wxTRANS("Frame count"),
+			wxTextEntryDialog *teD = new wxTextEntryDialog(this,TRANS("transition frame"),TRANS("Frame count"),
 						wxT("0"),(long int)wxOK|wxCANCEL);
 	
 			std::string s;
@@ -743,7 +746,7 @@ void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
 		case PROPERTY_TYPE_COLOUR:
 		{
 			ColourKeyFrameDialog *colDlg = new ColourKeyFrameDialog(this,
-					wxID_ANY,wxTRANS("Key frame : Colour")) ;
+					wxID_ANY,TRANS("Key frame : Colour")) ;
 			if( colDlg->ShowModal() != wxID_OK)
 			{
 				colDlg->Destroy();
@@ -796,8 +799,8 @@ void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
 			{
 				sd->Destroy();
 				wxMessageDialog *wxD  =new wxMessageDialog(this,
-						wxTRANS("File existed, but was unable to read or interpret file contents."), 
-						wxTRANS("String load failed"),wxICON_ERROR|wxOK);
+						TRANS("File existed, but was unable to read or interpret file contents."), 
+						TRANS("String load failed"),wxICON_ERROR|wxOK);
 
 				wxD->ShowModal();
 				wxD->Destroy();
@@ -818,7 +821,7 @@ void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
 		case PROPERTY_TYPE_REAL:
 		{
 			RealKeyFrameDialog<float> *r = new RealKeyFrameDialog<float>(this,
-					wxID_ANY,wxTRANS("Keyframe : decimal"));
+					wxID_ANY,TRANS("Keyframe : decimal"));
 			if(!getRealKeyFrame(frameProp,filterProp,r))
 				return;
 			frameProp.setInterpMode(r->getTransitionMode());
@@ -827,7 +830,7 @@ void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
 		case PROPERTY_TYPE_INTEGER:
 		{
 			RealKeyFrameDialog<int> *r = new RealKeyFrameDialog<int>(this,
-					wxID_ANY,wxTRANS("Keyframe : integer"));
+					wxID_ANY,TRANS("Keyframe : integer"));
 			if(!getRealKeyFrame(frameProp,filterProp,r))
 				return;
 			frameProp.setInterpMode(r->getTransitionMode());
@@ -836,7 +839,7 @@ void ExportAnimationDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
 		case PROPERTY_TYPE_POINT3D:
 		{
 			RealKeyFrameDialog<Point3D> *r = new RealKeyFrameDialog<Point3D>(this,
-					wxID_ANY,wxTRANS("Keyframe : 3D Point"));
+					wxID_ANY,TRANS("Keyframe : 3D Point"));
 			if(!getRealKeyFrame(frameProp,filterProp,r))
 				return;
 			//Animator needs special Linear ramping code, so select that
@@ -961,7 +964,7 @@ void ExportAnimationDialog::OnOutputDirText(wxCommandEvent &event)
 void ExportAnimationDialog::OnButtonWorkDir(wxCommandEvent &event)
 {
 	//Pop up a directory dialog, to choose the base path for the new folder
-	wxDirDialog *wxD = new wxDirDialog(this, wxTRANS("Select or create new folder"),
+	wxDirDialog *wxD = new wxDirDialog(this, TRANS("Select or create new folder"),
 	wxFileSelectorDefaultWildcardStr, wxFD_SAVE);
 
 	unsigned int res;
@@ -1043,7 +1046,7 @@ void ExportAnimationDialog::OnBtnResolution(wxCommandEvent &event)
 	
 	string s;
 	s=sWidth+"x" + sHeight;
-	textImageSize->SetValue(wxStr(s));
+	textImageSize->SetValue((s));
 
 	r->Destroy();
 }
@@ -1141,39 +1144,36 @@ void ExportAnimationDialog::getPathMapping(vector<pair<string,size_t> > &mapping
 void ExportAnimationDialog::set_properties()
 {
     // begin wxGlade: ExportAnimationDialog::set_properties
-    SetTitle(wxTRANS("Export Animation"));
-    filterTreeCtrl->SetToolTip(wxTRANS("Select filter"));
-    propertyGrid->CreateGrid(0, 2);
-    propertyGrid->SetColLabelValue(0, wxTRANS("Property"));
-    propertyGrid->SetColLabelValue(1, wxTRANS("Value"));
-    propertyGrid->SetToolTip(wxTRANS("Select property"));
+    SetTitle(TRANS("Export Animation"));
+    filterTreeCtrl->SetToolTip(TRANS("Select filter"));
+    propertyGrid->SetToolTip(TRANS("Select property"));
     animationGrid->CreateGrid(0, 5);
-    animationGrid->SetColLabelValue(0, wxTRANS("Filter"));
-    animationGrid->SetColLabelValue(1, wxTRANS("Property"));
-    animationGrid->SetColLabelValue(2, wxTRANS("Mode"));
-    animationGrid->SetColLabelValue(3, wxTRANS("Start Frame"));
-    animationGrid->SetColLabelValue(4, wxTRANS("End Frame"));
-    animationGrid->SetToolTip(wxTRANS("Keyframe table"));
-    keyFrameRemoveButton->SetToolTip(wxTRANS("Remove the selected keyframe from the table"));
-    textWorkDir->SetToolTip(wxTRANS("Enter where the animation frames will be exported to"));
-    buttonWorkDir->SetToolTip(wxTRANS("Browse to directory where the animation frames will be exported to"));
+    animationGrid->SetColLabelValue(0, TRANS("Filter"));
+    animationGrid->SetColLabelValue(1, TRANS("Property"));
+    animationGrid->SetColLabelValue(2, TRANS("Mode"));
+    animationGrid->SetColLabelValue(3, TRANS("Start Frame"));
+    animationGrid->SetColLabelValue(4, TRANS("End Frame"));
+    animationGrid->SetToolTip(TRANS("Keyframe table"));
+    keyFrameRemoveButton->SetToolTip(TRANS("Remove the selected keyframe from the table"));
+    textWorkDir->SetToolTip(TRANS("Enter where the animation frames will be exported to"));
+    buttonWorkDir->SetToolTip(TRANS("Browse to directory where the animation frames will be exported to"));
     checkImageOutput->SetValue(1);
-    textImageName->SetToolTip(wxTRANS("Title for files, result will be saved as #-name.png, where # is image number."));
-    textImageSize->SetToolTip(wxTRANS("Target resolution (image size)"));
+    textImageName->SetToolTip(TRANS("Title for files, result will be saved as #-name.png, where # is image number."));
+    textImageSize->SetToolTip(TRANS("Target resolution (image size)"));
     comboRangeFormat->SetSelection(-1);
-    frameSlider->SetToolTip(wxTRANS("Select frame for property display"));
-    textFrame->SetToolTip(wxTRANS("Enter frame number to change frame (eg 1/20)"));
-    checkPoints->SetToolTip(wxTRANS("Save point data (POS files) in output folder?"));
-    checkPlotData->SetToolTip(wxTRANS("Save plots (as text files) in output folder?"));
-    checkVoxelData->SetToolTip(wxTRANS("Save voxel data (raw files) in output folder?"));
-    checkRangeData->SetToolTip(wxTRANS("Save range files  in output folder?"));
+    frameSlider->SetToolTip(TRANS("Select frame for property display"));
+    textFrame->SetToolTip(TRANS("Enter frame number to change frame (eg 1/20)"));
+    checkPoints->SetToolTip(TRANS("Save point data (POS files) in output folder?"));
+    checkPlotData->SetToolTip(TRANS("Save plots (as text files) in output folder?"));
+    checkVoxelData->SetToolTip(TRANS("Save voxel data (raw files) in output folder?"));
+    checkRangeData->SetToolTip(TRANS("Save range files  in output folder?"));
     framePropGrid->CreateGrid(0, 3);
-    framePropGrid->SetColLabelValue(0, wxTRANS("Filter"));
-    framePropGrid->SetColLabelValue(1, wxTRANS("Property"));
-    framePropGrid->SetColLabelValue(2, wxTRANS("Value"));
-    framePropGrid->SetToolTip(wxTRANS("Animation parameters for current frame"));
-    cancelButton->SetToolTip(wxTRANS("Abort animation"));
-    okButton->SetToolTip(wxTRANS("Run Animation"));
+    framePropGrid->SetColLabelValue(0, TRANS("Filter"));
+    framePropGrid->SetColLabelValue(1, TRANS("Property"));
+    framePropGrid->SetColLabelValue(2, TRANS("Value"));
+    framePropGrid->SetToolTip(TRANS("Animation parameters for current frame"));
+    cancelButton->SetToolTip(TRANS("Abort animation"));
+    okButton->SetToolTip(TRANS("Run Animation"));
     // end wxGlade
 }
 
@@ -1244,8 +1244,8 @@ void ExportAnimationDialog::do_layout()
     propGridSizer->Add(framePropGrid, 1, wxEXPAND, 0);
     frameViewSizer->Add(propGridSizer, 2, wxALL|wxEXPAND, 3);
     frameViewPane->SetSizer(frameViewSizer);
-    viewNotebook->AddPage(filterViewPane, wxTRANS("Filter view"));
-    viewNotebook->AddPage(frameViewPane, wxTRANS("Frame view"));
+    viewNotebook->AddPage(filterViewPane, TRANS("Filter view"));
+    viewNotebook->AddPage(frameViewPane, TRANS("Frame view"));
     animateSizer->Add(viewNotebook, 1, wxEXPAND, 0);
     globalButtonSizer->Add(20, 1, 1, wxEXPAND, 0);
     globalButtonSizer->Add(cancelButton, 0, wxALL|wxALIGN_BOTTOM, 3);
diff --git a/src/gui/dialogs/animateFilterDialog.h b/src/gui/dialogs/animateFilterDialog.h
index 49fa856..1f4cdac 100644
--- a/src/gui/dialogs/animateFilterDialog.h
+++ b/src/gui/dialogs/animateFilterDialog.h
@@ -181,7 +181,7 @@ protected:
     wxStaticBox* keyFramesSizer_staticbox;
     wxStaticBox* filterPropertySizer_staticbox;
     wxTreeCtrl* filterTreeCtrl;
-    wxCustomPropGrid* propertyGrid;
+    wxPropertyGrid* propertyGrid;
     wxPanel* filterLeftPane;
     wxGrid* animationGrid;
     wxButton* keyFrameRemoveButton;
@@ -221,7 +221,8 @@ protected:
 
 public:
     virtual void OnFilterTreeCtrlSelChanged(wxTreeEvent &event); // wxGlade: <event_handler>
-    virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // wxGlade: <event_handler>
+    virtual void OnFilterGridCellChanging(wxPropertyGridEvent &event); // wxGlade: <event_handler>
+    virtual void OnFilterGridCellSelected(wxPropertyGridEvent &event); // wxGlade: <event_handler>
     virtual void OnAnimateGridCellEditorShow(wxGridEvent &event); // wxGlade: <event_handler>
     virtual void OnFrameGridCellEditorShow(wxGridEvent &event); // wxGlade: <event_handler>
     virtual void OnButtonKeyFrameRemove(wxCommandEvent &event); // wxGlade: <event_handler>
diff --git a/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp b/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp
index 147f1f9..2f16b25 100644
--- a/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp
+++ b/src/gui/dialogs/animateSubDialogs/choiceKeyFrameDialog.cpp
@@ -82,7 +82,7 @@ void ChoiceKeyFrameDialog::buildCombo(size_t defaultChoice)
 	comboChoice->Clear();
 
 	for(size_t ui=0;ui<choiceStrings.size();ui++)
-		comboChoice->Append(wxStr(choiceStrings[ui]));
+		comboChoice->Append((choiceStrings[ui]));
 
 	comboChoice->SetSelection(defaultChoice);
 }
diff --git a/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp b/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp
index f640e72..25a0b9c 100644
--- a/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp
+++ b/src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp
@@ -53,23 +53,23 @@ ColourKeyFrameDialog::ColourKeyFrameDialog(wxWindow* parent, int id, const wxStr
 	wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX)
 {
 	// begin wxGlade: ColourKeyFrameDialog::ColourKeyFrameDialog
-	sizerMainArea_staticbox = new wxStaticBox(this, -1, wxTRANS("Keyframe Data"));
-	labelTransition = new wxStaticText(this, wxID_ANY, wxTRANS("Transition"));
+	sizerMainArea_staticbox = new wxStaticBox(this, -1, TRANS("Keyframe Data"));
+	labelTransition = new wxStaticText(this, wxID_ANY, TRANS("Transition"));
 	//FIXME: THis is declared in animator.h - use that def.
 	const wxString comboTransition_choices[] = {
-        wxTRANS("Step"),
-        wxTRANS("Ramp")
+        TRANS("Step"),
+        TRANS("Ramp")
     };
 	comboTransition = new wxComboBox(this, ID_COMBO_TRANSITION, wxT(""), wxDefaultPosition, wxDefaultSize, 2, comboTransition_choices, wxCB_DROPDOWN|wxCB_READONLY);
-	labelFrameStart = new wxStaticText(this, wxID_ANY, wxTRANS("Start Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+	labelFrameStart = new wxStaticText(this, wxID_ANY, TRANS("Start Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
 	textFrameStart = new wxTextCtrl(this, ID_TEXT_FRAME_START, wxEmptyString);
-	labelFrameEnd = new wxStaticText(this, wxID_ANY, wxTRANS("End Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+	labelFrameEnd = new wxStaticText(this, wxID_ANY, TRANS("End Frame"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
 	textFrameEnd = new wxTextCtrl(this, ID_TEXT_FRAME_END, wxEmptyString);
 	verticalLine = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_VERTICAL);
-	labelStartVal = new wxStaticText(this, wxID_ANY, wxTRANS("Initial Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
-	btnStartColour = new wxButton(this, ID_BTN_START_VALUE, wxTRANS("startColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-	labelFinalVal = new wxStaticText(this, wxID_ANY, wxTRANS("Final Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
-	btnEndColour = new wxButton(this, ID_BTN_FINAL_VALUE, wxTRANS("endColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+	labelStartVal = new wxStaticText(this, wxID_ANY, TRANS("Initial Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+	btnStartColour = new wxButton(this, ID_BTN_START_VALUE, TRANS("startColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
+	labelFinalVal = new wxStaticText(this, wxID_ANY, TRANS("Final Value"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+	btnEndColour = new wxButton(this, ID_BTN_FINAL_VALUE, TRANS("endColour"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
 	buttonCancel = new wxButton(this, wxID_CANCEL, wxEmptyString);
 	buttonOK = new wxButton(this, wxID_OK, wxEmptyString);
 
@@ -114,16 +114,14 @@ size_t ColourKeyFrameDialog::getEndFrame() const
 std::string ColourKeyFrameDialog::getEndValue() const 
 {
 	ASSERT(transitionMode!=TRANSITION_STEP);
-	std::string s;
-	genColString(endRed,endGreen,endBlue,s);
-	return s;
+	ColourRGBA rgb(endRed,endGreen,endBlue);
+	return rgb.rgbString();
 }
 
 std::string ColourKeyFrameDialog::getStartValue() const
 {
-	std::string s;
-	genColString(startRed,startGreen,startBlue,s);
-	return s;
+	ColourRGBA rgb(startRed,startGreen,startBlue);
+	return rgb.rgbString();
 }
 
 void ColourKeyFrameDialog::OnComboTransition(wxCommandEvent &event)
@@ -234,10 +232,10 @@ void ColourKeyFrameDialog::updateButtonColours()
 void ColourKeyFrameDialog::set_properties()
 {
 	// begin wxGlade: ColourKeyFrameDialog::set_properties
-	SetTitle(wxTRANS("Key Frame : Colour"));
+	SetTitle(TRANS("Key Frame : Colour"));
 	comboTransition->SetSelection(-1);
-	btnStartColour->SetToolTip(wxTRANS("Colour at the start of the transtition"));
-	btnEndColour->SetToolTip(wxTRANS("Colour at end of transition"));
+	btnStartColour->SetToolTip(TRANS("Colour at the start of the transtition"));
+	btnEndColour->SetToolTip(TRANS("Colour at end of transition"));
 	// end wxGlade
 }
 
diff --git a/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp b/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp
index 5586a69..559288c 100644
--- a/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp
+++ b/src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp
@@ -42,12 +42,12 @@ StringKeyFrameDialog::StringKeyFrameDialog(wxWindow* parent, int id, const wxStr
 	wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
 {
 	// begin wxGlade: StringKeyFrameDialog::StringKeyFrameDialog
-	labelStartFrame = new wxStaticText(this, wxID_ANY, wxTRANS("Start Frame: "));
+	labelStartFrame = new wxStaticText(this, wxID_ANY, TRANS("Start Frame: "));
 	textStartFrame = new wxTextCtrl(this, ID_TEXT_START_FRAME, wxEmptyString);
-	radioFromFile = new wxRadioButton(this, ID_RADIO_FROM_FILE, wxTRANS("From File"));
+	radioFromFile = new wxRadioButton(this, ID_RADIO_FROM_FILE, TRANS("From File"));
 	textFilename = new wxTextCtrl(this, ID_TEXT_FROM_FILE, wxEmptyString);
 	btnChooseFile = new wxButton(this, wxID_OPEN, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-	radioFromTable = new wxRadioButton(this, ID_RADIO_FROM_TABLE, wxTRANS("From Table"));
+	radioFromTable = new wxRadioButton(this, ID_RADIO_FROM_TABLE, TRANS("From Table"));
 	gridStrings = new wxGrid(this, ID_GRID_STRINGS);
 	btnStringAdd = new wxButton(this, wxID_ADD, wxEmptyString);
 	btnRemove = new wxButton(this, wxID_REMOVE, wxEmptyString);
@@ -63,7 +63,7 @@ StringKeyFrameDialog::StringKeyFrameDialog(wxWindow* parent, int id, const wxStr
 	startFrameOK=filenameOK=false;
 	string s;
 	stream_cast(s,startFrame);
-	textStartFrame->SetValue(wxStr(s));
+	textStartFrame->SetValue((s));
 
 	radioFromFile->SetValue(true);
 
@@ -78,11 +78,7 @@ BEGIN_EVENT_TABLE(StringKeyFrameDialog, wxDialog)
 	EVT_TEXT(ID_TEXT_FROM_FILE, StringKeyFrameDialog::OnTextFilename)
 	EVT_BUTTON(wxID_OPEN, StringKeyFrameDialog::OnBtnChooseFile)
 	EVT_RADIOBUTTON(ID_RADIO_FROM_TABLE, StringKeyFrameDialog::OnTableRadio)
-#if wxCHECK_VERSION(2,9,0)
 	EVT_GRID_CMD_CELL_CHANGED(ID_GRID_STRINGS, StringKeyFrameDialog::OnGridCellChange)
-#else
-	EVT_GRID_CMD_CELL_CHANGE(ID_GRID_STRINGS, StringKeyFrameDialog::OnGridCellChange)
-#endif
 	EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_STRINGS, StringKeyFrameDialog::OnGridEditorShown)
 	EVT_BUTTON(wxID_ADD, StringKeyFrameDialog::OnBtnAdd)
 	EVT_BUTTON(wxID_REMOVE, StringKeyFrameDialog::OnBtnRemove)
@@ -105,8 +101,8 @@ void StringKeyFrameDialog::buildGrid()
 		gridStrings->DeleteRows(0,gridStrings->GetNumberRows());
 
 	gridStrings->AppendCols(2);
-	gridStrings->SetColLabelValue(0,wxTRANS("Frame"));
-	gridStrings->SetColLabelValue(1,wxTRANS("Value"));
+	gridStrings->SetColLabelValue(0,TRANS("Frame"));
+	gridStrings->SetColLabelValue(1,TRANS("Value"));
 
 	gridStrings->AppendRows(valueStrings.size());
 	
@@ -120,8 +116,8 @@ void StringKeyFrameDialog::buildGrid()
 		stream_cast(pos,ui+startFrame);
 
 		//set the frame-value pair
-		gridStrings->SetCellValue(ui,0,wxStr(pos));
-		gridStrings->SetCellValue(ui,1,wxStr(valueStrings[ui]));
+		gridStrings->SetCellValue(ui,0,(pos));
+		gridStrings->SetCellValue(ui,1,(valueStrings[ui]));
 	}
 	gridStrings->EndBatch();
 }
@@ -241,8 +237,8 @@ void StringKeyFrameDialog::OnGridEditorShown(wxGridEvent &event)
 void StringKeyFrameDialog::OnBtnChooseFile(wxCommandEvent &event)
 {
 	//Pop up a directory dialog, to choose the base path for the new folder
-	wxFileDialog *wxD = new wxFileDialog(this,wxTRANS("Select text file..."), wxT(""),
-		wxT(""),wxTRANS("Text files (*.txt)|*.txt;|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
+	wxFileDialog *wxD = new wxFileDialog(this,TRANS("Select text file..."), wxT(""),
+		wxT(""),TRANS("Text files (*.txt)|*.txt;|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
 
 	unsigned int res;
 	res = wxD->ShowModal();
@@ -343,22 +339,22 @@ void StringKeyFrameDialog::OnBtnRemove(wxCommandEvent &event)
 void StringKeyFrameDialog::set_properties()
 {
 	// begin wxGlade: StringKeyFrameDialog::set_properties
-	SetTitle(wxTRANS("String Keyframes"));
+	SetTitle(TRANS("String Keyframes"));
 	SetSize(wxSize(542, 412));
-	SetToolTip(wxTRANS("Frame at which to start string sequence"));
-	textStartFrame->SetToolTip(wxTRANS("Frame offset for data start"));
-	textFilename->SetToolTip(wxTRANS("File to use as string data source, one value per row"));
-	btnChooseFile->SetToolTip(wxTRANS("Select file to use as data source"));
-	radioFromTable->SetToolTip(wxTRANS("Use table below for data source"));
+	SetToolTip(TRANS("Frame at which to start string sequence"));
+	textStartFrame->SetToolTip(TRANS("Frame offset for data start"));
+	textFilename->SetToolTip(TRANS("File to use as string data source, one value per row"));
+	btnChooseFile->SetToolTip(TRANS("Select file to use as data source"));
+	radioFromTable->SetToolTip(TRANS("Use table below for data source"));
 	gridStrings->CreateGrid(0, 2);
-	gridStrings->SetColLabelValue(0, wxTRANS("Frame"));
+	gridStrings->SetColLabelValue(0, TRANS("Frame"));
 	gridStrings->SetColSize(0, 1);
-	gridStrings->SetColLabelValue(1, wxTRANS("Value"));
+	gridStrings->SetColLabelValue(1, TRANS("Value"));
 	gridStrings->SetColSize(1, 3);
-	btnStringAdd->SetToolTip(wxTRANS("Add new data rows to table, hold shift/cmd to insert multiple rows"));
-	btnRemove->SetToolTip(wxTRANS("Remove selected strings from table"));
-	btnCancel->SetToolTip(wxTRANS("Abort value selection and return to previous window"));
-	btnOK->SetToolTip(wxTRANS("Accept data values"));
+	btnStringAdd->SetToolTip(TRANS("Add new data rows to table, hold shift/cmd to insert multiple rows"));
+	btnRemove->SetToolTip(TRANS("Remove selected strings from table"));
+	btnCancel->SetToolTip(TRANS("Abort value selection and return to previous window"));
+	btnOK->SetToolTip(TRANS("Accept data values"));
 	// end wxGlade
 }
 
diff --git a/src/gui/dialogs/autosaveDialog.cpp b/src/gui/dialogs/autosaveDialog.cpp
index b358920..0ed075c 100644
--- a/src/gui/dialogs/autosaveDialog.cpp
+++ b/src/gui/dialogs/autosaveDialog.cpp
@@ -36,7 +36,7 @@ AutosaveDialog::AutosaveDialog(wxWindow* parent, int id, const wxString& title,
     // begin wxGlade: AutosaveDialog::AutosaveDialog
     const wxString *listStates_choices = NULL;
     listStates = new wxListBox(this, ID_LIST_STATES, wxDefaultPosition, wxDefaultSize, 0, listStates_choices, wxLB_SINGLE|wxLB_NEEDED_SB);
-    btnRemoveAll = new wxButton(this, ID_REMOVE_ALL, wxTRANS("Remove &All"));
+    btnRemoveAll = new wxButton(this, ID_REMOVE_ALL, TRANS("Remove &All"));
     btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString);
     btnOK = new wxButton(this, wxID_OK, wxEmptyString);
 
@@ -114,13 +114,13 @@ void AutosaveDialog::OnOK(wxCommandEvent &event)
 void AutosaveDialog::setItems( const std::vector<std::string> &newItems)
 {
 	for(size_t ui=0;ui<newItems.size();ui++)
-		listStates->Insert(wxStr(newItems[ui]),ui);
+		listStates->Insert((newItems[ui]),ui);
 }
 
 void AutosaveDialog::set_properties()
 {
     // begin wxGlade: AutosaveDialog::set_properties
-    SetTitle(wxTRANS("Restore state?"));
+    SetTitle(TRANS("Restore state?"));
     // end wxGlade
 }
 
@@ -130,7 +130,7 @@ void AutosaveDialog::do_layout()
     // begin wxGlade: AutosaveDialog::do_layout
     wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL);
-    wxStaticText* labelHeader = new wxStaticText(this, wxID_ANY, wxTRANS("Multiple autosave states were found; would you like to restore one?"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+    wxStaticText* labelHeader = new wxStaticText(this, wxID_ANY, TRANS("Multiple autosave states were found; would you like to restore one?"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
     sizer_1->Add(labelHeader, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 8);
     sizer_1->Add(listStates, 1, wxALL|wxEXPAND, 8);
     sizer_2->Add(btnRemoveAll, 0, wxLEFT|wxBOTTOM, 8);
diff --git a/src/gui/dialogs/filterErrorDialog.cpp b/src/gui/dialogs/filterErrorDialog.cpp
index c4ac665..0b8b192 100644
--- a/src/gui/dialogs/filterErrorDialog.cpp
+++ b/src/gui/dialogs/filterErrorDialog.cpp
@@ -34,12 +34,12 @@ FilterErrorDialog::FilterErrorDialog(wxWindow* parent, int id, const wxString& t
     // begin wxGlade: FilterErrorDialog::FilterErrorDialog
     textErrorMessage = new wxTextCtrl(this, wxID_ANY, wxEmptyString,wxDefaultPosition,wxDefaultSize,wxTE_MULTILINE|wxTE_READONLY);
     bitmapError = new wxStaticBitmap(this, wxID_ANY, wxArtProvider::GetBitmap(wxART_ERROR));
-    labelError = new wxStaticText(this, wxID_ANY, wxTRANS("Error"));
+    labelError = new wxStaticText(this, wxID_ANY, TRANS("Error"));
     bitmapWarning = new wxStaticBitmap(this, wxID_ANY,wxArtProvider::GetBitmap(wxART_WARNING));
-    labelWarning = new wxStaticText(this, wxID_ANY, wxTRANS("Warning"));
+    labelWarning = new wxStaticText(this, wxID_ANY, TRANS("Warning"));
     btnOK = new wxButton(this, wxID_OK, wxEmptyString);
 
-    SetTitle(wxTRANS("Filter Errors"));
+    SetTitle(TRANS("Filter Errors"));
     set_properties();
     do_layout();
     // end wxGlade
@@ -49,7 +49,7 @@ FilterErrorDialog::FilterErrorDialog(wxWindow* parent, int id, const wxString& t
 void FilterErrorDialog::set_properties()
 {
     // begin wxGlade: FilterErrorDialog::set_properties
-    SetTitle(wxTRANS("Filter Errors"));
+    SetTitle(TRANS("Filter Errors"));
     SetSize(wxSize(551, 414));
     // end wxGlade
 }
@@ -65,7 +65,7 @@ void FilterErrorDialog::SetText(const std::vector<string> &text)
 	}
 
 	textErrorMessage->Clear();
-	textErrorMessage->AppendText(wxStr(bigMessage));
+	textErrorMessage->AppendText((bigMessage));
 }
 
 void FilterErrorDialog::do_layout()
diff --git a/src/gui/dialogs/prefDialog.cpp b/src/gui/dialogs/prefDialog.cpp
index 066381c..e482e79 100644
--- a/src/gui/dialogs/prefDialog.cpp
+++ b/src/gui/dialogs/prefDialog.cpp
@@ -26,6 +26,7 @@
 
 #include "wx/wxcommon.h"
 #include "wx/wxcomponents.h"
+#include "wx/propertyGridUpdater.h"
 
 #include <wx/colordlg.h>
 
@@ -69,47 +70,43 @@ PrefDialog::PrefDialog(wxWindow* parent, int id, const wxString& title, const wx
     notePrefPanels_pane_3 = new wxPanel(notePrefPanels, wxID_ANY);
 	panelStartup = new wxPanel(notePrefPanels, wxID_ANY);
 	panelFilters = new wxPanel(notePrefPanels, wxID_ANY);
-	sizer_2_staticbox = new wxStaticBox(panelStartup, -1, wxTRANS("Panel Display"));
+	sizer_2_staticbox = new wxStaticBox(panelStartup, -1, TRANS("Panel Display"));
 #ifndef DISABLE_ONLINE_UPDATE
-	updateSizer_staticbox = new wxStaticBox(panelStartup, -1, wxTRANS("Online Updates"));
+	updateSizer_staticbox = new wxStaticBox(panelStartup, -1, TRANS("Online Updates"));
 #endif
-    	sizer_7_staticbox = new wxStaticBox(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Startup"));
-    	sizerCamSpeed_staticbox = new wxStaticBox(notePrefPanels_pane_3, -1, wxTRANS("Camera Speed"));
-	filterPropSizer_staticbox = new wxStaticBox(panelFilters, -1, wxTRANS("Filter Defaults"));
-	lblFilters = new wxStaticText(panelFilters, wxID_ANY, wxTRANS("Available Filters"));
+    	sizer_7_staticbox = new wxStaticBox(notePrefPanels_pane_3, wxID_ANY, TRANS("Startup"));
+    	sizerCamSpeed_staticbox = new wxStaticBox(notePrefPanels_pane_3, -1, TRANS("Camera Speed"));
+	lblFilters = new wxStaticText(panelFilters, wxID_ANY, TRANS("Available Filters"));
 	listFilters = new wxListBox(panelFilters, ID_LIST_FILTERS, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_SINGLE|wxLB_SORT);
-	filterGridProperties = new wxCustomPropGrid(panelFilters, ID_GRID_PROPERTIES);
-	filterBtnResetAllFilters = new wxButton(panelFilters, ID_BTN_RESET_FILTER_ALL, wxTRANS("Reset All"));
-	filterResetDefaultFilter = new wxButton(panelFilters, ID_BTN_RESET_FILTER, wxTRANS("Reset"));
+	filterGridProperties =new wxPropertyGrid(panelFilters, ID_GRID_PROPERTIES,
+						wxDefaultPosition,wxDefaultSize,PROPERTY_GRID_STYLE);
+	filterGridProperties->SetExtraStyle(PROPERTY_GRID_EXTRA_STYLE);
+	filterBtnResetAllFilters = new wxButton(panelFilters, ID_BTN_RESET_FILTER_ALL, TRANS("Reset All"));
+	filterResetDefaultFilter = new wxButton(panelFilters, ID_BTN_RESET_FILTER, TRANS("Reset"));
 	const wxString comboPanelStartMode_choices[] = {
-		wxNTRANS("Show all panels"),
-		wxNTRANS("Remember last"),
-		wxNTRANS("Show Selected")
+		NTRANS("Show all panels"),
+		NTRANS("Remember last"),
+		NTRANS("Show Selected")
 	};
 	comboPanelStartMode = new wxComboBox(panelStartup, ID_START_COMBO_PANEL, wxT(""), wxDefaultPosition, wxDefaultSize, 3, comboPanelStartMode_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY);
-	chkControl = new wxCheckBox(panelStartup, ID_START_CHECK_CONTROL, wxTRANS("Control Pane"));
-	chkRawData = new wxCheckBox(panelStartup, ID_START_CHECK_RAWDATA, wxTRANS("Raw Data Panel"));
-	chkPlotlist = new wxCheckBox(panelStartup, ID_START_CHECK_PLOTLIST, wxTRANS("Plot List"));
+	chkControl = new wxCheckBox(panelStartup, ID_START_CHECK_CONTROL, TRANS("Control Pane"));
+	chkRawData = new wxCheckBox(panelStartup, ID_START_CHECK_RAWDATA, TRANS("Raw Data Panel"));
+	chkPlotlist = new wxCheckBox(panelStartup, ID_START_CHECK_PLOTLIST, TRANS("Plot List"));
 #ifndef DISABLE_ONLINE_UPDATE
-	checkAllowOnlineUpdate = new wxCheckBox(panelStartup, wxID_ANY, wxTRANS("Periodically notify about available updates"));
+	checkAllowOnlineUpdate = new wxCheckBox(panelStartup, wxID_ANY, TRANS("Periodically notify about available updates"));
 #endif
-    	chkPreferOrtho = new wxCheckBox(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Prefer orthographic at startup"));
-	lblMoveSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Move Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
-	labelSlowCamMoveRate = new wxStaticText(notePrefPanels_pane_3,wxID_ANY, wxTRANS("(slow)"));
+    	chkPreferOrtho = new wxCheckBox(notePrefPanels_pane_3, wxID_ANY, TRANS("Prefer orthographic at startup"));
+	lblMoveSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, TRANS("Move Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+	labelSlowCamMoveRate = new wxStaticText(notePrefPanels_pane_3,wxID_ANY, TRANS("(slow)"));
 	sliderCamMoveRate = new wxSlider(notePrefPanels_pane_3, ID_MOUSE_MOVE_SLIDER, 25, 1, 400,wxDefaultPosition,wxDefaultSize,wxSL_HORIZONTAL|wxSL_LABELS);
-	labelFastCamMoveRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(fast)"));
-	lblZoomSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("Zoom Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
-	labelSlowCamZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(slow)"));
+	labelFastCamMoveRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, TRANS("(fast)"));
+	lblZoomSpeed = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, TRANS("Zoom Rate"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+	labelSlowCamZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, TRANS("(slow)"));
 	sliderCamZoomRate = new wxSlider(notePrefPanels_pane_3, ID_MOUSE_ZOOM_SLIDER, 25, 1, 400,wxDefaultPosition,wxDefaultSize,wxSL_HORIZONTAL|wxSL_LABELS);
-	labelSlowFastZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, wxTRANS("(fast)"));
+	labelSlowFastZoomRate = new wxStaticText(notePrefPanels_pane_3, wxID_ANY, TRANS("(fast)"));
 	btnOK = new wxButton(this, wxID_OK, wxEmptyString);
 	btnCancel = new wxButton(this, wxID_CANCEL, wxEmptyString);
 
-	filterGridProperties->CreateGrid(0, 2);
-	filterGridProperties->EnableDragRowSize(false);
-	filterGridProperties->SetColLabelValue(0, wxTRANS("Param"));
-	filterGridProperties->SetColLabelValue(1, wxTRANS("Value"));
-
 	bool enable=(comboPanelStartMode->GetSelection()  == STARTUP_COMBO_SELECT_SPECIFY);
 
 	chkRawData->Enable(enable);
@@ -120,6 +117,8 @@ PrefDialog::PrefDialog(wxWindow* parent, int id, const wxString& title, const wx
 	programmaticEvent=false;
 	curFilter=0;
 
+	backFilterPropGrid=0;
+
 	set_properties();
 	do_layout();
 	// end wxGlade
@@ -133,18 +132,14 @@ PrefDialog::~PrefDialog()
 BEGIN_EVENT_TABLE(PrefDialog, wxDialog)
     // begin wxGlade: PrefDialog::event_table
     EVT_LISTBOX(ID_LIST_FILTERS, PrefDialog::OnFilterListClick)
-#if wxCHECK_VERSION(2,9,0)
-    EVT_GRID_CMD_CELL_CHANGED(ID_GRID_PROPERTIES, PrefDialog::OnFilterCellChange)
-#else
-    EVT_GRID_CMD_CELL_CHANGE(ID_GRID_PROPERTIES, PrefDialog::OnFilterCellChange)
-#endif
-    EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_PROPERTIES,PrefDialog::OnFilterGridCellEditorShow)
+    EVT_PG_CHANGING(ID_GRID_PROPERTIES, PrefDialog::OnFilterCellChange)
     EVT_BUTTON(ID_BTN_RESET_FILTER,PrefDialog::OnResetFilterButton)
     EVT_BUTTON(ID_BTN_RESET_FILTER_ALL,PrefDialog::OnResetFilterAllButton)
     EVT_COMBOBOX(ID_START_COMBO_PANEL, PrefDialog::OnStartupPanelCombo)
     EVT_CHECKBOX(ID_CHECK_PREFER_ORTHO, PrefDialog::OnCheckPreferOrtho)
     EVT_COMMAND_SCROLL(ID_MOUSE_ZOOM_SLIDER, PrefDialog::OnMouseZoomSlider)
     EVT_COMMAND_SCROLL(ID_MOUSE_MOVE_SLIDER, PrefDialog::OnMouseMoveSlider)
+    EVT_IDLE(PrefDialog::OnIdle)
     // end wxGlade
 END_EVENT_TABLE();
 
@@ -157,7 +152,7 @@ void PrefDialog::createFilterListing()
 	vector<size_t> v;
 	for(size_t ui=0;ui<filterDefaults.size();ui++)
 	{
-		s=wxStr(filterDefaults[ui]->typeString());
+		s=(filterDefaults[ui]->typeString());
 		v.push_back(filterDefaults[ui]->getType());
 		listFilters->Append(s);
 	}
@@ -172,7 +167,7 @@ void PrefDialog::createFilterListing()
 			//This is a bit of a hack, but it works.
 			Filter *t;
 			t=makeFilter(ui);
-			s = wxStr(t->typeString());
+			s = (t->typeString());
 			listFilters->Append(s);
 			delete t;
 		}
@@ -224,6 +219,19 @@ void PrefDialog::setFilterDefaults(const vector<Filter *> &defs)
 		filterDefaults[ui]=defs[ui]->cloneUncached();
 }
 
+
+void PrefDialog::OnIdle(wxIdleEvent &evt)
+{
+	//This is required due to a bug in wx's propertygrid
+	// see wx bug #16222
+	if(backFilterPropGrid)
+	{
+		delete backFilterPropGrid;
+		backFilterPropGrid=0;
+	
+	}
+}
+
 void PrefDialog::OnFilterListClick(wxCommandEvent &event)
 {
 
@@ -259,8 +267,9 @@ void PrefDialog::OnFilterListClick(wxCommandEvent &event)
 }
 
 
-void PrefDialog::OnFilterCellChange(wxGridEvent &event)
+void PrefDialog::OnFilterCellChange(wxPropertyGridEvent &event)
 {
+	event.SetValidationFailureBehavior(0);
 	//Disallow programmatic event from causing filter update (stack loop->overflow)
 	if(programmaticEvent)
 	{
@@ -269,102 +278,33 @@ void PrefDialog::OnFilterCellChange(wxGridEvent &event)
 	}
 
 	//Grab the changed value	
-	std::string value; 
-	int row=event.GetRow();
-	value = stlStr(filterGridProperties->GetCellValue(
-					row,1));
-	programmaticEvent=true;
+	std::string value,keyStr; 
+	value = getPropValueFromEvent(event);
+	
+	size_t key;
+	keyStr=event.GetProperty()->GetName();
+	stream_cast(key,keyStr);
 
 	bool needUpdate;
-	curFilter->setProperty(filterGridProperties->getKeyFromRow(row),
-							value,needUpdate);
+	curFilter->setProperty(key,value,needUpdate);
 
 	if(find(filterDefaults.begin(),filterDefaults.end(),
 				curFilter) == filterDefaults.end())
 		filterDefaults.push_back(curFilter);
+
+	//Build the new property grid in an aside,
+	// due to wx bug, 
+	backFilterPropGrid= new wxPropertyGrid(panelFilters,ID_GRID_PROPERTIES,
+					wxDefaultPosition,wxDefaultSize,PROPERTY_GRID_STYLE);
+	filterGridProperties->SetExtraStyle(PROPERTY_GRID_EXTRA_STYLE);
 	
+	std::swap(backFilterPropGrid,filterGridProperties);
 	updateFilterProp(curFilter);
-	programmaticEvent=false;
-}
-
-
-
-//This function modifies the properties before showing the cell content editor.T
-//This is needed only for certain data types (colours, bools) other data types are edited
-//using the default editor and modified using ::OnGridFilterPropertyChange
-void PrefDialog::OnFilterGridCellEditorShow(wxGridEvent &event)
-{
-	//Find where the event occurred (cell & property)
-	const GRID_PROPERTY *item=0;
-
-	unsigned int key;
-	key=filterGridProperties->getKeyFromRow(event.GetRow());
-
-	item=filterGridProperties->getProperty(key);
-
-	bool needUpdate;
-	switch(item->type)
-	{
-		case PROPERTY_TYPE_BOOL:
-		{
-			std::string s;
-			//Toggle the property in the grid
-			if(item->data == "0")
-				s= "1";
-			else
-				s="0";
-			curFilter->setProperty(key,s,needUpdate);
-
-			event.Veto();
-
-			updateFilterProp(curFilter);
-			break;
-		}
-		case PROPERTY_TYPE_COLOUR:
-		{
-			//Show a wxColour choose dialog. 
-			wxColourData d;
-
-			unsigned char r,g,b,a;
-			parseColString(item->data,r,g,b,a);
-
-			d.SetColour(wxColour(r,g,b,a));
-			wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d);
-						
-
-			if( colDg->ShowModal() == wxID_OK)
-			{
-				wxColour c;
-				//Change the colour
-				c=colDg->GetColourData().GetColour();
-				
-				std::string s;
-				genColString(c.Red(),c.Green(),c.Blue(),s);
-			
-				//Pass the new colour to the viscontrol system, which updates
-				//the filters	
-				curFilter->setProperty(key,s,needUpdate);
-			}
-
-			//Set the filter property
-			//Disallow direct editing of the grid cell
-			event.Veto();
-
-
-			updateFilterProp(curFilter);
-			break;
-		}	
-		case PROPERTY_TYPE_CHOICE:
-			break;
-		default:
-		//we will handle this after the user has edited the cell contents
-			break;
-	}
 
-	//Add to the modified filter defaults as needed
-	if(find(filterDefaults.begin(),filterDefaults.end(),
-				curFilter) == filterDefaults.end())
-		filterDefaults.push_back(curFilter);
+	do_filtergrid_prop_layout();
+	
+	//reforce layout code
+	programmaticEvent=false;
 }
 
 void PrefDialog::OnResetFilterButton(wxCommandEvent &evt)
@@ -431,39 +371,19 @@ void PrefDialog::updateFilterProp(const Filter *f)
 	if(!(f->canBeHazardous()))
 	{
 		filterGridProperties->Enable(true);
-		updateFilterPropertyGrid(filterGridProperties,f);
+		updateFilterPropertyGrid(filterGridProperties,f,"");
 	}
 	else
 	{
 		//If the filter is potentially hazardous,
 		//then we will disallow editing of the properties.
 		//and give a notice to that effect	
-		filterGridProperties->BeginBatch();
+		filterGridProperties->Freeze();
 		filterGridProperties->Enable(false);
-		wxGridCellAttr *readOnlyColAttr=new wxGridCellAttr;
-
-		//Empty the grid
-		//then fill it up with a note.
-		if(filterGridProperties->GetNumberCols())
-			filterGridProperties->DeleteCols(0,filterGridProperties->GetNumberCols());
-		if(filterGridProperties->GetNumberRows())
-			filterGridProperties->DeleteRows(0,filterGridProperties->GetNumberRows());
-		
-		filterGridProperties->AppendRows(1);
-		filterGridProperties->AppendCols(1);
-		filterGridProperties->AutoSizeColumn(0,true);
-		filterGridProperties->SetColAttr(0,readOnlyColAttr);
-		filterGridProperties->SetColLabelValue(0,wxTRANS("Notice"));
-
-		filterGridProperties->SetCellValue(0,0,
-			wxTRANS("For security reasons, defaults are not modifiable for this filter"));
-
-		filterGridProperties->EndBatch();
-
-		//Set the column size so you can see the message		
-		filterGridProperties->SetColSize(0, filterGridProperties->GetSize().GetWidth()
-					- filterGridProperties->GetScrollThumb(wxVERTICAL) - 15);
-		
+		filterGridProperties->Clear();
+		filterGridProperties->Append(new wxPropertyCategory(string("Not Editable for security reasons")));
+		filterGridProperties->Thaw();
+
 	}
 }
 
@@ -493,17 +413,17 @@ void PrefDialog::setStartupCheckboxEnables(unsigned int value)
 	switch(value)
 	{
 		case STARTUP_COMBO_SELECT_SHOW_ALL:
-			comboPanelStartMode->SetToolTip(wxTRANS("Show all panels when starting program"));
+			comboPanelStartMode->SetToolTip(TRANS("Show all panels when starting program"));
 			break;
 		case STARTUP_COMBO_SELECT_REMEMBER:
-			comboPanelStartMode->SetToolTip(wxTRANS("Show panels visible at last shutdown when starting program"));
+			comboPanelStartMode->SetToolTip(TRANS("Show panels visible at last shutdown when starting program"));
 			
 			chkRawData->SetValue(true);
 			chkControl->SetValue(true);
 			chkPlotlist->SetValue(true);
 			break;
 		case STARTUP_COMBO_SELECT_SPECIFY:
-			comboPanelStartMode->SetToolTip(wxTRANS("Show selected panels when starting program"));
+			comboPanelStartMode->SetToolTip(TRANS("Show selected panels when starting program"));
 			break;
 		default:
 			ASSERT(false);
@@ -552,19 +472,19 @@ void PrefDialog::OnMouseMoveSlider(wxScrollEvent &event)
 void PrefDialog::set_properties()
 {
     // begin wxGlade: PrefDialog::set_properties
-    SetTitle(wxTRANS("Preferences"));
+    SetTitle(TRANS("Preferences"));
     SetSize(wxSize(640, 487));
-    comboPanelStartMode->SetToolTip(wxTRANS("Set the method of panel layout when starting the program"));
+    comboPanelStartMode->SetToolTip(TRANS("Set the method of panel layout when starting the program"));
     comboPanelStartMode->SetSelection(0);
 #ifndef DISABLE_ONLINE_UPDATE
-    checkAllowOnlineUpdate->SetToolTip(wxTRANS("Lets the program check the internet to see if updates to the program version are available, then notifies you about updates now and again."));
+    checkAllowOnlineUpdate->SetToolTip(TRANS("Lets the program check the internet to see if updates to the program version are available, then notifies you about updates now and again."));
 #endif
-    chkPreferOrtho->SetToolTip(wxTRANS("By default, use an orthographic camera at startup. State files will override this preference."));
-    sliderCamMoveRate->SetToolTip(wxTRANS("Camera translation, orbit and swivel rates. "));
-    sliderCamZoomRate->SetToolTip(wxTRANS("Camera zooming rate."));
+    chkPreferOrtho->SetToolTip(TRANS("By default, use an orthographic camera at startup. State files will override this preference."));
+    sliderCamMoveRate->SetToolTip(TRANS("Camera translation, orbit and swivel rates. "));
+    sliderCamZoomRate->SetToolTip(TRANS("Camera zooming rate."));
 
-    filterResetDefaultFilter->SetToolTip(wxTRANS("Reset the filter initial values back to program defaults"));
-    filterBtnResetAllFilters->SetToolTip(wxTRANS("Reset all filter initial values back to program defaults"));
+    filterResetDefaultFilter->SetToolTip(TRANS("Reset the filter initial values back to program defaults"));
+    filterBtnResetAllFilters->SetToolTip(TRANS("Reset all filter initial values back to program defaults"));
     
     // end wxGlade
 }
@@ -589,22 +509,8 @@ void PrefDialog::do_layout()
 	wxStaticBoxSizer* sizer_2 = new wxStaticBoxSizer(sizer_2_staticbox, wxVERTICAL);
 	wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL);
 	wxBoxSizer* sizer_4 = new wxBoxSizer(wxVERTICAL);
-    filterPropSizer_staticbox->Lower();
-	wxStaticBoxSizer* filterPropSizer = new wxStaticBoxSizer(filterPropSizer_staticbox, wxHORIZONTAL);
-	wxBoxSizer* filterRightSideSizer = new wxBoxSizer(wxVERTICAL);
-	wxBoxSizer* resetButtonSizer = new wxBoxSizer(wxHORIZONTAL);
-	wxBoxSizer* filterLeftSizer = new wxBoxSizer(wxVERTICAL);
-	filterLeftSizer->Add(lblFilters, 0, 0, 0);
-	filterLeftSizer->Add(listFilters, 1, wxEXPAND, 0);
-	filterPropSizer->Add(filterLeftSizer, 1, wxEXPAND, 0);
-	filterPropSizer->Add(20, 20, 0, 0, 0);
-	filterRightSideSizer->Add(filterGridProperties, 1, wxEXPAND, 0);
-	resetButtonSizer->Add(filterBtnResetAllFilters, 0, 0, 0);
-	resetButtonSizer->Add(filterResetDefaultFilter, 0, 0, 0);
-	resetButtonSizer->Add(20, 20, 1, 0, 0);
-	filterRightSideSizer->Add(resetButtonSizer, 0, wxEXPAND, 0);
-	filterPropSizer->Add(filterRightSideSizer, 2, wxEXPAND, 0);
-	panelFilters->SetSizer(filterPropSizer);
+	do_filtergrid_prop_layout();
+//	filterPropSizer_staticbox->Lower();
 #if defined(__WIN32) || defined(__WIN64)
 	sizer_2->Add(comboPanelStartMode, 0, wxBOTTOM|wxFIXED_MINSIZE, 4);
 #else
@@ -650,9 +556,9 @@ void PrefDialog::do_layout()
 	sizerCamSpeed->AddStretchSpacer();
     sizer_5->Add(sizerCamSpeed, 1, wxEXPAND, 0);
     notePrefPanels_pane_3->SetSizer(sizer_5);
-	notePrefPanels->AddPage(panelFilters, wxTRANS("Pref"));
-	notePrefPanels->AddPage(panelStartup, wxTRANS("Startup"));
-	notePrefPanels->AddPage(notePrefPanels_pane_3, wxTRANS("Camera"));
+	notePrefPanels->AddPage(panelFilters, TRANS("Filt. Default"));
+	notePrefPanels->AddPage(panelStartup, TRANS("Startup"));
+	notePrefPanels->AddPage(notePrefPanels_pane_3, TRANS("Camera"));
 	panelSizer->Add(notePrefPanels, 2, wxEXPAND, 0);
 	exitButtonSizer->Add(20, 20, 1, wxEXPAND, 0);
 	exitButtonSizer->Add(btnOK, 0, wxTOP, 8);
@@ -664,3 +570,27 @@ void PrefDialog::do_layout()
 	// end wxGlade
 }
 
+void PrefDialog::do_filtergrid_prop_layout()
+{
+	panelFilters->SetSizer(NULL);
+	wxBoxSizer* filterPropSizer = new wxBoxSizer(wxHORIZONTAL);
+	wxBoxSizer* filterRightSideSizer = new wxBoxSizer(wxVERTICAL);
+	wxBoxSizer* resetButtonSizer = new wxBoxSizer(wxHORIZONTAL);
+	wxBoxSizer* filterLeftSizer = new wxBoxSizer(wxVERTICAL);
+	
+	filterLeftSizer->Add(lblFilters, 0, 0, 0);
+	filterLeftSizer->Add(listFilters, 1, wxEXPAND, 0);
+	filterPropSizer->Add(filterLeftSizer, 1, wxEXPAND, 0);
+	filterPropSizer->Add(20, 20, 0, 0, 0);
+	filterRightSideSizer->Add(filterGridProperties, 1, wxEXPAND, 0);
+	resetButtonSizer->Add(filterBtnResetAllFilters, 0, 0, 0);
+	resetButtonSizer->Add(filterResetDefaultFilter, 0, 0, 0);
+	resetButtonSizer->Add(20, 20, 1, 0, 0);
+	filterRightSideSizer->Add(resetButtonSizer, 0, wxEXPAND, 0);
+	filterPropSizer->Add(filterRightSideSizer, 2, wxEXPAND, 0);
+	panelFilters->SetSizer(filterPropSizer);
+
+	panelFilters->Fit();
+	panelFilters->Layout();
+}
+
diff --git a/src/gui/dialogs/prefDialog.h b/src/gui/dialogs/prefDialog.h
index a219f12..6991786 100644
--- a/src/gui/dialogs/prefDialog.h
+++ b/src/gui/dialogs/prefDialog.h
@@ -73,7 +73,7 @@ protected:
     wxStaticBox* filterPropSizer_staticbox;
     wxStaticText* lblFilters;
     wxListBox* listFilters;
-    wxCustomPropGrid* filterGridProperties;
+    wxPropertyGrid* filterGridProperties,*backFilterPropGrid;
     wxButton* filterBtnResetAllFilters;
     wxButton* filterResetDefaultFilter;
     wxPanel* panelFilters;
@@ -107,11 +107,11 @@ public:
 	// end wxGlade
 	PrefDialog(wxWindow* parent, int id=wxID_ANY, const wxString& title=wxT("Preferences"), const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER);
 	virtual ~PrefDialog();
-	virtual void OnFilterCellChange(wxGridEvent &event); // wxGlade: <event_handler>
+	virtual void OnFilterCellChange(wxPropertyGridEvent &event); // wxGlade: <event_handler>
 	virtual void OnFilterListClick(wxCommandEvent &event); // wxGlade: <event_handler>
-	virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // wxGlade: <event_handler>
 	virtual void OnResetFilterButton(wxCommandEvent &event); // wxGlade: <event_handler>
 	virtual void OnResetFilterAllButton(wxCommandEvent &event); // wxGlade: <event_handler>
+	virtual void OnIdle(wxIdleEvent &evt);
 
 	//set the filter defaults. note that the incoming pointers are cloned, and control is NOT transferred to this class
 	void setFilterDefaults(const std::vector<Filter * > &defs);
@@ -141,6 +141,9 @@ public:
 	void OnMouseMoveSlider(wxScrollEvent &event);
 	void OnMouseZoomSlider(wxScrollEvent &event);
 
+    	//Force a re-layout of the filter property grid
+	void do_filtergrid_prop_layout();
+
 	void initialise();
 	void cleanup();
 }; // wxGlade: end class
diff --git a/src/gui/dialogs/rangeEditDialog.cpp b/src/gui/dialogs/rangeEditDialog.cpp
index 87426f9..f865e91 100644
--- a/src/gui/dialogs/rangeEditDialog.cpp
+++ b/src/gui/dialogs/rangeEditDialog.cpp
@@ -215,7 +215,7 @@ RangeEditorDialog::RangeEditorDialog(wxWindow* parent, int id, const wxString& t
     gridRanges = new wxGrid(noteLeftRanges, ID_GRID_RANGES);
     btnRangeIonAdd = new wxButton(noteLeftRanges,wxID_ADD, wxEmptyString);
     btnRangeIonRemove = new wxButton(noteLeftRanges, wxID_REMOVE, wxEmptyString);
-    checkShowOverlay = new wxCheckBox(noteLeftOverlay, ID_CHECK_SHOW_OVERLAY, wxTRANS("Show Overlays"));
+    checkShowOverlay = new wxCheckBox(noteLeftOverlay, ID_CHECK_SHOW_OVERLAY, TRANS("Show Overlays"));
     textOverlayCmpnt = new wxTextCtrl(noteLeftOverlay, ID_TEXT_FILTER_CMPNT, wxEmptyString,
     						wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER);
     listOverlay = new wxCheckListBox(noteLeftOverlay, ID_LIST_OVERLAY, wxDefaultPosition, wxDefaultSize, 0);
@@ -240,26 +240,16 @@ RangeEditorDialog::RangeEditorDialog(wxWindow* parent, int id, const wxString& t
     checkShowOverlay->SetValue(true);
 
     haveSetTextFocus=false;
-    textOverlayCmpnt->SetValue(wxTRANS("e.g. H2O"));
+    textOverlayCmpnt->SetValue(TRANS("e.g. H2O"));
 
-#if wxCHECK_VERSION(2, 9, 0)
     textOverlayCmpnt->Bind(wxEVT_SET_FOCUS, &RangeEditorDialog::OnTextOverlaySetFocus, this);
-#else
-    textOverlayCmpnt->Connect(wxID_ANY,
-                 wxEVT_SET_FOCUS,
-		   wxFocusEventHandler(RangeEditorDialog::OnTextOverlaySetFocus), NULL, this);
-#endif
 }
 
 
 
 RangeEditorDialog::~RangeEditorDialog()
 {
-#if wxCHECK_VERSION(2, 9, 0)
     textOverlayCmpnt->Unbind(wxEVT_SET_FOCUS, &RangeEditorDialog::OnTextOverlaySetFocus, this);
-#else
-    textOverlayCmpnt->Disconnect();
-#endif
 }
 
 
@@ -272,13 +262,8 @@ BEGIN_EVENT_TABLE(RangeEditorDialog, wxDialog)
     EVT_TEXT(ID_TEXT_FILTER_CMPNT,RangeEditorDialog::OnTextOverlay)
     EVT_TEXT_ENTER(ID_TEXT_FILTER_CMPNT,RangeEditorDialog::OnTextOverlayEnter)
     EVT_CHECKBOX(ID_CHECK_SHOW_OVERLAY, RangeEditorDialog::OnCheckShowOverlay)
-#if wxCHECK_VERSION(2,9,0)
     EVT_GRID_CMD_CELL_CHANGED(ID_GRID_RANGES, RangeEditorDialog::OnGridRangesCellChange)
     EVT_GRID_CMD_CELL_CHANGED(ID_GRID_IONS, RangeEditorDialog::OnGridIonsCellChange)
-#else
-    EVT_GRID_CMD_CELL_CHANGE(ID_GRID_RANGES, RangeEditorDialog::OnGridRangesCellChange)
-    EVT_GRID_CMD_CELL_CHANGE(ID_GRID_IONS, RangeEditorDialog::OnGridIonsCellChange)
-#endif
     EVT_GRID_CMD_CELL_LEFT_CLICK(ID_GRID_RANGES,RangeEditorDialog::OnGridRangeClick) 
     EVT_GRID_CMD_CELL_LEFT_CLICK(ID_GRID_IONS,RangeEditorDialog::OnGridIonClick) 
     EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_RANGES,RangeEditorDialog::OnGridRangesEditorShown)
@@ -288,7 +273,7 @@ BEGIN_EVENT_TABLE(RangeEditorDialog, wxDialog)
     EVT_CHECKLISTBOX(ID_LIST_OVERLAY, RangeEditorDialog::OnListOverlayCheck)
     EVT_BUTTON(wxID_OK, RangeEditorDialog::OnBtnOK)
     EVT_BUTTON(wxID_CANCEL, RangeEditorDialog::OnBtnCancel)
-    EVT_SPLITTER_UNSPLIT(ID_SPLIT_LEFTRIGHT, RangeEditorDialog::OnSashVerticalUnsplit)
+    EVT_SPLITTER_DCLICK(ID_SPLIT_LEFTRIGHT, RangeEditorDialog::OnSashVerticalDClick)
     // end wxGlade
 END_EVENT_TABLE();
 
@@ -518,7 +503,7 @@ void RangeEditorDialog::generateListEntries()
 		unsigned int plotID;
 		plotID = plotIDs[ui];
 
-		std::wstring title;
+		std::string title;
 		title=plotWrap.getTitle(plotID);
 
 		//Only use plots from spectra
@@ -528,7 +513,7 @@ void RangeEditorDialog::generateListEntries()
 		//Append the plot to the list in the user interface,
 		// with the plot Id embeded in the element
 		int idx;
-		idx=listPlots->Append(wxStr(title));
+		idx=listPlots->Append((title));
 		listToPlotIDs[idx]=plotIDs[ui];
 	}
 
@@ -549,7 +534,7 @@ void RangeEditorDialog::generateOverlayList(const vector<OVERLAY_DATA> &overlays
 
 	for(size_t ui=0;ui<overlays.size();ui++)
 	{
-		listOverlay->Insert(wxStr(overlays[ui].title),ui);
+		listOverlay->Insert((overlays[ui].title),ui);
 		listOverlay->Check(ui,overlays[ui].enabled);
 	}
 
@@ -572,10 +557,10 @@ void RangeEditorDialog::generateIonEntries(size_t rowVisibleHint)
 		gridIons->DeleteRows(0,gridIons->GetNumberRows());
 	
 	gridIons->AppendCols(4);
-	gridIons->SetColLabelValue(ION_COL_PLOT,wxTRANS("Plot"));
-	gridIons->SetColLabelValue(ION_COL_SHORTNAME,wxTRANS("Short Name"));
-	gridIons->SetColLabelValue(ION_COL_LONGNAME,wxTRANS("Long Name"));
-	gridIons->SetColLabelValue(ION_COL_COLOUR,wxTRANS("Colour"));
+	gridIons->SetColLabelValue(ION_COL_PLOT,TRANS("Plot"));
+	gridIons->SetColLabelValue(ION_COL_SHORTNAME,TRANS("Short Name"));
+	gridIons->SetColLabelValue(ION_COL_LONGNAME,TRANS("Long Name"));
+	gridIons->SetColLabelValue(ION_COL_COLOUR,TRANS("Colour"));
 	//--
 	
 	
@@ -594,7 +579,7 @@ void RangeEditorDialog::generateIonEntries(size_t rowVisibleHint)
 	}
 	
 	
-	std::wstring title;
+	std::string title;
 	title=plotWrap.getTitle(curPlot);
 
 	//Colour to  use for incomplete ions/ranges
@@ -613,12 +598,12 @@ void RangeEditorDialog::generateIonEntries(size_t rowVisibleHint)
 		gridIonIds[uj]=curIonRow;
 
 		gridIons->SetCellValue(curIonRow,
-				ION_COL_PLOT,wxStr(title));
+				ION_COL_PLOT,(title));
 
 		gridIons->SetCellValue(curIonRow,
-				ION_COL_SHORTNAME,wxStr(currentRange->getName(uj)));
+				ION_COL_SHORTNAME,(currentRange->getName(uj)));
 		gridIons->SetCellValue(curIonRow,
-				ION_COL_LONGNAME,wxStr(currentRange->getName(uj,false)));
+				ION_COL_LONGNAME,(currentRange->getName(uj,false)));
 		
 		//set the colour
 		wxGridCellAttr *attr = gridIons->GetOrCreateCellAttr(curIonRow,ION_COL_COLOUR);
@@ -641,12 +626,12 @@ void RangeEditorDialog::generateIonEntries(size_t rowVisibleHint)
 	for(size_t ui=0;ui<incompleteIons.size();ui++)
 	{
 		gridIons->SetCellValue(curIonRow,
-				ION_COL_PLOT,wxStr(title));
+				ION_COL_PLOT,(title));
 
 		gridIons->SetCellValue(curIonRow,
-				ION_COL_SHORTNAME,wxStr(incompleteIons[ui].getShortName()));
+				ION_COL_SHORTNAME,(incompleteIons[ui].getShortName()));
 		gridIons->SetCellValue(curIonRow,
-				ION_COL_LONGNAME,wxStr(incompleteIons[ui].getLongName()));
+				ION_COL_LONGNAME,(incompleteIons[ui].getLongName()));
 		
 		//set the colour
 		wxGridCellAttr *attr = gridIons->GetOrCreateCellAttr(curIonRow,ION_COL_COLOUR);
@@ -706,10 +691,10 @@ void RangeEditorDialog::generateRangeEntries(size_t rowVisibleHint)
 		gridRanges->DeleteRows(0,gridRanges->GetNumberRows());
 	
 	gridRanges->AppendCols(4);
-	gridRanges->SetColLabelValue(0,wxTRANS("Plot"));
-	gridRanges->SetColLabelValue(1,wxTRANS("Ion"));
-	gridRanges->SetColLabelValue(2,wxTRANS("Start"));
-	gridRanges->SetColLabelValue(3,wxTRANS("End"));
+	gridRanges->SetColLabelValue(0,TRANS("Plot"));
+	gridRanges->SetColLabelValue(1,TRANS("Ion"));
+	gridRanges->SetColLabelValue(2,TRANS("Start"));
+	gridRanges->SetColLabelValue(3,TRANS("End"));
 	//---
 
 	gridRangeIds.clear();
@@ -730,7 +715,7 @@ void RangeEditorDialog::generateRangeEntries(size_t rowVisibleHint)
 	wxColour incomplColour;
 	//A light blue colour
 	incomplColour.Set(162,162,255);
-	std::wstring title;
+	std::string title;
 	title=plotWrap.getTitle(curPlot);
 	
 	//Fill in the range grid
@@ -745,14 +730,14 @@ void RangeEditorDialog::generateRangeEntries(size_t rowVisibleHint)
 		std::string ionName;
 		ionName=currentRange->getName(currentRange->getIonID((unsigned int)ui));
 
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_PLOT,wxStr(title));
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_PARENT_ION,wxStr(ionName));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_PLOT,(title));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_PARENT_ION,(ionName));
 
 		std::string tmpStr;
 		stream_cast(tmpStr,rangeBound.first);
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_START,wxStr(tmpStr));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_START,(tmpStr));
 		stream_cast(tmpStr,rangeBound.second);
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_END,wxStr(tmpStr));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_END,(tmpStr));
 
 		curRangeRow++;
 	}
@@ -769,14 +754,14 @@ void RangeEditorDialog::generateRangeEntries(size_t rowVisibleHint)
 		std::string ionName;
 		ionName=incompleteRanges[ui].getIonName();
 
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_PLOT,wxStr(title));
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_PARENT_ION,wxStr(ionName));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_PLOT,(title));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_PARENT_ION,(ionName));
 
 		std::string tmpStr;
 		stream_cast(tmpStr,incompleteRanges[ui].getStart());
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_START,wxStr(tmpStr));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_START,(tmpStr));
 		stream_cast(tmpStr,incompleteRanges[ui].getEnd());
-		gridRanges->SetCellValue(curRangeRow,RNG_COL_END,wxStr(tmpStr));
+		gridRanges->SetCellValue(curRangeRow,RNG_COL_END,(tmpStr));
 
 		for(size_t uj=0;uj<RNG_COL_ENUM_END; uj++)
 			gridRanges->SetCellBackgroundColour(curRangeRow,uj,incomplColour);
@@ -1268,16 +1253,11 @@ void RangeEditorDialog::OnBtnRangeIonAdd(wxCommandEvent &event)
 		!gridRanges->GetNumberRows() || !gridIons->GetNumberRows())
 	{
 		wxArrayString wxStrs;
-		wxStrs.Add(wxCStr("Ion"));
-		wxStrs.Add(wxCStr("Range"));
-
-#if wxCHECK_VERSION(2, 9, 0)
-		wxSingleChoiceDialog *wxD = new wxSingleChoiceDialog(this, wxTRANS("Range or ion?"),
-				wxTRANS("Select type to add"),wxStrs,(void **)NULL,wxDEFAULT_DIALOG_STYLE|wxOK|wxCENTRE);
-#else
-		wxSingleChoiceDialog *wxD = new wxSingleChoiceDialog(this, wxTRANS("Range or ion?"),
-				wxTRANS("Select type to add"),wxStrs,NULL,wxDEFAULT_DIALOG_STYLE|wxOK|wxCENTRE);
-#endif
+		wxStrs.Add(("Ion"));
+		wxStrs.Add(("Range"));
+
+		wxSingleChoiceDialog *wxD = new wxSingleChoiceDialog(this, TRANS("Range or ion?"),
+				TRANS("Select type to add"),wxStrs,(void **)NULL,wxDEFAULT_DIALOG_STYLE|wxOK|wxCENTRE);
 
 		wxD->ShowModal();
 
@@ -1438,7 +1418,7 @@ void RangeEditorDialog::OnListOverlayKeyDown(wxListEvent &event)
 	plotPanel->Refresh();
 }
 
-void RangeEditorDialog::OnSashVerticalUnsplit(wxSplitterEvent &event)
+void RangeEditorDialog::OnSashVerticalDClick(wxSplitterEvent &event)
 {
 	event.Veto();
 }
@@ -1558,16 +1538,16 @@ void RangeEditorDialog::OnTextOverlayEnter(wxCommandEvent &event)
 void RangeEditorDialog::set_properties()
 {
     // begin wxGlade: RangeEditorDialog::set_properties
-    SetTitle(wxTRANS("Range Editor"));
+    SetTitle(TRANS("Range Editor"));
     gridRanges->CreateGrid(0, 3);
     gridIons->CreateGrid(0, 3);
 
-    checkShowOverlay->SetToolTip(wxTRANS("Enable or disable all overlays"));
-    listOverlay->SetToolTip(wxTRANS("Entered overlays, use delete to remove"));
-    listPlots->SetToolTip(wxTRANS("Available plots for ranging"));
-    textOverlayCmpnt->SetToolTip(wxTRANS("Enter species to display as overlay, e.g. SiO2"));
-    gridRanges->SetToolTip(wxTRANS("Editable ranges"));
-    gridIons->SetToolTip(wxTRANS("Editable ions"));
+    checkShowOverlay->SetToolTip(TRANS("Enable or disable all overlays"));
+    listOverlay->SetToolTip(TRANS("Entered overlays, use delete to remove"));
+    listPlots->SetToolTip(TRANS("Available plots for ranging"));
+    textOverlayCmpnt->SetToolTip(TRANS("Enter species to display as overlay, e.g. SiO2"));
+    gridRanges->SetToolTip(TRANS("Editable ranges"));
+    gridIons->SetToolTip(TRANS("Editable ions"));
     // end wxGlade
 }
 
@@ -1602,9 +1582,9 @@ void RangeEditorDialog::do_layout()
     sizerOverlay->Add(sizerOverlayContainer, 1, wxEXPAND, 0);
     sizerOverlayPane->Add(sizerOverlay, 1, wxEXPAND, 0);
     noteLeftOverlay->SetSizer(sizerOverlayPane);
-    notebookLeft->AddPage(noteLeftPlots, wxTRANS("Plots"));
-    notebookLeft->AddPage(noteLeftRanges, wxTRANS("Ranges"));
-    notebookLeft->AddPage(noteLeftOverlay, wxTRANS("Overlay"));
+    notebookLeft->AddPage(noteLeftPlots, TRANS("Plots"));
+    notebookLeft->AddPage(noteLeftRanges, TRANS("Ranges"));
+    notebookLeft->AddPage(noteLeftOverlay, TRANS("Overlay"));
     sizerNote->Add(notebookLeft, 1, wxEXPAND, 0);
     panelSplitLeft->SetSizer(sizerNote);
     sizerRight->Add(plotPanel, 1, wxEXPAND, 0);
diff --git a/src/gui/dialogs/rangeEditDialog.h b/src/gui/dialogs/rangeEditDialog.h
index c7a09fc..94c30ea 100644
--- a/src/gui/dialogs/rangeEditDialog.h
+++ b/src/gui/dialogs/rangeEditDialog.h
@@ -210,7 +210,7 @@ public:
     virtual void OnCheckShowOverlay(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnBtnOK(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnBtnCancel(wxCommandEvent &event); // wxGlade: <event_handler>
-    virtual void OnSashVerticalUnsplit(wxSplitterEvent &event); // wxGlade: <event_handler>
+    virtual void OnSashVerticalDClick(wxSplitterEvent &event); // wxGlade: <event_handler>
     virtual void OnListOverlayCheck(wxCommandEvent &event);
     virtual void OnListOverlayKeyDown(wxListEvent &event);
     virtual void OnTextOverlay(wxCommandEvent &event);
diff --git a/src/gui/dialogs/resolutionDialog.cpp b/src/gui/dialogs/resolutionDialog.cpp
index 6b8631b..da66edd 100644
--- a/src/gui/dialogs/resolutionDialog.cpp
+++ b/src/gui/dialogs/resolutionDialog.cpp
@@ -42,26 +42,17 @@ ResolutionDialog::ResolutionDialog(wxWindow* parent, int id, const wxString& tit
     wxDialog(parent, id, title, pos, size, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
 {
     // begin wxGlade: ResolutionDialog::ResolutionDialog
-    labelWidth = new wxStaticText(this, wxID_ANY, wxTRANS("Width :"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+    labelWidth = new wxStaticText(this, wxID_ANY, TRANS("Width :"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
     textWidth = new wxTextCtrl(this, ID_TEXT_WIDTH, wxT(""));
-    labelHeight = new wxStaticText(this, wxID_ANY, wxTRANS("Height :"));
+    labelHeight = new wxStaticText(this, wxID_ANY, TRANS("Height :"));
     textHeight = new wxTextCtrl(this, ID_TEXT_HEIGHT, wxT(""));
     static_line_2 = new wxStaticLine(this, wxID_ANY);
-    btnReset = new wxButton(this, ID_RESET, wxTRANS("Reset"));
+    btnReset = new wxButton(this, ID_RESET, TRANS("Reset"));
     btnOK = new wxButton(this, wxID_OK, wxEmptyString);
     button_2 = new wxButton(this, wxID_CANCEL, wxEmptyString);
 
-#if wxCHECK_VERSION(2, 9, 0)
     textWidth->Bind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelWidth, this);
     textHeight->Bind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelHeight, this);
-#else
-    textWidth->Connect(wxID_ANY, wxEVT_MOUSEWHEEL,
-		    wxMouseEventHandler(ResolutionDialog::OnMouseWheelWidth),NULL,this);
-    textHeight->Connect(wxID_ANY, wxEVT_MOUSEWHEEL,
-		    wxMouseEventHandler(ResolutionDialog::OnMouseWheelHeight),NULL,this);
-#endif
-
-
 
     set_properties();
     do_layout();
@@ -99,10 +90,10 @@ void ResolutionDialog::setRes(unsigned int w, unsigned int h, bool asReset)
 
 	std::string s;
 	stream_cast(s,w);
-	textWidth->SetValue(wxStr(s));
+	textWidth->SetValue((s));
 
 	stream_cast(s,h);
-	textHeight->SetValue(wxStr(s));
+	textHeight->SetValue((s));
 
 	resWidth=w;
 	resHeight=h;
@@ -136,7 +127,7 @@ void ResolutionDialog::OnTextWidth(wxCommandEvent &event)
 	if(textStr.find_first_not_of("0123456789")!=std::string::npos )
 	{
 		stream_cast(textStr,resWidth);
-		textWidth->SetValue(wxStr(textStr));
+		textWidth->SetValue((textStr));
 		programmaticEvent--;
 		return;
 	}
@@ -158,7 +149,7 @@ void ResolutionDialog::OnTextWidth(wxCommandEvent &event)
 
 	resHeight=(unsigned int)(width*aspect);
 	stream_cast(textStr,resHeight);
-	textHeight->SetValue(wxStr(textStr));
+	textHeight->SetValue((textStr));
 
 
 	updateImage();
@@ -183,7 +174,7 @@ void ResolutionDialog::OnTextHeight(wxCommandEvent &event)
 	if(textStr.find_first_not_of("0123456789")!=std::string::npos )
 	{
 		stream_cast(textStr,resHeight);
-		textHeight->SetValue(wxStr(textStr));
+		textHeight->SetValue((textStr));
 		programmaticEvent--;
 		return;
 	}
@@ -206,7 +197,7 @@ void ResolutionDialog::OnTextHeight(wxCommandEvent &event)
 
 	resWidth=(unsigned int)(height/aspect);
 	stream_cast(textStr,resWidth);
-	textWidth->SetValue(wxStr(textStr));
+	textWidth->SetValue((textStr));
 
 	updateImage();
 
@@ -268,7 +259,7 @@ void ResolutionDialog::OnMouseWheelWidth(wxMouseEvent &event)
 	std::string textStr;
 	resHeight=(unsigned int)(resWidth*aspect);
 	stream_cast(textStr,resHeight);
-	textHeight->SetValue(wxStr(textStr));
+	textHeight->SetValue((textStr));
 	
 	updateImage();
 	programmaticEvent--;
@@ -313,7 +304,7 @@ void ResolutionDialog::OnMouseWheelHeight(wxMouseEvent &event)
 	std::string textStr;
 	resWidth=(unsigned int)(resHeight/aspect);
 	stream_cast(textStr,resWidth);
-	textWidth->SetValue(wxStr(textStr));
+	textWidth->SetValue((textStr));
 
 	updateImage();
 	programmaticEvent--;
@@ -334,20 +325,15 @@ void ResolutionDialog::finishDialog()
 	//programmatic event counter should be decremented to zero
 	ASSERT(!programmaticEvent);
 
-#if wxCHECK_VERSION(2, 9, 0)
-    textWidth->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelWidth, this);
-    textHeight->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelHeight, this);
-#else
-	textWidth->Disconnect();
-	textHeight->Disconnect();
-#endif
+	textWidth->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelWidth, this);
+	textHeight->Unbind(wxEVT_MOUSEWHEEL, &ResolutionDialog::OnMouseWheelHeight, this);
 	EndModal(wxID_OK);
 }
 
 void ResolutionDialog::set_properties()
 {
     // begin wxGlade: ResolutionDialog::set_properties
-    SetTitle(wxTRANS("Resolution Selection"));
+    SetTitle(TRANS("Resolution Selection"));
     // end wxGlade
 }
 
diff --git a/src/gui/glPane.cpp b/src/gui/glPane.cpp
index 030241d..8f66c3f 100644
--- a/src/gui/glPane.cpp
+++ b/src/gui/glPane.cpp
@@ -23,7 +23,6 @@
 
 #include "common/stringFuncs.h"
 #include "gl/select.h"
-#include "gl/tr.h"
 #include "glPane.h"
 
 
@@ -67,7 +66,6 @@ EVT_RIGHT_DOWN(BasicGLPane::mouseDown)
 EVT_LEAVE_WINDOW(BasicGLPane::mouseLeftWindow)
 EVT_SIZE(BasicGLPane::resized)
 EVT_KEY_DOWN(BasicGLPane::keyPressed)
-EVT_CHAR(BasicGLPane::charEvent) 
 EVT_KEY_UP(BasicGLPane::keyReleased)
 EVT_MOUSEWHEEL(BasicGLPane::mouseWheelMoved)
 EVT_PAINT(BasicGLPane::render)
@@ -89,12 +87,7 @@ int attribList[] = {WX_GL_RGBA,
 			1,
 			0,0};
 
-BasicGLPane::BasicGLPane(wxWindow* parent) :
-#if wxCHECK_VERSION(2,9,0)
-wxGLCanvas(parent, wxID_ANY,  attribList)
-#else
-wxGLCanvas(parent, wxID_ANY,  wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas"),attribList)
-#endif
+BasicGLPane::BasicGLPane(wxWindow* parent) : wxGLCanvas(parent, wxID_ANY,  attribList)
 {
 	haveCameraUpdates=false;
 	applyingDevice=false;
@@ -102,9 +95,7 @@ wxGLCanvas(parent, wxID_ANY,  wxDefaultPosition, wxDefaultSize, 0, wxT("GLCanvas
 
 	keyDoubleTapTimer=new wxTimer(this,ID_KEYPRESS_TIMER);
 	lastKeyDoubleTap=(unsigned int)-1;
-#if wxCHECK_VERSION(2,9,0)
 	context=0;
-#endif
 
 	mouseMoveFactor=mouseZoomFactor=1.0f;	
 	dragging=false;
@@ -121,15 +112,7 @@ BasicGLPane::~BasicGLPane()
 
 bool BasicGLPane::displaySupported() const
 {
-#if wxCHECK_VERSION(2,9,0)
 	return IsDisplaySupported(attribList);
-#else
-	ASSERT(false);
-	//Lets hope so. If its not, then its just going to fail anyway. 
-	//If it is, then returning false would simply create a roadblock.
-	//Either way, you shouldn't get here.
-	return true; 
-#endif
 }
 
 void BasicGLPane::setSceneInteractionAllowed(bool enabled)
@@ -226,16 +209,6 @@ void BasicGLPane::forceRedraw()
 	wxPaintEvent ptEvent;
 	wxPostEvent(this,ptEvent);
 
-	//Hack to fix panel redraw commands not working under windows
-	//--
-#if defined(__WIN32) || defined(__WIN64)
-	wxYield();
-
-	Hide();
-	Show();
-
-#endif
-	//--
 }
 
 // some useful events to use
@@ -271,21 +244,13 @@ void BasicGLPane::mouseMoved(wxMouseEvent& event)
 		if(wxm.ShiftDown())
 			keyFlags|=FLAG_SHIFT;
 
-#if wxCHECK_VERSION(2,9,0)
 		if(wxm.LeftIsDown())
 		       	mouseFlags|= SELECT_BUTTON_LEFT;
 		if(wxm.RightIsDown())
 		       	mouseFlags|= SELECT_BUTTON_RIGHT;
 		if(wxm.MiddleIsDown())
 		       	mouseFlags|= SELECT_BUTTON_MIDDLE;
-#else
-		if(wxm.LeftDown())
-		       	mouseFlags|= SELECT_BUTTON_LEFT;
-		if(wxm.RightDown())
-		       	mouseFlags|= SELECT_BUTTON_RIGHT;
-		if(wxm.MiddleDown())
-		       	mouseFlags|= SELECT_BUTTON_MIDDLE;
-#endif
+		
 		//We can get  a mouse move event which reports no buttons before a mouse-up event,
 		//this occurs frequently under windows, but sometimes under GTK
 		if(!mouseFlags)
@@ -465,7 +430,6 @@ void BasicGLPane::mouseDown(wxMouseEvent& event)
 			Refresh();
 	}
 
-	event.Skip();
 }
 
 void BasicGLPane::mouseWheelMoved(wxMouseEvent& event) 
@@ -489,7 +453,6 @@ void BasicGLPane::mouseWheelMoved(wxMouseEvent& event)
 
 	haveCameraUpdates=true;
 	Refresh();
-	event.Skip();
 }
 
 void BasicGLPane::mouseReleased(wxMouseEvent& event) 
@@ -540,7 +503,6 @@ void BasicGLPane::mouseReleased(wxMouseEvent& event)
 	dragging=false;
 
 	Refresh();
-	event.Skip();
 	
 }
 
@@ -582,7 +544,6 @@ void BasicGLPane::mouseLeftWindow(wxMouseEvent& event)
 			dragging=false;
 		}
 	}
-	event.Skip();
 }
 
 void BasicGLPane::keyPressed(wxKeyEvent& event) 
@@ -600,11 +561,7 @@ void BasicGLPane::keyPressed(wxKeyEvent& event)
             // needs to be control in apple as cmd-space open spotlight
 			unsigned int keyMask;
 #ifdef __APPLE__
-    #if wxCHECK_VERSION(2,9,0)
 			keyMask = (event.RawControlDown() ? 1 : 0);
-    #else
-			keyMask = (event.ControlDown() ? 1 : 0);
-    #endif
 #else
 			keyMask = (event.CmdDown() ? 1 : 0);
 #endif
@@ -667,7 +624,7 @@ void BasicGLPane::keyPressed(wxKeyEvent& event)
 
 				
 				currentScene.ensureVisible(visibleDir);
-				parentStatusBar->SetStatusText(wxTRANS("Use shift/ctrl-space or double tap to alter reset axis"));
+				parentStatusBar->SetStatusText(TRANS("Use shift/ctrl-space or double tap to alter reset axis"));
 				parentStatusBar->SetBackgroundColour(*wxCYAN)
 					;
 				parentStatusTimer->Start(statusDelay,wxTIMER_ONE_SHOT);
@@ -676,8 +633,9 @@ void BasicGLPane::keyPressed(wxKeyEvent& event)
 			}
 		}
 		break;
+		default:
+			event.Skip();
 	}
-	event.Skip();
 }
 
 void BasicGLPane::setGlClearColour(float r, float g, float b)
@@ -728,24 +686,15 @@ void BasicGLPane::keyReleased(wxKeyEvent& event)
 			break;
 		}
 		default:
-		;
+			event.Skip();
 	}
 
 	Refresh();
-	event.Skip();
 }
 
-void BasicGLPane::charEvent(wxKeyEvent& event) 
-{
-
-}
- 
  
 void BasicGLPane::resized(wxSizeEvent& evt)
 {
-#if !wxCHECK_VERSION(2,9,0)
-	wxGLCanvas::OnSize(evt);
-#endif
 	prepare3DViewport(0,0,getWidth(),getHeight()); 
 	wxClientDC *dc=new wxClientDC(this);
 	Refresh();
@@ -810,15 +759,12 @@ void BasicGLPane::render( wxPaintEvent& evt )
 	if (!IsShown()) 
 		return;
 	
-#if wxCHECK_VERSION(2,9,0)
 	if(!context)
 	{
 		context = new wxGLContext(this);
 		SetCurrent(*context);
 	}
-#else
-	wxGLCanvas::SetCurrent();
-#endif
+
 	if(!paneInitialised)
 	{
 		paneInitialised=true;
@@ -848,6 +794,28 @@ void BasicGLPane::updateClearColour()
 				bClear,1.0f);
 }
 
+TRcontext *BasicGLPane::generateTileContext(unsigned int width, unsigned int height, unsigned char *imageBuffer, bool alpha) const
+{
+	int panelWidth,panelHeight;
+	GetClientSize(&panelWidth,&panelHeight);
+	
+	//Create TR library tile context
+	TRcontext *tr = trNew();
+	//Tile size
+	trTileSize(tr,panelWidth,panelHeight,0);
+	//Set overall image size
+	trImageSize(tr, width, height);
+	//Set buffer for overall image
+	if(alpha)
+		trImageBuffer(tr, GL_RGBA, GL_UNSIGNED_BYTE, imageBuffer);
+	else
+		trImageBuffer(tr, GL_RGB, GL_UNSIGNED_BYTE, imageBuffer);
+	//Set the row order for the image
+	trRowOrder(tr, TR_BOTTOM_TO_TOP);
+
+	return tr;
+}
+
 bool BasicGLPane::saveImage(unsigned int width, unsigned int height,
 		const char *filename, bool showProgress, bool needPostPaint)
 {
@@ -863,33 +831,29 @@ bool BasicGLPane::saveImage(unsigned int width, unsigned int height,
 	//create new image
 	wxImage *image = new wxImage(width,height);
 
-	//We cannot seem to draw outside the current viewport.
-	//in a cross platform manner.
-	//fall back to stitching the image together by hand
-	int panelWidth,panelHeight;
-	GetClientSize(&panelWidth,&panelHeight);
 
 	unsigned char *imageBuffer= (unsigned char*) malloc(3*(width)*height);
+	if(!imageBuffer)
+		return false;
+
 
 	glLoadIdentity();
-	//Create TR library tile context
-	TRcontext *tr = trNew();
 	const Camera *cm = currentScene.getActiveCam();
 
-	//Initialise tile data
-	{
-	//Tile size
-	trTileSize(tr,panelWidth,panelHeight,0);
-	//Set overall image size
-	trImageSize(tr, width, height);
-	//Set buffer for overall image
-	trImageBuffer(tr, GL_RGB, GL_UNSIGNED_BYTE, imageBuffer);
-	//Set the row order for the image
-	trRowOrder(tr, TR_BOTTOM_TO_TOP);
+	//We cannot seem to draw outside the current viewport.
+	//in a cross platform manner.
+	//fall back to stitching the image together by hand
 
+	//Initialise tile data
+	TRcontext *tr; 
 	//Inform the tiling system about our camera config
+	float farPlane; 
+	float aspect=currentScene.getAspect();
+	
+	{
+	tr=generateTileContext(width,height, imageBuffer);
 	BoundCube bc = currentScene.getBound();
-	float farPlane = 1.5*bc.getMaxDistanceToBox(cm->getOrigin());
+	farPlane = 1.5*bc.getMaxDistanceToBox(cm->getOrigin());
 	
 	if(cm->getProjectionMode() == PROJECTION_MODE_PERSPECTIVE)
 	{
@@ -907,69 +871,86 @@ bool BasicGLPane::saveImage(unsigned int width, unsigned int height,
 	}
 	else
 	{
-		float aspect=currentScene.getAspect();
-		float orthoScale=cm->getOrthoScale();
+		float orthoScale = cm->getOrthoScale();
 		trOrtho(tr,-orthoScale*aspect,orthoScale*aspect,
 				-orthoScale,orthoScale,0.0f,farPlane);
 
 	}
 	}
 
-
-	//Obtain tile count
-	unsigned int nRow,nCol;
+	//Obtain tile count from the renderer & init progress
+	//--
+	unsigned int totalTiles;
+	{
+	unsigned int nRow,nCol,nPass;
 	nRow=trGet(tr,TR_ROWS);
 	nCol=trGet(tr,TR_COLUMNS);
+	if(currentScene.hasOverlays())
+		nPass = 2;
+	else
+		nPass=1;
 
-	wxProgressDialog *wxD=0;	
-
+	totalTiles=nRow*nCol*nPass;
+	}
 
-	//Only show progress for multiple tiles
-	std::string tmpStr,tmpStrTwo;
-	stream_cast(tmpStrTwo,nRow*nCol);
-	
-	showProgress=showProgress && ( nRow*nCol > 1);
+	wxProgressDialog *wxD=0;	
+	showProgress=showProgress && ( totalTiles > 1);
 	if(showProgress)
 	{
-		wxD = new wxProgressDialog(wxTRANS("Image progress"), 
-					wxTRANS("Rendering tiles..."), nRow*nCol);
+		wxD = new wxProgressDialog(TRANS("Image progress"), 
+					TRANS("Rendering tiles..."), totalTiles);
 
-		wxD->Show();
 	}
+	//--
+
+
+	//We have to do two passes. First we have to
+	// do a 3D pass, then we have to separately
+	// draw the overlays.
+
+	// As we have 2 cameras, one for the normal scene
+	// and one for the overlay, we build the images,
+	// then merge the images, rather than trying to composite the entire scene in situ.
+
+	//PASS 1:
+	//--------------	
 
 	//HACK: Flip the all but scene's light z coordinate
 	// for some reason, the frustrum has an inversion
 	// somwhere in the coordinate system, and I can't find it!
 	// inverting the tile frustrum ends up with the depth test 
 	// also inverting.
+	const bool FLIP_LIGHT_HACK=true;
+	//x,y,z and w axis.
+	const bool IMPORTANT_AXIS[4]={true,false,true,false};
+
+	//opengl lighthas 4 
 	float oldLightPos[4];
-	currentScene.getLightPos(oldLightPos);
-	const int UNTRANS_AXIS=2;
-	for(size_t ui=0;ui<3;ui++)
+	if(FLIP_LIGHT_HACK)
 	{
-		if(ui == UNTRANS_AXIS)
-			continue;
-
-		oldLightPos[ui]=-oldLightPos[ui];
-	
+		currentScene.getLightPos(oldLightPos);
+		float newLightPos[4];
+		for(size_t ui=0;ui<4;ui++)
+		{
+			if(IMPORTANT_AXIS[ui])
+				newLightPos[ui]=oldLightPos[ui];
+			else
+				newLightPos[ui]=-oldLightPos[ui];
+		
+		}
+		currentScene.setLightPos(newLightPos);
 	}
-	currentScene.setLightPos(oldLightPos);
 	
+	if(showProgress)
+		wxD->Show();
 
-	//Loop through the tiles
+	//Loop through the tiles/ 
+	// note that 2D overlays will not be drawn in this pass
 	unsigned int thisTileNum=0;
 	int haveMoreTiles=1;
 	while(haveMoreTiles)
 	{
-		
-		
 		thisTileNum++;
-		//tell user which image tile we are making from the total image
-		stream_cast(tmpStr,thisTileNum);
-		tmpStr = std::string(TRANS("Tile ")) + tmpStr + std::string(TRANS(" of ")) + tmpStrTwo + "...";
-		//Update progress bar, if required
-		if(showProgress)
-			wxD->Update(thisTileNum,wxStr(tmpStr));
 
 		//Manually set the camera
 		//--
@@ -987,32 +968,97 @@ bool BasicGLPane::saveImage(unsigned int width, unsigned int height,
 
 		glPopMatrix();
 
+		//ending the tile copies
+		// data 
 		haveMoreTiles=trEndTile(tr);
+	
+		if(showProgress)	
+			wxD->Update(thisTileNum);
 
 	}
 
-	//re-set light coordinates
-	for(size_t ui=0;ui<3;ui++)
+	if(FLIP_LIGHT_HACK)
 	{
-		if (ui == UNTRANS_AXIS)
-			continue;
-		oldLightPos[ui]=-oldLightPos[ui];
+		//re-set light coordinates
+		currentScene.setLightPos(oldLightPos);
 	}
-	currentScene.setLightPos(oldLightPos);
 
-	if(showProgress)
-		wxD->Destroy();
 	trDelete(tr);
 
 	//Transfer pointer to image, which will perform free-ing of the buffer
 	image->SetData(imageBuffer);
-	
 	//HACK : Tiling function returns upside-down image. Fix in post-process
 	// argument is to set mirror axis such that x axis is unchanged
 	*image=image->Mirror(false);
+	//--------------	
+
+	//PASS 2
+	//--------------	
+
+	if(currentScene.hasOverlays())
+	{
+		//alllocate RGBA (4-channel) image
+		imageBuffer= (unsigned char*) malloc(4*(width)*height);
+		if(!imageBuffer)
+			return false;
+
+
+		tr=generateTileContext(width,height,imageBuffer,true);
+		trOrtho(tr,0.0f,aspect,
+				0.0f,1.0f,-1.0f,1.0f);
+		
+
+		haveMoreTiles=1;
+
+	
+		float rClear,gClear,bClear;
+		currentScene.getBackgroundColour(rClear,gClear,bClear);
+		glClearColor( rClear, gClear, 
+					bClear,0.0f);
+
+		//I am unclear why, but the faces are reversed
+		glDisable(GL_CULL_FACE);
+		while(haveMoreTiles)
+		{
+			thisTileNum++;
+			//Start the tile
+			trBeginTile(tr);
+			glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+			currentScene.drawOverlays(true);
+			//ending the tile copies
+			// data 
+			haveMoreTiles=trEndTile(tr);
+		
+			if(showProgress)	
+				wxD->Update(thisTileNum);
+		}	
+		glEnable(GL_CULL_FACE);
+		//restore the GL clear colour
+		updateClearColour();
+
+		///unpack the tile buffer into a wx image
+		wxImage imageOverlay(width,height);
+		imageOverlay.InitAlpha();
+
+		//FIXME: HACK - using "blue screen" effect
+		//don't use background as mask colour.
+		// use depth buffer or gl alpha
+		unsigned char mask[3] = {(unsigned char)rClear*255.0f,
+				(unsigned char)gClear*255.0f,(unsigned char)bClear*255.0f};
+		copyRGBAtoWXImage(width,height,imageBuffer,imageOverlay,mask);
+
+		free(imageBuffer);
+
+		combineWxImage(*image,imageOverlay);
+	}
+	
+	//--------------	
+	bool isOK=image->SaveFile(filename,wxBITMAP_TYPE_PNG);
 	
-	bool isOK=image->SaveFile(wxCStr(filename),wxBITMAP_TYPE_PNG);
 
+	if(showProgress)
+		wxD->Destroy();
+	
 	delete image;
 
 	if (needPostPaint) {
@@ -1038,8 +1084,8 @@ bool BasicGLPane::saveImageSequence(unsigned int resX, unsigned int resY, unsign
 
 	ASSERT(!currentScene.haveTempCam());
 	std::string outFile;
-	wxProgressDialog *wxD = new wxProgressDialog(wxTRANS("Animation progress"), 
-					wxTRANS("Rendering sequence..."), nFrames,this,wxPD_CAN_ABORT|wxPD_APP_MODAL );
+	wxProgressDialog *wxD = new wxProgressDialog(TRANS("Animation progress"), 
+					TRANS("Rendering sequence..."), nFrames,this,wxPD_CAN_ABORT|wxPD_APP_MODAL );
 
 	wxD->Show();
 	std::string tmpStr,tmpStrTwo;
@@ -1078,7 +1124,7 @@ bool BasicGLPane::saveImageSequence(unsigned int resX, unsigned int resY, unsign
 		stream_cast(tmpStr,ui+1);
 		//Tell user which image from the animation we are saving
 		tmpStr = std::string(TRANS("Saving Image ")) + tmpStr + std::string(TRANS(" of ")) + tmpStrTwo + "...";
-		if(!wxD->Update(ui,wxStr(tmpStr)))
+		if(!wxD->Update(ui,tmpStr))
 			break;
 
 		Refresh();
diff --git a/src/gui/glPane.h b/src/gui/glPane.h
index 5499d9e..aca3737 100644
--- a/src/gui/glPane.h
+++ b/src/gui/glPane.h
@@ -20,6 +20,7 @@
  
 
 #include "gl/scene.h"
+#include "gl/tr.h"
 
 #include <wx/glcanvas.h>
 #include <wx/timer.h>
@@ -29,9 +30,7 @@ class BasicGLPane : public wxGLCanvas
 {
 private:
 
-#if wxCHECK_VERSION(2,9,0)
 	wxGLContext *context;
-#endif
 
 	wxStatusBar *parentStatusBar;
 	wxTimer *parentStatusTimer;
@@ -76,6 +75,12 @@ private:
 	unsigned int lastKeyDoubleTap;
 
 	wxTimer *keyDoubleTapTimer;
+
+	//build a TR tile context to allow drawing the image in chunks.
+	// width and height are the output image size. 
+	// wantAlpha is used if we want to retrieve the alpha (transpar.) channel
+	TRcontext *generateTileContext(unsigned int width, unsigned int height, 
+			unsigned char *buffer, bool wantAlpha=false) const;
 public:
 	bool displaySupported() const;
 
diff --git a/src/gui/glade-skeleton/animateFilterDialog.wxg b/src/gui/glade-skeleton/animateFilterDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/animateSubDialogs/choiceKeyFrameDialog.wxg b/src/gui/glade-skeleton/animateSubDialogs/choiceKeyFrameDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/animateSubDialogs/colourChooserDialog.wxg b/src/gui/glade-skeleton/animateSubDialogs/colourChooserDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/animateSubDialogs/realKeyFrameDialog.wxg b/src/gui/glade-skeleton/animateSubDialogs/realKeyFrameDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/animateSubDialogs/stringKeyFrameDialog.wxg b/src/gui/glade-skeleton/animateSubDialogs/stringKeyFrameDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/autosaveDialog.wxg b/src/gui/glade-skeleton/autosaveDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/errorDialog.wxg b/src/gui/glade-skeleton/errorDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/mainWindow.wxg b/src/gui/glade-skeleton/mainWindow.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/preferencesDialog.wxg b/src/gui/glade-skeleton/preferencesDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/glade-skeleton/resDialog.wxg b/src/gui/glade-skeleton/resDialog.wxg
old mode 100755
new mode 100644
diff --git a/src/gui/mainFrame.cpp b/src/gui/mainFrame.cpp
index fbe36f9..ea4aab7 100644
--- a/src/gui/mainFrame.cpp
+++ b/src/gui/mainFrame.cpp
@@ -1,4 +1,20 @@
+/*
+ *	mainFrame.cpp - Main 3Depict window
+ *	Copyright (C) 2014, D Haley 
 
+ *	This program is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, either version 3 of the License, or
+ *	(at your option) any later version.
+
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
 
 #ifdef __APPLE__
 //FIXME: workaround for UI layout under apple platform 
@@ -32,11 +48,7 @@ enum
 #include <wx/stdpaths.h>
 #include <wx/tipdlg.h>
 
-#if wxCHECK_VERSION(2, 9, 0)
-	#include <wx/utils.h>  // Needed for wxLaunchDefaultApplication
-#else
-	#include <wx/mimetype.h> //Needed for GetOpenCommand
-#endif
+#include <wx/utils.h>  // Needed for wxLaunchDefaultApplication
 
 //Custom program dialog windows
 #include "gui/dialogs/StashDialog.h" //Stash editor
@@ -59,6 +71,8 @@ enum
 #include "backend/filters/dataLoad.h"
 
 
+#include "wx/propertyGridUpdater.h"
+
 using std::pair;
 using std::max;
 
@@ -89,7 +103,13 @@ const float BASELINE_SHIFT_FACTOR=0.0002f;
 
 
 const char *cameraIntroString=NTRANS("New camera name...");
-const char *stashIntroString=NTRANS("New stash name....");
+const char *stashIntroString=NTRANS("New stash name...");
+#if (defined(__WIN32) || defined(__WIN64))
+//Being non-empty string causes segfault under wine. Don't know why
+const char *ADD_FILTER_TEXT="";
+#else
+const char *ADD_FILTER_TEXT=NTRANS("New Filter...");
+#endif
 
 //Name of autosave state file. MUST end in .xml middle
 const char *AUTOSAVE_PREFIX= "autosave.";
@@ -118,7 +138,7 @@ const char * comboFilters_choices[FILTER_DROP_COUNT] =
 	NTRANS("Spectrum"),
 	NTRANS("Range File"),
 	NTRANS("Spat. Analysis"),
-	NTRANS("Voxelisation")
+	NTRANS("Voxelisation"),
 };
 
 //Mapping between filter ID and combo position
@@ -136,10 +156,11 @@ const unsigned int comboFiltersTypeMapping[FILTER_DROP_COUNT] = {
 	FILTER_TYPE_SPECTRUMPLOT,
 	FILTER_TYPE_RANGEFILE,
 	FILTER_TYPE_SPATIAL_ANALYSIS,
-	FILTER_TYPE_VOXELS
+	FILTER_TYPE_VOXELS,
  };
 //----
 
+
 //Constant identifiers for binding events in wxwidgets "event table"
 enum {
     
@@ -346,12 +367,13 @@ void clearWxTreeImages(wxTreeCtrl *t)
 MainWindowFrame::MainWindowFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style):
     wxFrame(parent, id, title, pos, size, style)
 {
+	COMPILE_ASSERT( (THREEDEP_ARRAYSIZE(comboFilters_choices) + 1 ) == FILTER_TYPE_ENUM_END);
+
 	initedOK=false;
 	plotUpdates=false;
 	programmaticEvent=false;
 	fullscreenState=0;
 	verCheckThread=0;
-	lastMessageType=MESSAGE_NONE;
 	lastProgressData.reset();
 
 	//Set up the program icon handler
@@ -400,21 +422,7 @@ MainWindowFrame::MainWindowFrame(wxWindow* parent, int id, const wxString& title
     panelTop = new BasicGLPane(splitTopBottom);
 
 
-#if wxCHECK_VERSION(2,9,0)
 	glPanelOK = panelTop->displaySupported();
-#else
-	#if defined(__WXGTK20__) 
-		//I had to work this out by studying the construtor, and then testing simultaneously
-		//on a broken and working Gl install. booyah.
-		glPanelOK=panelTop->m_glWidget;
-	#elif defined(__WIN32) || defined(__WIN64) || defined(__APPLE__)
-		//I hope this works. I'm not 100% sure -- I can't seem to reliably break my GL under windows.
-		glPanelOK=panelTop->GetContext();
-	#else
-		//lets just hope it worked.
-		glPanelOK=true;
-	#endif
-#endif
 
 	if(!glPanelOK)
 	{
@@ -441,106 +449,106 @@ TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please
     MainFrame_Menu = new wxMenuBar();
    
     fileMenu = new wxMenu();
-    fileMenu->Append(ID_FILE_OPEN, wxTRANS("&Open...\tCtrl+O"), wxTRANS("Open state file"), wxITEM_NORMAL);
-    fileMenu->Append(ID_FILE_MERGE, wxTRANS("&Merge...\tCtrl+Shift+O"), wxTRANS("Merge other file"), wxITEM_NORMAL);
+    fileMenu->Append(ID_FILE_OPEN, TRANS("&Open...\tCtrl+O"), TRANS("Open state file"), wxITEM_NORMAL);
+    fileMenu->Append(ID_FILE_MERGE, TRANS("&Merge...\tCtrl+Shift+O"), TRANS("Merge other file"), wxITEM_NORMAL);
     
     recentFilesMenu=new wxMenu();
     recentHistory->UseMenu(recentFilesMenu);
-    fileMenu->AppendSubMenu(recentFilesMenu,wxTRANS("&Recent"));
-    fileSave = fileMenu->Append(ID_FILE_SAVE, wxTRANS("&Save\tCtrl+S"), wxTRANS("Save state to file"), wxITEM_NORMAL);
+    fileMenu->AppendSubMenu(recentFilesMenu,TRANS("&Recent"));
+    fileSave = fileMenu->Append(ID_FILE_SAVE, TRANS("&Save\tCtrl+S"), TRANS("Save state to file"), wxITEM_NORMAL);
     fileSave->Enable(false);
-    fileMenu->Append(ID_FILE_SAVEAS, wxTRANS("Save &As...\tCtrl+Shift+S"), wxTRANS("Save current state to new file"), wxITEM_NORMAL);
+    fileMenu->Append(ID_FILE_SAVEAS, TRANS("Save &As...\tCtrl+Shift+S"), TRANS("Save current state to new file"), wxITEM_NORMAL);
     fileMenu->AppendSeparator();
     fileExport = new wxMenu();
-    fileExport->Append(ID_FILE_EXPORT_PLOT, wxTRANS("&Plot...\tCtrl+P"), wxTRANS("Export Current Plot"), wxITEM_NORMAL);
-    fileExport->Append(ID_FILE_EXPORT_IMAGE, wxTRANS("&Image...\tCtrl+I"), wxTRANS("Export Current 3D View"), wxITEM_NORMAL);
-    fileExport->Append(ID_FILE_EXPORT_IONS, wxTRANS("Ion&s...\tCtrl+N"), wxTRANS("Export Ion Data"), wxITEM_NORMAL);
-    fileExport->Append(ID_FILE_EXPORT_RANGE, wxTRANS("Ran&ges...\tCtrl+G"), wxTRANS("Export Range Data"), wxITEM_NORMAL);
-    fileExport->Append(ID_FILE_EXPORT_FILTER_ANIMATION, wxTRANS("&Animate Filters...\tCtrl+A"), wxTRANS("Export Animated Filter"), wxITEM_NORMAL);
-    fileExport->Append(ID_FILE_EXPORT_ANIMATION, wxTRANS("Ani&mate Camera...\tCtrl+M"), wxTRANS("Export Animated Camera"), wxITEM_NORMAL);
-    fileExport->Append(ID_FILE_EXPORT_PACKAGE, wxTRANS("Pac&kage...\tCtrl+K"), wxTRANS("Export analysis package"), wxITEM_NORMAL);
-
-    fileMenu->AppendSubMenu(fileExport,wxTRANS("&Export"));
+    fileExport->Append(ID_FILE_EXPORT_PLOT, TRANS("&Plot...\tCtrl+P"), TRANS("Export Current Plot"), wxITEM_NORMAL);
+    fileExport->Append(ID_FILE_EXPORT_IMAGE, TRANS("&Image...\tCtrl+I"), TRANS("Export Current 3D View"), wxITEM_NORMAL);
+    fileExport->Append(ID_FILE_EXPORT_IONS, TRANS("Ion&s...\tCtrl+N"), TRANS("Export Ion Data"), wxITEM_NORMAL);
+    fileExport->Append(ID_FILE_EXPORT_RANGE, TRANS("Ran&ges...\tCtrl+G"), TRANS("Export Range Data"), wxITEM_NORMAL);
+    fileExport->Append(ID_FILE_EXPORT_FILTER_ANIMATION, TRANS("&Animate Filters...\tCtrl+A"), TRANS("Export Animated Filter"), wxITEM_NORMAL);
+    fileExport->Append(ID_FILE_EXPORT_ANIMATION, TRANS("Ani&mate Camera...\tCtrl+M"), TRANS("Export Animated Camera"), wxITEM_NORMAL);
+    fileExport->Append(ID_FILE_EXPORT_PACKAGE, TRANS("Pac&kage...\tCtrl+K"), TRANS("Export analysis package"), wxITEM_NORMAL);
+
+    fileMenu->AppendSubMenu(fileExport,TRANS("&Export"));
     fileMenu->AppendSeparator();
 #ifdef __APPLE__
-    fileMenu->Append(ID_FILE_EXIT, wxTRANS("&Quit\tCtrl+Q"), wxTRANS("Exit Program"), wxITEM_NORMAL);
+    fileMenu->Append(ID_FILE_EXIT, TRANS("&Quit\tCtrl+Q"), TRANS("Exit Program"), wxITEM_NORMAL);
 #else
-    fileMenu->Append(ID_FILE_EXIT, wxTRANS("E&xit"), wxTRANS("Exit Program"), wxITEM_NORMAL);
+    fileMenu->Append(ID_FILE_EXIT, TRANS("E&xit"), TRANS("Exit Program"), wxITEM_NORMAL);
 #endif
-    MainFrame_Menu->Append(fileMenu, wxTRANS("&File"));
+    MainFrame_Menu->Append(fileMenu, TRANS("&File"));
 
     wxMenu* wxglade_tmp_menu_1 = new wxMenu();
     wxglade_tmp_menu_1->Append(ID_VIEW_BACKGROUND, 
-		    wxTRANS("&Background Colour...\tCtrl+B"),wxTRANS("Change background colour"));
+		    TRANS("&Background Colour...\tCtrl+B"),TRANS("Change background colour"));
     wxglade_tmp_menu_1->AppendSeparator(); //Separator
 #ifndef __APPLE__
     checkMenuControlPane= wxglade_tmp_menu_1->Append(ID_VIEW_CONTROL_PANE, 
-		    wxTRANS("&Control Pane\tF2"), wxTRANS("Toggle left control pane"), wxITEM_CHECK);
+		    TRANS("&Control Pane\tF2"), TRANS("Toggle left control pane"), wxITEM_CHECK);
 #else
     checkMenuControlPane= wxglade_tmp_menu_1->Append(ID_VIEW_CONTROL_PANE, 
-		    wxTRANS("&Control Pane\tAlt+C"), wxTRANS("Toggle left control pane"), wxITEM_CHECK);
+		    TRANS("&Control Pane\tAlt+C"), TRANS("Toggle left control pane"), wxITEM_CHECK);
 
 #endif
     checkMenuControlPane->Check();
 #ifndef __APPLE__
     checkMenuRawDataPane= wxglade_tmp_menu_1->Append(ID_VIEW_RAW_DATA_PANE, 
-		    wxTRANS("&Raw Data Pane\tF3"), wxTRANS("Toggle raw data  pane (bottom)"), wxITEM_CHECK);
+		    TRANS("&Raw Data Pane\tF3"), TRANS("Toggle raw data  pane (bottom)"), wxITEM_CHECK);
 #else
     checkMenuRawDataPane= wxglade_tmp_menu_1->Append(ID_VIEW_RAW_DATA_PANE, 
-		    wxTRANS("&Raw Data Pane\tAlt+R"), wxTRANS("Toggle raw data  pane (bottom)"), wxITEM_CHECK);
+		    TRANS("&Raw Data Pane\tAlt+R"), TRANS("Toggle raw data  pane (bottom)"), wxITEM_CHECK);
 #endif
     checkMenuRawDataPane->Check();
 #ifndef __APPLE__
-    checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, wxTRANS("&Plot List\tF4"),wxTRANS("Toggle plot list"), wxITEM_CHECK);
+    checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, TRANS("&Plot List\tF4"),TRANS("Toggle plot list"), wxITEM_CHECK);
 #else
-    checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, wxTRANS("&Plot List\tAlt+P"),wxTRANS("Toggle plot list"), wxITEM_CHECK);
+    checkMenuSpectraList=wxglade_tmp_menu_1->Append(ID_VIEW_SPECTRA, TRANS("&Plot List\tAlt+P"),TRANS("Toggle plot list"), wxITEM_CHECK);
 #endif
     checkMenuSpectraList->Check();
 
     wxglade_tmp_menu_1->AppendSeparator(); //Separator
     wxMenu* viewPlot= new wxMenu();
-    checkViewLegend=viewPlot->Append(ID_VIEW_PLOT_LEGEND,wxTRANS("&Legend\tCtrl+L"),wxTRANS("Toggle Legend display"),wxITEM_CHECK);
+    checkViewLegend=viewPlot->Append(ID_VIEW_PLOT_LEGEND,TRANS("&Legend\tCtrl+L"),TRANS("Toggle Legend display"),wxITEM_CHECK);
     checkViewLegend->Check();
-    wxglade_tmp_menu_1->AppendSubMenu(viewPlot,wxTRANS("P&lot..."));
-    checkViewWorldAxis=wxglade_tmp_menu_1->Append(ID_VIEW_WORLDAXIS,wxTRANS("&Axis\tCtrl+Shift+I"),wxTRANS("Toggle World Axis display"),wxITEM_CHECK);
+    wxglade_tmp_menu_1->AppendSubMenu(viewPlot,TRANS("P&lot..."));
+    checkViewWorldAxis=wxglade_tmp_menu_1->Append(ID_VIEW_WORLDAXIS,TRANS("&Axis\tCtrl+Shift+I"),TRANS("Toggle World Axis display"),wxITEM_CHECK);
     checkViewWorldAxis->Check();
     
     wxglade_tmp_menu_1->AppendSeparator(); //Separator
 #ifndef __APPLE__
-    menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, wxTRANS("&Fullscreen mode\tF11"),wxTRANS("Next fullscreen mode: with toolbars"));
+    menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, TRANS("&Fullscreen mode\tF11"),TRANS("Next fullscreen mode: with toolbars"));
 #else
-    menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, wxTRANS("&Fullscreen mode\tCtrl+Shift+F"),wxTRANS("Next fullscreen mode: with toolbars"));
+    menuViewFullscreen=wxglade_tmp_menu_1->Append(ID_VIEW_FULLSCREEN, TRANS("&Fullscreen mode\tCtrl+Shift+F"),TRANS("Next fullscreen mode: with toolbars"));
 #endif
 
 
     wxMenu *Edit = new wxMenu();
-    editUndoMenuItem = Edit->Append(ID_EDIT_UNDO,wxTRANS("&Undo\tCtrl+Z"));
+    editUndoMenuItem = Edit->Append(ID_EDIT_UNDO,TRANS("&Undo\tCtrl+Z"));
     editUndoMenuItem->Enable(false);
-    editRedoMenuItem = Edit->Append(ID_EDIT_REDO,wxTRANS("&Redo\tCtrl+Y"));
+    editRedoMenuItem = Edit->Append(ID_EDIT_REDO,TRANS("&Redo\tCtrl+Y"));
    editRedoMenuItem->Enable(false);
     Edit->AppendSeparator();
-    editRangeMenuItem=Edit->Append(ID_EDIT_RANGE,wxTRANS("&Range"));
+    editRangeMenuItem=Edit->Append(ID_EDIT_RANGE,TRANS("&Range"));
     editRangeMenuItem->Enable(false);
     Edit->AppendSeparator();
-    Edit->Append(ID_EDIT_PREFERENCES,wxTRANS("&Preferences"));
+    Edit->Append(ID_EDIT_PREFERENCES,TRANS("&Preferences"));
 
-    MainFrame_Menu->Append(Edit, wxTRANS("&Edit"));
+    MainFrame_Menu->Append(Edit, TRANS("&Edit"));
 
 
-    MainFrame_Menu->Append(wxglade_tmp_menu_1, wxTRANS("&View"));
+    MainFrame_Menu->Append(wxglade_tmp_menu_1, TRANS("&View"));
     wxMenu* Help = new wxMenu();
-    Help->Append(ID_HELP_HELP, wxTRANS("&Help...\tCtrl+H"), wxTRANS("Show help files and documentation"), wxITEM_NORMAL);
-    Help->Append(ID_HELP_CONTACT, wxTRANS("&Contact..."), wxTRANS("Open contact page"), wxITEM_NORMAL);
+    Help->Append(ID_HELP_HELP, TRANS("&Help...\tCtrl+H"), TRANS("Show help files and documentation"), wxITEM_NORMAL);
+    Help->Append(ID_HELP_CONTACT, TRANS("&Contact..."), TRANS("Open contact page"), wxITEM_NORMAL);
     Help->AppendSeparator();
-    Help->Append(ID_HELP_ABOUT, wxTRANS("&About..."), wxTRANS("Information about this program"), wxITEM_NORMAL);
-    MainFrame_Menu->Append(Help, wxTRANS("&Help"));
+    Help->Append(ID_HELP_ABOUT, TRANS("&About..."), TRANS("Information about this program"), wxITEM_NORMAL);
+    MainFrame_Menu->Append(Help, TRANS("&Help"));
     SetMenuBar(MainFrame_Menu);
-    lblSettings = new wxStaticText(noteData, wxID_ANY, wxTRANS("Stashed Filters"));
+    lblSettings = new wxStaticText(noteData, wxID_ANY, TRANS("Stashed Filters"));
 
 
-    comboStash = new wxComboBox(noteData, ID_COMBO_STASH, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxTE_PROCESS_ENTER|SAFE_CB_SORT);
+    comboStash = new wxComboBox(noteData, ID_COMBO_STASH, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxTE_PROCESS_ENTER|wxCB_SORT);
     btnStashManage = new wxButton(noteData, ID_BTN_STASH_MANAGE, wxT("..."),wxDefaultPosition,wxSize(28,28));
-    filteringLabel = new wxStaticText(noteData, wxID_ANY, wxTRANS("New Filters"));
+    filteringLabel = new wxStaticText(noteData, wxID_ANY, TRANS("New Filters"));
 
 
     //Workaround for wx bug http://trac.wxwidgets.org/ticket/4398
@@ -554,103 +562,107 @@ TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please
 	//construct translation->comboFilters_choices offset.
 	filterMap[TRANS(str)] = ui;
 	//Add to filter name wxArray
-	wxString wxStrTrans = wxTRANS(str);
+	wxString wxStrTrans = TRANS(str);
 	filterNames.Add(wxStrTrans);
     }
+    
 
 
 
-    comboFilters = new wxComboBox(filterTreePane, ID_COMBO_FILTER, wxT(""), wxDefaultPosition, wxDefaultSize, filterNames, wxCB_DROPDOWN|wxCB_READONLY|SAFE_CB_SORT);
-
+    comboFilters = new wxComboBox(filterTreePane, ID_COMBO_FILTER, TRANS(ADD_FILTER_TEXT), 
+    			wxDefaultPosition, wxDefaultSize, filterNames, wxCB_DROPDOWN|wxCB_SORT);
+    comboFilters->Enable(false);
 
     treeFilters = new TextTreeCtrl(filterTreePane, ID_TREE_FILTERS, wxDefaultPosition, wxDefaultSize, wxTR_HAS_BUTTONS|wxTR_NO_LINES|wxTR_HIDE_ROOT|wxTR_DEFAULT_STYLE|wxSUNKEN_BORDER|wxTR_EDIT_LABELS);
     vector<string> msgs;
     msgs.push_back("No data loaded:");
     msgs.push_back("open file, then add filters");
     treeFilters->setMessages(msgs); 
-    lastRefreshLabel = new wxStaticText(filterTreePane, wxID_ANY, wxTRANS("Last Outputs"));
+    lastRefreshLabel = new wxStaticText(filterTreePane, wxID_ANY, TRANS("Last Outputs"));
     listLastRefresh = new wxListCtrl(filterTreePane, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxSUNKEN_BORDER);
-    checkAutoUpdate = new wxCheckBox(filterTreePane, ID_CHECK_AUTOUPDATE, wxTRANS("Auto Refresh"));
+    checkAutoUpdate = new wxCheckBox(filterTreePane, ID_CHECK_AUTOUPDATE, TRANS("Auto Refresh"));
     refreshButton = new wxButton(filterTreePane, wxID_REFRESH, wxEmptyString);
     btnFilterTreeExpand= new wxButton(filterTreePane, ID_BTN_EXPAND, wxT("▼"),wxDefaultPosition,wxSize(30,30));
     btnFilterTreeCollapse = new wxButton(filterTreePane, ID_BTN_COLLAPSE, wxT("▲"),wxDefaultPosition,wxSize(30,30));
     btnFilterTreeErrs = new wxBitmapButton(filterTreePane,ID_BTN_FILTERTREE_ERRS,wxArtProvider::GetBitmap(wxART_INFORMATION),wxDefaultPosition,wxSize(40,40));
 
-    propGridLabel = new wxStaticText(filterPropertyPane, wxID_ANY, wxTRANS("Filter settings"));
-    gridFilterPropGroup = new wxCustomPropGrid(filterPropertyPane, ID_GRID_FILTER_PROPERTY);
-    labelCameraName = new wxStaticText(noteCamera, wxID_ANY, wxTRANS("Camera Name"));
+    propGridLabel = new wxStaticText(filterPropertyPane, wxID_ANY, TRANS("Filter settings"));
+    gridFilterPropGroup = new wxPropertyGrid(filterPropertyPane, ID_GRID_FILTER_PROPERTY,wxDefaultPosition,wxDefaultSize,PROPERTY_GRID_STYLE);
+    gridFilterPropGroup->SetExtraStyle(PROPERTY_GRID_EXTRA_STYLE);
+    labelCameraName = new wxStaticText(noteCamera, wxID_ANY, TRANS("Camera Name"));
     comboCamera = new wxComboBox(noteCamera, ID_COMBO_CAMERA, wxT(""), wxDefaultPosition, wxDefaultSize, 0, NULL, wxCB_DROPDOWN|wxTE_PROCESS_ENTER );
     buttonRemoveCam = new wxButton(noteCamera, wxID_REMOVE, wxEmptyString);
     cameraNamePropertySepStaticLine = new wxStaticLine(noteCamera, wxID_ANY);
-    gridCameraProperties = new wxCustomPropGrid(noteCamera, ID_GRID_CAMERA_PROPERTY);
+    gridCameraProperties = new wxPropertyGrid(noteCamera,ID_GRID_CAMERA_PROPERTY,
+					wxDefaultPosition,wxDefaultSize,PROPERTY_GRID_STYLE);
 #ifndef APPLE_EFFECTS_WORKAROUND
-    checkPostProcessing = new wxCheckBox(notePost, ID_EFFECT_ENABLE, wxTRANS("3D Post-processing"));
+    checkPostProcessing = new wxCheckBox(notePost, ID_EFFECT_ENABLE, TRANS("3D Post-processing"));
 #endif
-    checkFxCrop = new wxCheckBox(noteFxPanelCrop, ID_EFFECT_CROP_ENABLE, wxTRANS("Enable Cropping"));
+    checkFxCrop = new wxCheckBox(noteFxPanelCrop, ID_EFFECT_CROP_ENABLE, TRANS("Enable Cropping"));
     const wxString comboFxCropAxisOne_choices[] = {
-        wxTRANS("x-y"),
-        wxTRANS("x-z"),
-        wxTRANS("y-x"),
-        wxTRANS("y-z"),
-        wxTRANS("z-x"),
-        wxTRANS("z-y")
+        TRANS("x-y"),
+        TRANS("x-z"),
+        TRANS("y-x"),
+        TRANS("y-z"),
+        TRANS("z-x"),
+        TRANS("z-y")
     };
     comboFxCropAxisOne = new wxComboBox(noteFxPanelCrop, ID_EFFECT_CROP_AXISONE_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 6, comboFxCropAxisOne_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY);
     panelFxCropOne = new CropPanel(noteFxPanelCrop, ID_EFFECT_CROP_AXISONE_COMBO,
 		   		 wxDefaultPosition,wxDefaultSize,wxEXPAND);
     const wxString comboFxCropAxisTwo_choices[] = {
-        wxTRANS("x-y"),
-        wxTRANS("x-z"),
-        wxTRANS("y-x"),
-        wxTRANS("y-z"),
-        wxTRANS("z-x"),
-        wxTRANS("z-y")
+        TRANS("x-y"),
+        TRANS("x-z"),
+        TRANS("y-x"),
+        TRANS("y-z"),
+        TRANS("z-x"),
+        TRANS("z-y")
     };
     comboFxCropAxisTwo = new wxComboBox(noteFxPanelCrop, ID_EFFECT_CROP_AXISTWO_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 6, comboFxCropAxisTwo_choices, wxCB_SIMPLE|wxCB_DROPDOWN|wxCB_READONLY);
     panelFxCropTwo = new CropPanel(noteFxPanelCrop, ID_EFFECT_CROP_AXISTWO_COMBO,wxDefaultPosition,wxDefaultSize,wxEXPAND);
-    checkFxCropCameraFrame = new wxCheckBox(noteFxPanelCrop,ID_EFFECT_CROP_CHECK_COORDS,wxTRANS("Use camera coordinates"));
-    labelFxCropDx = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dX"));
+    checkFxCropCameraFrame = new wxCheckBox(noteFxPanelCrop,ID_EFFECT_CROP_CHECK_COORDS,TRANS("Use camera coordinates"));
+    labelFxCropDx = new wxStaticText(noteFxPanelCrop, wxID_ANY, TRANS("dX"));
     textFxCropDx = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DX, wxEmptyString);
-    labelFxCropDy = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dY"));
+    labelFxCropDy = new wxStaticText(noteFxPanelCrop, wxID_ANY, TRANS("dY"));
     textFxCropDy = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DY, wxEmptyString);
-    labelFxCropDz = new wxStaticText(noteFxPanelCrop, wxID_ANY, wxTRANS("dZ"));
+    labelFxCropDz = new wxStaticText(noteFxPanelCrop, wxID_ANY, TRANS("dZ"));
     textFxCropDz = new wxTextCtrl(noteFxPanelCrop, ID_EFFECT_CROP_TEXT_DZ, wxEmptyString);
-    checkFxEnableStereo = new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_ENABLE, wxTRANS("Enable Anaglyphic Stereo"));
-    checkFxStereoLensFlip= new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_LENSFLIP, wxTRANS("Flip Channels"));
-    lblFxStereoMode = new wxStaticText(noteFxPanelStereo, wxID_ANY, wxTRANS("Anaglyph Mode"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
+    checkFxEnableStereo = new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_ENABLE, TRANS("Enable Anaglyphic Stereo"));
+    checkFxStereoLensFlip= new wxCheckBox(noteFxPanelStereo, ID_EFFECT_STEREO_LENSFLIP, TRANS("Flip Channels"));
+    lblFxStereoMode = new wxStaticText(noteFxPanelStereo, wxID_ANY, TRANS("Anaglyph Mode"), wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE);
     const wxString comboFxStereoMode_choices[] = {
-        wxTRANS("Red-Blue"),
-        wxTRANS("Red-Green"),
-        wxTRANS("Red-Cyan"),
-        wxTRANS("Green-Magenta"),
+        TRANS("Red-Blue"),
+        TRANS("Red-Green"),
+        TRANS("Red-Cyan"),
+        TRANS("Green-Magenta"),
     };
     comboFxStereoMode = new wxComboBox(noteFxPanelStereo, ID_EFFECT_STEREO_COMBO, wxT(""), wxDefaultPosition, wxDefaultSize, 4, comboFxStereoMode_choices, wxCB_DROPDOWN|wxCB_SIMPLE|wxCB_READONLY);
     bitmapFxStereoGlasses = new wxStaticBitmap(noteFxPanelStereo, wxID_ANY, wxNullBitmap);
-    labelFxStereoBaseline = new wxStaticText(noteFxPanelStereo, wxID_ANY, wxTRANS("Baseline Separation"));
+    labelFxStereoBaseline = new wxStaticText(noteFxPanelStereo, wxID_ANY, TRANS("Baseline Separation"));
     sliderFxStereoBaseline = new wxSlider(noteFxPanelStereo,ID_EFFECT_STEREO_BASELINE_SLIDER, 20, 0, 100);
-    labelAppearance = new wxStaticText(noteTools, wxID_ANY, wxTRANS("Appearance"));
-    checkAlphaBlend = new wxCheckBox(noteTools,ID_CHECK_ALPHA , wxTRANS("Smooth && translucent objects"));
+    labelAppearance = new wxStaticText(noteTools, wxID_ANY, TRANS("Appearance"));
+    checkAlphaBlend = new wxCheckBox(noteTools,ID_CHECK_ALPHA , TRANS("Smooth && translucent objects"));
     checkAlphaBlend->SetValue(true);
-    checkLighting = new wxCheckBox(noteTools, ID_CHECK_LIGHTING, wxTRANS("3D lighting"));
+    checkLighting = new wxCheckBox(noteTools, ID_CHECK_LIGHTING, TRANS("3D lighting"));
     checkLighting->SetValue(true);
     static_line_1 = new wxStaticLine(noteTools, wxID_ANY);
-    labelPerformance = new wxStaticText(noteTools, wxID_ANY, wxTRANS("Performance"));
-    checkWeakRandom = new wxCheckBox(noteTools, ID_CHECK_WEAKRANDOM, wxTRANS("Fast and weak randomisation."));
+    labelPerformance = new wxStaticText(noteTools, wxID_ANY, TRANS("Performance"));
+    checkWeakRandom = new wxCheckBox(noteTools, ID_CHECK_WEAKRANDOM, TRANS("Fast and weak randomisation."));
     checkWeakRandom->SetValue(true);
-    checkLimitOutput = new wxCheckBox(noteTools, ID_CHECK_LIMIT_POINT_OUT, wxTRANS("Limit Output Pts"));
+    checkLimitOutput = new wxCheckBox(noteTools, ID_CHECK_LIMIT_POINT_OUT, TRANS("Limit Output Pts"));
     checkLimitOutput->SetValue((visControl.getIonDisplayLimit() !=0));
     std::string tmpStr;
     stream_cast(tmpStr,visControl.getIonDisplayLimit());
-    textLimitOutput = new wxTextCtrl(noteTools, ID_TEXT_LIMIT_POINT_OUT, wxStr(tmpStr),
+    textLimitOutput = new wxTextCtrl(noteTools, ID_TEXT_LIMIT_POINT_OUT, (tmpStr),
 		    	wxDefaultPosition,wxDefaultSize,wxTE_PROCESS_ENTER );
-    checkCaching = new wxCheckBox(noteTools, ID_CHECK_CACHING, wxTRANS("Filter caching"));
+    checkCaching = new wxCheckBox(noteTools, ID_CHECK_CACHING, TRANS("Filter caching"));
     checkCaching->SetValue(true);
-    labelMaxRamUsage = new wxStaticText(noteTools, wxID_ANY, wxTRANS("Max. Ram usage (%)"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
+    labelMaxRamUsage = new wxStaticText(noteTools, wxID_ANY, TRANS("Max. Ram usage (%)"), wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
     spinCachePercent = new wxSpinCtrl(noteTools, ID_SPIN_CACHEPERCENT, wxT("50"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 1, 100);
     panelView = new wxPanel(panelTop, ID_PANEL_VIEW);
     panelSpectra = new MathGLPane(splitterSpectra, wxID_ANY);
-    plotListLabel = new wxStaticText(window_2_pane_2, wxID_ANY, wxTRANS("Plot List"));
-    plotList = new wxListBox(window_2_pane_2, ID_LIST_PLOTS, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE|wxLB_NEEDED_SB|wxLB_SORT);
+    plotListLabel = new wxStaticText(window_2_pane_2, wxID_ANY, TRANS("Plot List"));
+    plotList = new wxListBox(window_2_pane_2, ID_LIST_PLOTS, wxDefaultPosition, wxDefaultSize, 0, NULL, wxLB_MULTIPLE|wxLB_NEEDED_SB);
     gridRawData = new CopyGrid(noteRaw, ID_GRID_RAW_DATA);
     btnRawDataSave = new wxButton(noteRaw, wxID_SAVE, wxEmptyString);
     btnRawDataClip = new wxButton(noteRaw, wxID_COPY, wxEmptyString);
@@ -662,6 +674,8 @@ TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please
     set_properties();
     do_layout();
 
+    backCameraPropGrid=0;
+    backFilterPropGrid=0;
     //Disable post-processing
 #ifndef APPLE_EFFECTS_WORKAROUND
     checkPostProcessing->SetValue(false); 
@@ -702,8 +716,8 @@ TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please
     splitterSpectra->SetSashGravity(0.82);
 
     //Last Refresh box
-    listLastRefresh->InsertColumn(0,wxTRANS("Type"));
-    listLastRefresh->InsertColumn(1,wxTRANS("Num"));
+    listLastRefresh->InsertColumn(0,TRANS("Type"));
+    listLastRefresh->InsertColumn(1,TRANS("Num"));
 
     //Set callback for mathgl plot
     panelSpectra->registerUpdateHandler(this,
@@ -718,32 +732,23 @@ TRANS("Unable to initialise the openGL (3D) panel. Program cannot start. Please
    
     if(configFile.read() == CONFIG_ERR_BADFILE)
     {
-	textConsoleOut->AppendText(wxTRANS("Warning: Your configuration file appears to be invalid:\n"));
-	wxString wxS = wxTRANS("\tConfig Load: ");
-	wxS+= wxStr( configFile.getErrMessage());
+	textConsoleOut->AppendText(TRANS("Warning: Your configuration file appears to be invalid:\n"));
+	wxString wxS = TRANS("\tConfig Load: ");
+	wxS+= ( configFile.getErrMessage());
 	textConsoleOut->AppendText(wxS);
     }
     else
 	    restoreConfigDefaults();
 	
 	
-	
-	//Attempt to load the auto-save file, if it exists
-	//-----------------
-	checkReloadAutosave();
-	//-----------------
-
 	//Try to set the window size to a nice size
 	SetSize(getNiceWindowSize());
-
 	initedOK=true;   
 
 
 
 
 
-	updateTimer->Start(UPDATE_TIMER_DELAY,wxTIMER_CONTINUOUS);
-	autoSaveTimer->Start(AUTOSAVE_DELAY*1000,wxTIMER_CONTINUOUS);
 
 #ifndef DISABLE_ONLINE_UPDATE
         wxDateTime datetime = wxDateTime::Today();	
@@ -795,28 +800,26 @@ MainWindowFrame::~MainWindowFrame()
 
 	//wxwidgets can crash if objects are ->Connect-ed  in 
 	// wxWindowBase::DestroyChildren(), so Disconnect before destructing
-#if wxCHECK_VERSION(2, 9, 0)
     comboCamera->Unbind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboCameraSetFocus, this);
     comboStash->Unbind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboStashSetFocus, this);
     noteDataView->Unbind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &MainWindowFrame::OnNoteDataView, this);
     treeFilters->Unbind(wxEVT_KEY_DOWN,&MainWindowFrame::OnTreeKeyDown,this);
-#else
-	noteDataView->Disconnect();
-	comboStash->Disconnect();
-	comboCamera->Disconnect();
-#endif
 }
 
 
+void MainWindowFrame::finaliseStartup()
+{
+	updateTimer->Start(UPDATE_TIMER_DELAY,wxTIMER_CONTINUOUS);
+	autoSaveTimer->Start(AUTOSAVE_DELAY*1000,wxTIMER_CONTINUOUS);
+}
+
 BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame)
-    EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_FILTER_PROPERTY,MainWindowFrame::OnFilterGridCellEditorShow)
-    EVT_GRID_CMD_EDITOR_HIDDEN(ID_GRID_FILTER_PROPERTY,MainWindowFrame::OnFilterGridCellEditorHide)
-    EVT_GRID_CMD_EDITOR_SHOWN(ID_GRID_CAMERA_PROPERTY,MainWindowFrame::OnCameraGridCellEditorShow)
-    EVT_GRID_CMD_EDITOR_HIDDEN(ID_GRID_CAMERA_PROPERTY,MainWindowFrame::OnCameraGridCellEditorHide)
     EVT_TIMER(ID_STATUS_TIMER,MainWindowFrame::OnStatusBarTimer)
     EVT_TIMER(ID_PROGRESS_TIMER,MainWindowFrame::OnProgressTimer)
     EVT_TIMER(ID_UPDATE_TIMER,MainWindowFrame::OnUpdateTimer)
     EVT_TIMER(ID_AUTOSAVE_TIMER,MainWindowFrame::OnAutosaveTimer)
+    EVT_IDLE(MainWindowFrame::OnIdle)
+   
     EVT_SPLITTER_UNSPLIT(ID_SPLIT_TOP_BOTTOM, MainWindowFrame::OnRawDataUnsplit) 
     EVT_SPLITTER_UNSPLIT(ID_SPLIT_LEFTRIGHT, MainWindowFrame::OnControlUnsplit) 
     EVT_SPLITTER_UNSPLIT(ID_SPLIT_SPECTRA, MainWindowFrame::OnSpectraUnsplit) 
@@ -864,9 +867,6 @@ BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame)
     EVT_TEXT_ENTER(ID_COMBO_STASH, MainWindowFrame::OnComboStashEnter)
     EVT_COMBOBOX(ID_COMBO_STASH, MainWindowFrame::OnComboStash)
     EVT_TREE_END_DRAG(ID_TREE_FILTERS, MainWindowFrame::OnTreeEndDrag)
-#if !defined(WX_TREE_WORKAROUND)
-    EVT_TREE_KEY_DOWN(ID_TREE_FILTERS, MainWindowFrame::OnTreeKeyDown)
-#endif
     EVT_TREE_SEL_CHANGING(ID_TREE_FILTERS, MainWindowFrame::OnTreeSelectionPreChange)
     EVT_TREE_SEL_CHANGED(ID_TREE_FILTERS, MainWindowFrame::OnTreeSelectionChange)
     EVT_TREE_DELETE_ITEM(ID_TREE_FILTERS, MainWindowFrame::OnTreeDeleteItem)
@@ -874,13 +874,9 @@ BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame)
     EVT_BUTTON(ID_BTN_EXPAND, MainWindowFrame::OnBtnExpandTree)
     EVT_BUTTON(ID_BTN_COLLAPSE, MainWindowFrame::OnBtnCollapseTree)
     EVT_BUTTON(ID_BTN_FILTERTREE_ERRS, MainWindowFrame::OnBtnFilterTreeErrs)
-#if wxCHECK_VERSION(2,9,0)
-    EVT_GRID_CMD_CELL_CHANGED(ID_GRID_FILTER_PROPERTY, MainWindowFrame::OnGridFilterPropertyChange)
-    EVT_GRID_CMD_CELL_CHANGED(ID_GRID_CAMERA_PROPERTY, MainWindowFrame::OnGridCameraPropertyChange)
-#else
-    EVT_GRID_CMD_CELL_CHANGE(ID_GRID_FILTER_PROPERTY, MainWindowFrame::OnGridFilterPropertyChange)
-    EVT_GRID_CMD_CELL_CHANGE(ID_GRID_CAMERA_PROPERTY, MainWindowFrame::OnGridCameraPropertyChange)
-#endif
+    EVT_PG_CHANGING(ID_GRID_FILTER_PROPERTY, MainWindowFrame::OnGridFilterPropertyChange)
+    EVT_PG_CHANGING(ID_GRID_CAMERA_PROPERTY, MainWindowFrame::OnGridCameraPropertyChange)
+    EVT_PG_DOUBLE_CLICK(ID_GRID_FILTER_PROPERTY, MainWindowFrame::OnGridFilterDClick)
     EVT_TEXT(ID_COMBO_CAMERA, MainWindowFrame::OnComboCameraText)
     EVT_TEXT_ENTER(ID_COMBO_CAMERA, MainWindowFrame::OnComboCameraEnter)
     EVT_CHECKBOX(ID_CHECK_ALPHA, MainWindowFrame::OnCheckAlpha)
@@ -890,7 +886,7 @@ BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame)
     EVT_SPINCTRL(ID_SPIN_CACHEPERCENT, MainWindowFrame::OnCacheRamUsageSpin)
     EVT_COMBOBOX(ID_COMBO_CAMERA, MainWindowFrame::OnComboCamera)
     EVT_COMBOBOX(ID_COMBO_FILTER, MainWindowFrame::OnComboFilter)
-    EVT_TEXT_ENTER(ID_COMBO_FILTER, MainWindowFrame::OnComboFilterEnter)
+    EVT_TEXT(ID_COMBO_FILTER, MainWindowFrame::OnComboFilterText)
     EVT_BUTTON(ID_BTN_STASH_MANAGE, MainWindowFrame::OnButtonStashDialog)
     EVT_BUTTON(wxID_REMOVE, MainWindowFrame::OnButtonRemoveCam)
     EVT_LISTBOX(ID_LIST_PLOTS, MainWindowFrame::OnSpectraListbox)
@@ -918,6 +914,21 @@ BEGIN_EVENT_TABLE(MainWindowFrame, wxFrame)
 END_EVENT_TABLE();
 
 
+void MainWindowFrame::OnIdle(wxIdleEvent &evt)
+{
+	if(backFilterPropGrid)
+	{
+		delete backFilterPropGrid;
+		backFilterPropGrid=0;
+	}
+
+	if(backCameraPropGrid)
+	{
+		delete backCameraPropGrid;
+		backCameraPropGrid=0;
+	}
+}
+
 unsigned int MainWindowFrame::guessFileType(const std::string &dataFile)
 {
 	
@@ -926,7 +937,7 @@ unsigned int MainWindowFrame::guessFileType(const std::string &dataFile)
 	wxFileName fname;
 	wxString volume,path,name,ext;
 	bool hasExt;
-	fname.SplitPath(wxStr(dataFile),&volume,
+	fname.SplitPath((dataFile),&volume,
 			&path,&name,&ext, &hasExt);
 
 	//Test the extension to determine what we will do
@@ -971,8 +982,8 @@ void MainWindowFrame::checkAskSaveState()
 	if(visControl.hasStateData() && visControl.stateModifyLevel() >=STATE_MODIFIED_ANCILLARY)
 	{
 		wxMessageDialog wxD (this,
-			wxTRANS("Current state has not been saved, would you like to save it now?")
-			,wxTRANS("State changed"),wxYES_NO|wxICON_QUESTION|wxYES_DEFAULT );
+			TRANS("Current state has not been saved, would you like to save it now?")
+			,TRANS("State changed"),wxYES_NO|wxICON_QUESTION|wxYES_DEFAULT );
 		wxD.SetAffirmativeId(wxID_YES);
 		wxD.SetEscapeId(wxID_NO);
 
@@ -1011,8 +1022,8 @@ void MainWindowFrame::OnFileOpen(wxCommandEvent &event)
 	}
 
 	//Load a file, either a state file, or a new pos file
-	wxFileDialog wxF(this,wxTRANS("Select Data or State File..."), wxT(""),
-		wxT(""),wxStr(totalStr),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
+	wxFileDialog wxF(this,TRANS("Select Data or State File..."), wxT(""),
+		wxT(""),(totalStr),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
 
 	//Show the file dialog	
 	if( (wxF.ShowModal() == wxID_CANCEL))
@@ -1021,11 +1032,13 @@ void MainWindowFrame::OnFileOpen(wxCommandEvent &event)
 	//See if the user would like to save state, if we are opening a state file
 	// which will overwrite our current state
 	std::string filePath = stlStr(wxF.GetPath());
-	if(guessFileType(filePath) == FILE_TYPE_XML)
+	if(guessFileType(filePath) == FILE_OPEN_TYPE_XML)
 		checkAskSaveState();
-		
-	
 	
+	//Force an update with an empty scene	
+	visControl.clear();
+	doSceneUpdate();
+
 	textConsoleOut->Clear();
 	//Get vis controller to update tree control to match internal
 	// structure. Retain tree selection & visibility if we currently
@@ -1065,8 +1078,8 @@ void MainWindowFrame::OnFileMerge(wxCommandEvent &event)
 		return;
 
 	//Load a file, either a state file, or a new pos file, or text file
-	wxFileDialog wxF(this,wxTRANS("Select Data or State File..."), wxT(""),
-		wxT(""),wxTRANS("3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|XML State File (*.xml)|*.xml|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
+	wxFileDialog wxF(this,TRANS("Select Data or State File..."), wxT(""),
+		wxT(""),TRANS("3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|XML State File (*.xml)|*.xml|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
 
 	//Show the file dialog	
 	if( (wxF.ShowModal() == wxID_CANCEL))
@@ -1096,6 +1109,7 @@ void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y)
 	//Try opening the files as range (if ext. agrees)
 	// or as 
 	bool loaded =false;
+	bool rangeLoaded=false;
 	for(unsigned int ui=0;ui<files.Count();ui++)
 	{
 		string ext;
@@ -1134,7 +1148,7 @@ void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y)
 				if(rng.openGuessFormat(s.c_str()))
 				{
 					rangeOK=true;
-
+					rangeLoaded=true;
 						
 					//Load rangefile &  construct filter
 					RangeFileFilter *f;
@@ -1143,9 +1157,12 @@ void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y)
 					f->setRangeData(rng);
 					f->setRangeFilename(s.c_str());
 
-					//Get the parent filter pointer	
+					//Add the filter, using the seelcted
+					// item as the parent
 					visControl.addFilter(f,false,filterId);
 
+					//update the tree control
+					visControl.updateWxTreeCtrl(treeFilters);
 				}
 				else
 				{
@@ -1155,6 +1172,7 @@ void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y)
 					//refresh (when we treat this as a pos file).
 					//FIXME: Something needs to go here... A queue for messages?
 				}
+			
 			}
 		}
 		//---
@@ -1185,6 +1203,9 @@ void MainWindowFrame::OnDropFiles(const wxArrayString &files, int x, int y)
 #endif
 	}
 
+	if(loaded || rangeLoaded)
+		doSceneUpdate();
+
 	if(files.Count())
 	{
 		//If we are using the default camera,
@@ -1211,7 +1232,7 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge,bool noUpdate
 		{
 			std::string str;
 			str=ss.str();
-			textConsoleOut->AppendText(wxStr(str));
+			textConsoleOut->AppendText((str));
 			//Note that the parent window must be NULL 
 			// if the parent window is not visible (eg autosave startup)
 			wxWindow *parentWin=NULL;
@@ -1227,8 +1248,8 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge,bool noUpdate
 		if(visControl.hasHazardousContents())
 		{
 			wxMessageDialog wxD(this,
-						wxTRANS("This state file contains filters that can be unsafe to run\nDo you wish to remove these before continuing?.") 
-						,wxTRANS("Security warning"),wxYES_NO|wxICON_WARNING|wxYES_DEFAULT );
+						TRANS("This state file contains filters that can be unsafe to run\nDo you wish to remove these before continuing?.") 
+						,TRANS("Security warning"),wxYES_NO|wxICON_WARNING|wxYES_DEFAULT );
 
 			wxD.SetAffirmativeId(wxID_YES);
 			wxD.SetEscapeId(wxID_NO);
@@ -1253,7 +1274,7 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge,bool noUpdate
 		for(unsigned int ui=1;ui<camNames.size();ui++)
 		{
 			//Do not delete as this will be deleted by wx
-			comboCamera->Append(wxStr(camNames[ui]),
+			comboCamera->Append((camNames[ui]),
 					(wxClientData *)new wxListUint(ui));	
 			//If this is the active cam (1) set the selection and (2) remember
 			//the ID
@@ -1265,19 +1286,19 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge,bool noUpdate
 		if(camNames.size() > 1)
 		{
 			//Use the remembered ID to update the grid.
-			visControl.updateCamPropertyGrid(gridCameraProperties,
+			visControl.updateCameraPropGrid(gridCameraProperties,
 						visControl.getActiveCamId());
 		}
 		else
 		{
 			//Reset the camera property fields & combo box
-			gridCameraProperties->clear();
-			comboCamera->SetValue(wxCStr(TRANS(cameraIntroString)));
+			gridCameraProperties->Clear();
+			comboCamera->SetValue((TRANS(cameraIntroString)));
 		}
 		}
 
 		//reset the stash combo box
-		comboStash->SetValue(wxCStr(TRANS(stashIntroString)));
+		comboStash->SetValue((TRANS(stashIntroString)));
 
 
 		//Check to see if we have any effects that we need to enable
@@ -1304,11 +1325,11 @@ bool MainWindowFrame::loadFile(const wxString &fileStr, bool merge,bool noUpdate
 		{
 			wxListUint *u;
 			u = new wxListUint(stashList[ui].second);
-			comboStash->Append(wxStr(stashList[ui].first),(wxClientData *)u);
+			comboStash->Append((stashList[ui].first),(wxClientData *)u);
 			ASSERT(comboStash->GetClientObject(comboStash->GetCount()-1));
 		}
 
-		gridFilterPropGroup->clear();
+		gridFilterPropGroup->Clear();
 
 	}
 	else 
@@ -1378,13 +1399,13 @@ void MainWindowFrame::OnRecentFile(wxCommandEvent &event)
 		else 
 		{
 			//See if the user wants to save the current state
-			if(guessFileType(stlStr(f)) == FILE_TYPE_XML)
+			if(guessFileType(stlStr(f)) == FILE_OPEN_TYPE_XML)
 				checkAskSaveState();
-		
-			if(loadFile(f))
+	
+			loadOK=loadFile(f);	
+			if(loadOK)
 			{
-				if(loadOK)
-					statusMessage(TRANS("Loaded file."),MESSAGE_INFO);
+				statusMessage(TRANS("Loaded file."),MESSAGE_INFO);
 				panelTop->forceRedraw();
 			}
 		}
@@ -1398,6 +1419,10 @@ void MainWindowFrame::OnRecentFile(wxCommandEvent &event)
 		}
 		
 		setSaveStatus();
+
+		//make sure camera is properly centred
+		if(visControl.numCams() == 1)
+			visControl.ensureSceneVisible(3);
 	}
 
 }
@@ -1409,7 +1434,7 @@ void MainWindowFrame::OnFileSave(wxCommandEvent &event)
 	//Save menu should not be selectable if there is no file to save to.
 	ASSERT(!saveFilename.empty());
 	//If the file does not exist, use saveas instead
-	if( saveFilename.empty()  || !wxFileExists(wxStr(saveFilename)))
+	if( saveFilename.empty()  || !wxFileExists((saveFilename)))
 	{
 		OnFileSaveAs(event);
 		return;
@@ -1425,7 +1450,7 @@ void MainWindowFrame::OnFileSave(wxCommandEvent &event)
 	{
 		//Update the recent files, and the menu.
 		configFile.addRecentFile(saveFilename);
-		recentHistory->AddFileToHistory(wxStr(saveFilename));
+		recentHistory->AddFileToHistory((saveFilename));
 	
 		std::string tmpStr;
 		tmpStr=	std::string("Saved state: ") + saveFilename;
@@ -1446,8 +1471,8 @@ void MainWindowFrame::OnFileExportPlot(wxCommandEvent &event)
 		return;
 	}
 
-	wxFileDialog wxF(this,wxTRANS("Save plot..."), wxT(""),
-		wxT(""),wxTRANS("By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*.svg|PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE);
+	wxFileDialog wxF(this,TRANS("Save plot..."), wxT(""),
+		wxT(""),TRANS("By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*.svg|PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE);
 
 	if( wxF.ShowModal() == wxID_CANCEL)
 		return;
@@ -1498,11 +1523,11 @@ void MainWindowFrame::OnFileExportPlot(wxCommandEvent &event)
 		const char *descriptions[] = {"PNG File", "Scalable Vector Graphic",""};
 		wxArrayString wxStrs;
 		for(size_t ui=0;ui<EXT_NONE;ui++)
-			wxStrs.Add(wxCStr(descriptions[ui]));
+			wxStrs.Add((descriptions[ui]));
 
 
-		wxSingleChoiceDialog  wxD(this,wxTRANS("Select type for save"),
-						wxTRANS("Choose file type"),wxStrs);
+		wxSingleChoiceDialog  wxD(this,TRANS("Select type for save"),
+						TRANS("Choose file type"),wxStrs);
 
 		if(wxD.ShowModal() == wxID_CANCEL)
 			return;
@@ -1522,7 +1547,7 @@ void MainWindowFrame::OnFileExportPlot(wxCommandEvent &event)
 	else if (strExt == "png")
 	{
 		//Show a resolution chooser dialog
-		ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution"));
+		ResolutionDialog d(this,wxID_ANY,TRANS("Choose resolution"));
 
 		int plotW,plotH;
 		panelSpectra->GetClientSize(&plotW,&plotH);
@@ -1556,16 +1581,30 @@ void MainWindowFrame::OnFileExportPlot(wxCommandEvent &event)
 
 void MainWindowFrame::OnFileExportImage(wxCommandEvent &event)
 {
-	wxFileDialog wxF(this,wxTRANS("Save Image..."), wxT(""),
-		wxT(""),wxTRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE);
+	wxFileDialog wxF(this,TRANS("Save Image..."), wxT(""),
+		wxT(""),TRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE);
+	std::string dataFile; 
+	do
+	{
 
-	if( (wxF.ShowModal() == wxID_CANCEL))
-		return;
+		if( (wxF.ShowModal() == wxID_CANCEL))
+			return;
 
-	std::string dataFile = stlStr(wxF.GetPath());
+		dataFile=stlStr(wxF.GetPath());
+
+		//ask user for confirm if file exists
+		if(!wxFileExists(wxF.GetPath()))
+			break;
+
+		wxMessageDialog wxMd(this,TRANS("File already exists. Overwrite?"),
+					TRANS("Overwrite?"),wxYES_NO|wxICON_WARNING);
+		
+		if( wxMd.ShowModal() == wxID_YES)
+			break;
+	} while(true); 
 	
 	//Show a resolution chooser dialog
-	ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution"));
+	ResolutionDialog d(this,wxID_ANY,TRANS("Choose resolution"));
 
 	//Use the current res as the dialog default
 	int w,h;
@@ -1594,14 +1633,14 @@ void MainWindowFrame::OnFileExportImage(wxCommandEvent &event)
 
 void MainWindowFrame::OnFileExportVideo(wxCommandEvent &event)
 {
-	wxFileDialog wxF(this,wxTRANS("Save Image..."), wxT(""),
-		wxT(""),wxTRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE);
+	wxFileDialog wxF(this,TRANS("Save Image..."), wxT(""),
+		wxT(""),TRANS("PNG File (*.png)|*.png|All Files (*)|*"),wxFD_SAVE);
 
 	if( (wxF.ShowModal() == wxID_CANCEL))
 		return;
 	
 	//Show a resolution chooser dialog
-	ResolutionDialog d(this,wxID_ANY,wxTRANS("Choose resolution"));
+	ResolutionDialog d(this,wxID_ANY,TRANS("Choose resolution"));
 
 	//Use the current res as the dialog default
 	int w,h;
@@ -1633,7 +1672,7 @@ void MainWindowFrame::OnFileExportVideo(wxCommandEvent &event)
 
 	///TODO: This is nasty and hackish. We should present a nice,
 	//well laid out dialog for frame count (show angular increment) 
-	wxTextEntryDialog teD(this,wxTRANS("Number of frames"),wxTRANS("Frame count"),
+	wxTextEntryDialog teD(this,TRANS("Number of frames"),TRANS("Frame count"),
 						wxT("180"),(long int)wxOK|wxCANCEL);
 
 	unsigned int numFrames=0;
@@ -1680,7 +1719,7 @@ void MainWindowFrame::setLockUI(bool locking=true,
 	{
 		case WINDOW_LOCK_REFRESH:
 		{
-			comboFilters->Enable(!locking);
+			comboFilters->Enable(!locking && visControl.numFilters());
 			refreshButton->Enable(!locking && visControl.numFilters());;
 			btnFilterTreeErrs->Enable(!locking);
 
@@ -1867,8 +1906,8 @@ void MainWindowFrame::OnFileExportFilterVideo(wxCommandEvent &event)
 	//Display modal progress dialog
 	//--
 	wxProgressDialog *prog;
-	prog = new wxProgressDialog(wxTRANS("Animating"),
-		wxTRANS("Performing refresh"),numFrames,this,wxPD_CAN_ABORT|wxPD_APP_MODAL );
+	prog = new wxProgressDialog(TRANS("Animating"),
+		TRANS("Performing refresh"),numFrames,this,wxPD_CAN_ABORT|wxPD_APP_MODAL );
 	prog->Show();
 	//--
 
@@ -2156,10 +2195,10 @@ void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event)
 	}
 		
 	//This could be nicer, or reordered
-	wxTextEntryDialog wxTD(this,wxTRANS("Package name"),
-					wxTRANS("Package directory name"),wxT(""),wxOK|wxCANCEL);
+	wxTextEntryDialog wxTD(this,TRANS("Package name"),
+					TRANS("Package directory name"),wxT(""),wxOK|wxCANCEL);
 
-	wxTD.SetValue(wxTRANS("AnalysisPackage"));
+	wxTD.SetValue(TRANS("AnalysisPackage"));
 
 	if(wxTD.ShowModal() == wxID_CANCEL)
 		return;
@@ -2172,8 +2211,8 @@ void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event)
 	wxDirDialog wxD(this);
 	res = wxD.ShowModal();
 	
-	wxMessageDialog wxMesD(this,wxTRANS("Package folder already exists, won't overwrite.")
-					,wxTRANS("Not available"),wxOK|wxICON_ERROR);
+	wxMessageDialog wxMesD(this,TRANS("Package folder already exists, won't overwrite.")
+					,TRANS("Not available"),wxOK|wxICON_ERROR);
 
 	while(res != wxID_CANCEL)
 	{
@@ -2198,8 +2237,8 @@ void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event)
 	//Check to see that the folder actually exists
 	if(!wxMkdir(folder))
 	{
-		wxMessageDialog wxMesD(this,wxTRANS("Package folder creation failed\ncheck writing to this location is possible.")
-						,wxTRANS("Folder creation failed"),wxOK|wxICON_ERROR);
+		wxMessageDialog wxMesD(this,TRANS("Package folder creation failed\ncheck writing to this location is possible.")
+						,TRANS("Folder creation failed"),wxOK|wxICON_ERROR);
 		wxMesD.ShowModal();
 		return;
 	}
@@ -2218,8 +2257,8 @@ void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event)
 	else
 	{
 		//Copy the files in the mapping
-		wxProgressDialog wxP(wxTRANS("Copying"),
-			wxTRANS("Copying referenced files"),fileMapping.size());
+		wxProgressDialog wxP(TRANS("Copying"),
+			TRANS("Copying referenced files"),fileMapping.size());
 
 		wxP.Show();
 		for(map<string,string>::iterator it=fileMapping.begin();
@@ -2273,7 +2312,7 @@ void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event)
 			}
 			else
 			{
-				copyError=!wxCopyFile(wxStr(it->second),folder+wxStr(it->first));
+				copyError=!wxCopyFile((it->second),folder+(it->first));
 			}
 
 			if(copyError)
@@ -2287,10 +2326,10 @@ void MainWindowFrame::OnFileExportPackage(wxCommandEvent &event)
 
 
 		wxString s;
-		s=wxString(wxTRANS("Saved package: ")) + folder;
+		s=wxString(TRANS("Saved package: ")) + folder;
 		if(wantDebugPack)
 		{
-			s+=wxCStr(" (debug mode)");
+			s+=(" (debug mode)");
 		}
 		statusMessage(stlStr(s).c_str(),MESSAGE_INFO);
 	}
@@ -2310,12 +2349,12 @@ void MainWindowFrame::OnFileExportIons(wxCommandEvent &event)
 	visControl.switchoutFilterTree(f);
 	
 	//Load up the export dialog
-	ExportPosDialog *exportDialog=new ExportPosDialog(this,wxID_ANY,wxTRANS("Export"));
+	ExportPosDialog *exportDialog=new ExportPosDialog(this,wxID_ANY,TRANS("Export"));
 	exportDialog->initialiseData(f);
 	
 	//create a file chooser for later.
-	wxFileDialog wxF(this,wxTRANS("Save pos..."), wxT(""),
-		wxT(""),wxTRANS("POS Data (*.pos)|*.pos|All Files (*)|*"),wxFD_SAVE);
+	wxFileDialog wxF(this,TRANS("Save pos..."), wxT(""),
+		wxT(""),TRANS("POS Data (*.pos)|*.pos|All Files (*)|*"),wxFD_SAVE);
 	
 	//If the user cancels the file chooser, 
 	//drop them back into the export dialog.
@@ -2343,8 +2382,8 @@ void MainWindowFrame::OnFileExportIons(wxCommandEvent &event)
 	//Check file already exists (no overwrite without asking)
 	if(wxFileExists(wxF.GetPath()))
 	{
-		wxMessageDialog wxD(this,wxTRANS("File already exists, overwrite?")
-				   ,wxTRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION);
+		wxMessageDialog wxD(this,TRANS("File already exists, overwrite?")
+				   ,TRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION);
 
 		if(wxD.ShowModal() == wxID_CANCEL)
 		{
@@ -2400,7 +2439,7 @@ void MainWindowFrame::OnFileExportRange(wxCommandEvent &event)
 				MESSAGE_ERROR);
 		return;
 	}
-	ExportRngDialog *rngDialog = new ExportRngDialog(this,wxID_ANY,wxTRANS("Export Ranges"),
+	ExportRngDialog *rngDialog = new ExportRngDialog(this,wxID_ANY,TRANS("Export Ranges"),
 							wxDefaultPosition,wxSize(600,400));
 
 	vector<const Filter *> rangeData;
@@ -2423,8 +2462,8 @@ void MainWindowFrame::OnFileExportRange(wxCommandEvent &event)
 void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event)
 {
 	//Show a file save dialog
-	wxFileDialog wxF(this,wxTRANS("Save state..."), wxT(""),
-		wxT(""),wxTRANS("XML state file (*.xml)|*.xml|All Files (*)|*"),wxFD_SAVE);
+	wxFileDialog wxF(this,TRANS("Save state..."), wxT(""),
+		wxT(""),TRANS("XML state file (*.xml)|*.xml|All Files (*)|*"),wxFD_SAVE);
 
 	//Show, then check for user cancelling dialog
 	if( (wxF.ShowModal() == wxID_CANCEL))
@@ -2441,8 +2480,8 @@ void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event)
 	//Check file already exists (no overwrite without asking)
 	if(wxFileExists(wxF.GetPath()))
 	{
-		wxMessageDialog wxD(this,wxTRANS("File already exists, overwrite?")
-						,wxTRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION);
+		wxMessageDialog wxD(this,TRANS("File already exists, overwrite?")
+						,TRANS("Overwrite?"),wxOK|wxCANCEL|wxICON_QUESTION);
 
 		if(wxD.ShowModal() == wxID_CANCEL)
 			return;
@@ -2465,8 +2504,8 @@ void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event)
 	//and if so, do any of our filters
 	if(visControl.usingRelPaths() && visControl.hasStateOverrides())
 	{
-		wxMessageDialog wxD(this,wxTRANS("Files have been referred to using relative paths. Keep relative paths?")
-						,wxTRANS("Overwrite?"),wxYES|wxNO|wxICON_QUESTION);
+		wxMessageDialog wxD(this,TRANS("Files have been referred to using relative paths. Keep relative paths?")
+						,TRANS("Overwrite?"),wxYES|wxNO|wxICON_QUESTION);
 	
 		wxD.SetEscapeId(wxID_NO);
 		wxD.SetAffirmativeId(wxID_YES);
@@ -2496,7 +2535,7 @@ void MainWindowFrame::OnFileSaveAs(wxCommandEvent &event)
 
 		//Update the recent files, and the menu.
 		configFile.addRecentFile(dataFile);
-		recentHistory->AddFileToHistory(wxStr(dataFile));
+		recentHistory->AddFileToHistory((dataFile));
 	
 		dataFile=std::string(TRANS("Saved state: ")) + dataFile;
 		statusMessage(dataFile.c_str(),MESSAGE_INFO);
@@ -2536,7 +2575,7 @@ void MainWindowFrame::OnEditUndo(wxCommandEvent &event)
 	}
 	else
 	{
-		gridFilterPropGroup->clear();
+		gridFilterPropGroup->Clear();
 		updateLastRefreshBox();
 	}
 
@@ -2564,7 +2603,7 @@ void MainWindowFrame::OnEditRedo(wxCommandEvent &event)
 	}
 	else
 	{
-		gridFilterPropGroup->clear();
+		gridFilterPropGroup->Clear();
 		updateLastRefreshBox();
 	}
 
@@ -2575,7 +2614,7 @@ void MainWindowFrame::OnEditRedo(wxCommandEvent &event)
 
 void MainWindowFrame::OnEditRange(wxCommandEvent &event)
 {
-	RangeEditorDialog *r = new RangeEditorDialog(this,wxID_ANY,wxTRANS("Range editor"));
+	RangeEditorDialog *r = new RangeEditorDialog(this,wxID_ANY,TRANS("Range editor"));
 
 	r->setPlotWrapper(*(visControl.getPlotWrapper()));
 
@@ -2812,64 +2851,23 @@ void MainWindowFrame::OnHelpHelp(wxCommandEvent &event)
 	if(!s.size())
 		s=locateDataFile("3depict-manual.pdf");
 
+	//FIXME: under windows, currently we use "manual.pdf"
+	if(!s.size())
+		s=locateDataFile("manual.pdf");
 
 	//If we found it, use the default program associated with that data file
 	bool launchedOK=false;
-	if( wxFileExists(wxStr(s))  && s.size())
+	if( wxFileExists((s))  && s.size())
 	{
 		//we found the manual. Launch the default handler.
-#if wxCHECK_VERSION(2, 9, 0)
-		launchedOK=wxLaunchDefaultApplication(wxStr(s));
-#else
-		//its a bit more convoluted for earlier versions of wx.
-		//we have to try xdg-open or open for Linux and mac respectively
-		//for windows, we need to use the wxWidgets GetOpenCommand
-	
-		long appPID;
-
-	#if defined(__linux__)
-		//Try xdg-open first
-		wxString str;
-		str= wxT("xdg-open ");
-		str+=wxStr(s);
-		appPID=wxExecute(str,wxEXEC_ASYNC);
-		launchedOK=(appPID!=0);
-	#elif defined(__APPLE__)
-		//Try open first
-		wxString str;
-		str= wxT("open ");
-		str+=wxStr(s);
-		appPID=wxExecute(str,wxEXEC_ASYNC);
-		launchedOK=(appPID!=0);
-	#endif
-
-		//No luck still? Try wx's quirky GetOpenCommand		
-		if(!launchedOK)
-		{
-			wxString command;
-			//Sigh. In version < 2.9; wx uses the mime-type
-			//manager to wrap up the construction
-			//of wxFileType object (private constructor).
-			//so we can't just *make* a wxFileType
-			//we have to derive one from a "mime-type manager".
-			//the only way to do this is from the file extension
-			//or by passing the mime-string.
-			wxMimeTypesManager m;
-			wxFileType *t;
-				
-			t=m.GetFileTypeFromExtension(wxT("pdf"));
-			command=t->GetOpenCommand(wxStr(s));
-			appPID=wxExecute(command,wxEXEC_ASYNC);
-			launchedOK=(appPID!=0);
-		}
-#endif
+		launchedOK=wxLaunchDefaultApplication((s));
 	}
 
 	//Still no go? Give up and launch a browser.
 	if(!launchedOK)
 	{
 		std::string helpFileLocation("http://threedepict.sourceforge.net/documentation.html");
-		wxLaunchDefaultBrowser(wxStr(helpFileLocation),wxBROWSER_NEW_WINDOW);
+		wxLaunchDefaultBrowser((helpFileLocation),wxBROWSER_NEW_WINDOW);
 
 		statusMessage(TRANS("Manual not found locally. Launching web browser"),MESSAGE_INFO);
 	}
@@ -2878,7 +2876,7 @@ void MainWindowFrame::OnHelpHelp(wxCommandEvent &event)
 void MainWindowFrame::OnHelpContact(wxCommandEvent &event)
 {
 	std::string contactFileLocation("http://threedepict.sourceforge.net/contact.html");
-	wxLaunchDefaultBrowser(wxStr(contactFileLocation),wxBROWSER_NEW_WINDOW);
+	wxLaunchDefaultBrowser((contactFileLocation),wxBROWSER_NEW_WINDOW);
 
 	statusMessage(TRANS("Opening contact page in external web browser"),MESSAGE_INFO);
 }
@@ -2896,7 +2894,7 @@ void MainWindowFrame::OnButtonStashDialog(wxCommandEvent &event)
 		return;
 	}
 
-	StashDialog *s = new StashDialog(this,wxID_ANY,wxTRANS("Filter Stashes"));
+	StashDialog *s = new StashDialog(this,wxID_ANY,TRANS("Filter Stashes"));
 	s->setVisController(&visControl);
 	s->ready();
 	s->ShowModal();
@@ -2912,7 +2910,7 @@ void MainWindowFrame::OnButtonStashDialog(wxCommandEvent &event)
 	{
 		wxListUint *u;
 		u = new wxListUint(stashVec[ui].second);
-		comboStash->Append(wxStr(stashVec[ui].first),(wxClientData *)u);
+		comboStash->Append((stashVec[ui].first),(wxClientData *)u);
 		ASSERT(comboStash->GetClientObject(comboStash->GetCount()-1));
 	}
 
@@ -2923,9 +2921,9 @@ void MainWindowFrame::OnButtonStashDialog(wxCommandEvent &event)
 void MainWindowFrame::OnHelpAbout(wxCommandEvent &event)
 {
 	wxAboutDialogInfo info;
-	info.SetName(wxCStr(PROGRAM_NAME));
-	info.SetVersion(wxCStr(PROGRAM_VERSION));
-	info.SetDescription(wxTRANS("Quick and dirty analysis for point data.")); 
+	info.SetName((PROGRAM_NAME));
+	info.SetVersion((PROGRAM_VERSION));
+	info.SetDescription(TRANS("Quick and dirty analysis for point data.")); 
 	info.SetWebSite(wxT("https://sourceforge.net/apps/phpbb/threedepict/"));
 
 	info.AddDeveloper(wxT("D. Haley"));	
@@ -2935,7 +2933,7 @@ void MainWindowFrame::OnHelpAbout(wxCommandEvent &event)
 
 	info.AddArtist(_T("Thanks go to all who have developed the libraries that I use, which make this program possible.\n This includes the wxWidgets team, Alexy Balakin (MathGL), the FTGL and freetype people, the GNU Scientific Library contributors, the tree.h guy (Kasper Peeters)  and more."));
 
-	info.AddArtist(wxString(wxTRANS("Compiled with wx Version: " )) + 
+	info.AddArtist(wxString(TRANS("Compiled with wx Version: " )) + 
 			wxString(wxSTRINGIZE_T(wxVERSION_STRING)));
 
 	wxArrayString s;
@@ -3002,7 +3000,7 @@ void MainWindowFrame::OnComboStashEnter(wxCommandEvent &event)
 		}
 
 		unsigned int n =visControl.stashFilters(filterId,userText.c_str());
-		n=comboStash->Append(wxStr(userText),(wxClientData *)new wxListUint(n));
+		n=comboStash->Append((userText),(wxClientData *)new wxListUint(n));
 		ASSERT(comboStash->GetClientObject(n));
 		
 		statusMessage(TRANS("Created new filter tree stash"),MESSAGE_INFO);
@@ -3043,6 +3041,11 @@ void MainWindowFrame::OnComboStashEnter(wxCommandEvent &event)
 	comboStash->SetValue(wxT(""));
 }
 
+void MainWindowFrame::OnComboFilterText(wxCommandEvent &event)
+{
+	//prevent user from modifying text
+	comboFilters->ChangeValue(TRANS(ADD_FILTER_TEXT));
+}
 
 void MainWindowFrame::OnComboStash(wxCommandEvent &event)
 {
@@ -3161,18 +3164,15 @@ void MainWindowFrame::OnTreeSelectionChange(wxTreeEvent &event)
 	size_t filterId;
 	if(!getTreeFilterId(treeFilters->GetSelection(),filterId))
 	{
-		gridFilterPropGroup->clear();
+		gridFilterPropGroup->Clear();
 		return;
 	}
 
+	comboFilters->Enable();
 	visControl.updateFilterPropGrid(gridFilterPropGroup, filterId);
 
 	updateLastRefreshBox();
 	
-
-#if !wxCHECK_VERSION(2,9,0)
-	treeFilters->Fit();	
-#endif
 	panelTop->forceRedraw();
 
 }
@@ -3183,13 +3183,18 @@ void MainWindowFrame::updateLastRefreshBox()
 	size_t filterId;
 	if(!getTreeFilterId(treeFilters->GetSelection(),filterId))
 		return;
-	//retrieve the current active filter
-	const Filter *f= visControl.getFilterById(filterId);
-	
+
+	if(!visControl.getNumFilters())
+	{
+		listLastRefresh->DeleteAllItems();
+		return;
+	}	
 	//Prevent update flicker by disabling interaction
 	listLastRefresh->Freeze();
-
 	listLastRefresh->DeleteAllItems();
+	
+	//retrieve the current active filter
+	const Filter *f= visControl.getFilterById(filterId);
 	for(unsigned int ui=0;ui<NUM_STREAM_TYPES; ui++)
 	{
 		//Add items to the listbox in the form "type" "count"
@@ -3201,8 +3206,8 @@ void MainWindowFrame::updateLastRefreshBox()
 		{
 			long index;
 			stream_cast(n,numOut);
-			index=listLastRefresh->InsertItem(0,wxCStr(TRANS(STREAM_NAMES[ui])));
-			listLastRefresh->SetItem(index,1,wxStr(n));
+			index=listLastRefresh->InsertItem(0,(TRANS(STREAM_NAMES[ui])));
+			listLastRefresh->SetItem(index,1,(n));
 		}
 	}
 	listLastRefresh->Thaw();
@@ -3228,9 +3233,10 @@ void MainWindowFrame::OnTreeDeleteItem(wxTreeEvent &event)
 		event.Veto();
 		return;
 	}
-	//This event is only generated programatically, 
-	//Currently it *purposely* does nothing in the
-	//not updating case
+	//This event is only generated programatically,
+	// we do not have to handle the direct deletion.
+
+	listLastRefresh->DeleteAllItems();
 }
 
 void MainWindowFrame::OnTreeBeginLabelEdit(wxTreeEvent &event)
@@ -3371,10 +3377,6 @@ void MainWindowFrame::OnBtnFilterTreeErrs(wxCommandEvent &event)
 
 }
 
-//There appears to be a bug in MSW wx 3.0. Key down events don't work
-// in MSW (including in the wx official samples). To work around, use generic
-// KEY_DOWN event
-#if defined(WX_TREE_WORKAROUND)
 void MainWindowFrame::OnTreeKeyDown(wxKeyEvent &event)
 {
  	if(currentlyUpdatingScene)
@@ -3417,7 +3419,7 @@ void MainWindowFrame::OnTreeKeyDown(wxKeyEvent &event)
 			//Remove the item from the Tree 
 			visControl.removeFilterSubtree(((wxTreeUint *)tData)->value);
 			//Clear property grid
-			gridFilterPropGroup->clear();
+			gridFilterPropGroup->Clear();
 			if(parent !=treeFilters->GetRootItem())
 			{
 				ASSERT(parent.IsOk()); // should be - base node should always exist.
@@ -3455,93 +3457,14 @@ void MainWindowFrame::OnTreeKeyDown(wxKeyEvent &event)
 	}
 }
 
-#else
 
-void MainWindowFrame::OnTreeKeyDown(wxTreeEvent &event)
+void MainWindowFrame::OnGridFilterPropertyChange(wxPropertyGridEvent &event)
 {
-	if(currentlyUpdatingScene)
-	{
-		event.Veto();
-		return;
-	}
-	const wxKeyEvent k = event.GetKeyEvent();
-	switch(k.GetKeyCode())
-	{
-		case WXK_BACK:
-		case WXK_DELETE:
-		{
-			wxTreeItemId id;
-
-			if(!treeFilters->GetCount())
-				return;
-
-			id=treeFilters->GetSelection();
-
-			if(!id.IsOk() || id == treeFilters->GetRootItem())
-				return;
-
-
-			//TODO: Refactor out wxTreeItem... code, into separate routine
-			// that only spits out viscontrol Ids
-			//Rebuild the tree control, ensuring that the parent is visible,
-			//if it has a parent (recall root node  of wx control is hidden)
-			
-			//Get the parent & its data
-			wxTreeItemId parent = treeFilters->GetItemParent(id);
-			wxTreeItemData *parentData=treeFilters->GetItemData(parent);
-
-			//Ask viscontrol to ensure that the parent stays persistently
-			// visible when next rebuilding the tree control
-			visControl.setWxTreeFilterViewPersistence(
-					((wxTreeUint*)parentData)->value);	
-
-			//Tree data contains unique identifier for vis control to do matching
-			wxTreeItemData *tData=treeFilters->GetItemData(id);
-			//Remove the item from the Tree 
-			visControl.removeFilterSubtree(((wxTreeUint *)tData)->value);
-			//Clear property grid
-			gridFilterPropGroup->clear();
-			if(parent !=treeFilters->GetRootItem())
-			{
-				ASSERT(parent.IsOk()); // should be - base node should always exist.
-
-				//Ensure that the parent stays visible 
-				visControl.setWxTreeFilterViewPersistence(
-						((wxTreeUint*)parentData)->value);
-				visControl.updateWxTreeCtrl(treeFilters);
 
-				
-				//OK, so those old Id s are no longer valid,
-				//as we just rebuilt the tree. We need new ones
-				//Parent is now selected
-				parent=treeFilters->GetSelection();
-				parentData=treeFilters->GetItemData(parent);
-
-
-				//Update the filter property grid with the parent's data
-				visControl.updateFilterPropGrid(gridFilterPropGroup,
-							((wxTreeUint *)parentData)->value);
-			}
-			else
-			{
-				if(parent.IsOk())
-					visControl.updateWxTreeCtrl(treeFilters);
-			}
+	//Silence error mesages
+	// we will handle validation in the backend
+	event.SetValidationFailureBehavior(0);
 	
-			//Force a scene update, independent of if autoUpdate is enabled. 
-			doSceneUpdate();	
-		
-			break;
-		}
-		default:
-			event.Skip();
-	}
-}
-#endif
-
-void MainWindowFrame::OnGridFilterPropertyChange(wxGridEvent &event)
-{
-
 	if(programmaticEvent || currentlyUpdatingScene || visControl.isRefreshing())
 	{
 		event.Veto();
@@ -3550,12 +3473,7 @@ void MainWindowFrame::OnGridFilterPropertyChange(wxGridEvent &event)
 
 	programmaticEvent=true;
 	//Should only be in the second col
-	ASSERT(event.GetCol()==1);
-
-	std::string value; 
-	value = stlStr(gridFilterPropGroup->GetCellValue(
-					event.GetRow(),1));
-
+	
 	size_t filterId;
 	if(!getTreeFilterId(treeFilters->GetSelection(),filterId))
 	{
@@ -3564,10 +3482,19 @@ void MainWindowFrame::OnGridFilterPropertyChange(wxGridEvent &event)
 	}
 
 
+
+	//Obtain the key/value pairing that we are about to set
+	std::string newValue,keyStr;
+	newValue=getPropValueFromEvent(event);
+	
+	size_t key;
+	keyStr=event.GetProperty()->GetName();
+	stream_cast(key,keyStr);
+
+	//Try to apply the new value
 	bool needUpdate;
-	int row=event.GetRow();
 	if(!visControl.setFilterProperty(filterId,
-		gridFilterPropGroup->getKeyFromRow(row),value,needUpdate))
+				key,newValue,needUpdate))
 	{
 		event.Veto();
 		programmaticEvent=false;
@@ -3580,13 +3507,30 @@ void MainWindowFrame::OnGridFilterPropertyChange(wxGridEvent &event)
 	else 
 		clearWxTreeImages(treeFilters);
 
-	visControl.updateFilterPropGrid(gridFilterPropGroup,filterId);
+	//See wx bug #16222 - cannot modify a property grid's contents
+	// from a change event. Must work in a side-objectm then swap
+	//--
+	backFilterPropGrid= new wxPropertyGrid(filterPropertyPane,ID_GRID_FILTER_PROPERTY,
+					wxDefaultPosition,wxDefaultSize,PROPERTY_GRID_STYLE);
+	backFilterPropGrid->SetExtraStyle(PROPERTY_GRID_EXTRA_STYLE);
+
+	
+	visControl.updateFilterPropGrid(backFilterPropGrid,filterId,
+			stlStr(gridFilterPropGroup->SaveEditableState()));
+
+	std::swap(backFilterPropGrid,gridFilterPropGroup);
+	do_filtergrid_prop_layout();
+	//--
 
-	Layout();
 	programmaticEvent=false;
 }
 
-void MainWindowFrame::OnGridCameraPropertyChange(wxGridEvent &event)
+void MainWindowFrame::OnGridFilterDClick(wxPropertyGridEvent &event)
+{
+	Refresh();
+}
+
+void MainWindowFrame::OnGridCameraPropertyChange(wxPropertyGridEvent &event)
 {
 
 	if(programmaticEvent)
@@ -3596,14 +3540,48 @@ void MainWindowFrame::OnGridCameraPropertyChange(wxGridEvent &event)
 	}
 
 	programmaticEvent=true;
-	//Should only be in the second col
-	ASSERT(event.GetCol()==1);
+	
+	std::string eventType,newValue;
+	eventType=event.GetValue().GetType();
+	if(eventType == "long")
+	{
+		//Either integer property or enum
+		//integer property
+		wxLongLong ll;
+		ll=event.GetValue().GetLong();
+		
+		const wxPGChoices &choices = event.GetProperty()->GetChoices();
+		if(!choices.IsOk())
+		{
+			stream_cast(newValue,ll);
+		}
+		else
+		{
+			//So wx makes life har dhere. We need to do a dance to get the selection
+			// as a string
+			unsigned int ul;
+			ul=ll.ToLong();
+
+			wxArrayString arrStr;
+			arrStr=choices.GetLabels();
+			newValue=arrStr[ul];
+		}
+	}
+	else
+	{
+		//We don't need colour props in camera
+		// not implemented
+		ASSERT(eventType != "wxColour");
+		newValue =  event.GetValue().GetString();
+	}
+
 
-	std::string value; 
-	value = stlStr(gridCameraProperties->GetCellValue(
-					event.GetRow(),1));
+	std::string keyStr;
+	size_t key;
+	keyStr=event.GetProperty()->GetName();
+	stream_cast(key,keyStr);
 
-	//Get the camera ID value (long song and dance that it is)
+	//Get the camera ID value 
 	wxListUint *l;
 	int n = comboCamera->FindString(comboCamera->GetValue());
 	if(n == wxNOT_FOUND)
@@ -3618,23 +3596,27 @@ void MainWindowFrame::OnGridCameraPropertyChange(wxGridEvent &event)
 	size_t cameraId;
 	cameraId = l->value;
 
-	int row=event.GetRow();
-	if(visControl.setCamProperties(cameraId,gridCameraProperties->getKeyFromRow(row),value))
-		visControl.updateCamPropertyGrid(gridCameraProperties,cameraId);
-	else
-		event.Veto();
+	//Set property
+	visControl.setCamProperties(cameraId,key,newValue);
 
+	//FIXME :Need to send the ne grid, not the old, due to wx bug
+	//See wx bug #16222 - cannot modify a property grid's contents
+	// from a change event. Must work in a side-objectm then swap
+	//--
+	backCameraPropGrid= new wxPropertyGrid(noteCamera,ID_GRID_CAMERA_PROPERTY,
+					wxDefaultPosition,wxDefaultSize,PROPERTY_GRID_STYLE);
+	backCameraPropGrid->SetExtraStyle(PROPERTY_GRID_EXTRA_STYLE);
+	
+	visControl.updateCameraPropGrid(backCameraPropGrid,cameraId);
+	
+	std::swap(backCameraPropGrid,gridCameraProperties);
+	do_cameragrid_prop_layout();
+
+	//Ensure that the GL panel shows latest cam orientation 
 	panelTop->forceRedraw();
 	programmaticEvent=false;
-
-
 }
 
-void MainWindowFrame::OnCameraGridCellEditorHide(wxGridEvent &e)
-{
-	//Unlock the camera combo, now that we have finished editing
-	comboCamera->Enable(true);
-}
 
 void MainWindowFrame::OnComboCameraText(wxCommandEvent &event)
 {
@@ -3678,7 +3660,7 @@ void MainWindowFrame::OnComboCameraEnter(wxCommandEvent &event)
 		statusMessage(s.c_str(),MESSAGE_INFO);
 		
 		//refresh the camera property grid
-		visControl.updateCamPropertyGrid(gridCameraProperties ,l->value);
+		visControl.updateCameraPropGrid(gridCameraProperties ,l->value);
 
 		setSaveStatus();
 
@@ -3697,7 +3679,7 @@ void MainWindowFrame::OnComboCameraEnter(wxCommandEvent &event)
 	statusMessage(s.c_str(),MESSAGE_INFO);
 
 	visControl.setCam(u);
-	visControl.updateCamPropertyGrid(gridCameraProperties,u);
+	visControl.updateCameraPropGrid(gridCameraProperties,u);
 	panelTop->forceRedraw();
 
 	setSaveStatus();
@@ -3712,7 +3694,7 @@ void MainWindowFrame::OnComboCamera(wxCommandEvent &event)
 
 
 
-	visControl.updateCamPropertyGrid(gridCameraProperties,l->value);
+	visControl.updateCameraPropGrid(gridCameraProperties,l->value);
 
 	std::string s = std::string(TRANS("Restored camera: ") ) +stlStr(comboCamera->GetValue());	
 	statusMessage(s.c_str(),MESSAGE_INFO);
@@ -3765,6 +3747,7 @@ void MainWindowFrame::OnComboFilterEnter(wxCommandEvent &event)
 	OnComboFilter(event);
 }
 
+
 void MainWindowFrame::OnComboFilter(wxCommandEvent &event)
 {
 	if(currentlyUpdatingScene)
@@ -3777,6 +3760,9 @@ void MainWindowFrame::OnComboFilter(wxCommandEvent &event)
 			statusMessage(TRANS("Select an item from the filter tree before choosing a new filter"));
 		else
 			statusMessage(TRANS("Load data source (file->open) before choosing a new filter"));
+
+		comboFilters->SetSelection(wxNOT_FOUND);
+		comboFilters->ChangeValue(TRANS(ADD_FILTER_TEXT));
 		return;
 	}
 
@@ -3797,8 +3783,8 @@ void MainWindowFrame::OnComboFilter(wxCommandEvent &event)
 		case FILTER_TYPE_RANGEFILE:
 		{
 			///Prompt user for file
-			wxFileDialog wxF(this,wxTRANS("Select RNG File..."),wxT(""),wxT(""),
-					wxTRANS("Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
+			wxFileDialog wxF(this,TRANS("Select RNG File..."),wxT(""),wxT(""), 
+					TRANS(RANGEFILE_WX_CONSTANT),wxFD_OPEN|wxFD_FILE_MUST_EXIST);
 			
 
 			if( (wxF.ShowModal() == wxID_CANCEL))
@@ -3854,7 +3840,8 @@ void MainWindowFrame::OnComboFilter(wxCommandEvent &event)
 	if(haveErr)
 	{
 		//Clear the combo box
-		comboFilters->SetValue(wxT(""));
+		comboFilters->SetSelection(wxNOT_FOUND);
+		comboFilters->ChangeValue(TRANS(ADD_FILTER_TEXT));
 		return;
 	}
 
@@ -3862,7 +3849,8 @@ void MainWindowFrame::OnComboFilter(wxCommandEvent &event)
 	if(checkAutoUpdate->GetValue())
 		doSceneUpdate();
 
-	comboFilters->SetValue(wxT(""));
+	comboFilters->SetSelection(wxNOT_FOUND);
+	comboFilters->ChangeValue(TRANS(ADD_FILTER_TEXT));
 	
 }
 
@@ -3880,7 +3868,7 @@ bool MainWindowFrame::doSceneUpdate()
 
 		
 	statusMessage("",MESSAGE_NONE);
-	noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons."));
+	noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,TRANS("Cons."));
 
 	//Disable tree filters,refresh button and undo
 	setLockUI(true);
@@ -3892,6 +3880,7 @@ bool MainWindowFrame::doSceneUpdate()
 	//Set focus on the main frame itself, so that we can catch escape key presses
 	SetFocus();
 
+	wxBusyCursor busyCursor;
 	unsigned int errCode=visControl.refreshFilterTree();
 
 	progressTimer->Stop();
@@ -3946,13 +3935,13 @@ bool MainWindowFrame::doSceneUpdate()
 
 	//Add (or hide) a little "Star" to inform the user there is some info available
 	if(textConsoleOut->IsEmpty() || noteDataView->GetSelection()==NOTE_CONSOLE_PAGE_OFFSET)
-		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons."));
+		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,TRANS("Cons."));
 	else
 	{
 #if defined(__WIN32) || defined(__WIN64)
-		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("*Cons."));
+		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,TRANS("*Cons."));
 #else
-		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("§Cons."));
+		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,TRANS("§Cons."));
 #endif
 	}
 
@@ -4024,25 +4013,36 @@ void MainWindowFrame::setFilterTreeAnalysisImages()
 	//apply the filter->icon mapping
 	setWxTreeImages(treeFilters,iconSettings);
 	
-#if defined(__WIN32) || defined(__WIN64)
-	//HACK: Under MSW, force button to correct positioning, by forcing a relayout
-#if !wxCHECK_VERSION(2,9,0)
-	treeFilters->GetParent()->Layout();
-#endif
-#endif
 }
 
 void MainWindowFrame::OnStatusBarTimer(wxTimerEvent &event)
 {
-	for(unsigned int ui=0; ui<3; ui++)
+	if(statusQueue.empty())
 	{
+		//clear the status bar colour, then wipe the status text from each field
 		MainFrame_statusbar->SetBackgroundColour(wxNullColour);
-		MainFrame_statusbar->SetStatusText(wxT(""),ui);
-	}
-	
-	
-	//Stop the status timer, just in case
-	statusTimer->Stop();
+		for(unsigned int ui=0; ui<3; ui++)
+			MainFrame_statusbar->SetStatusText(wxT(""),ui);
+		
+		//Stop the status timer, as we are done 
+		statusTimer->Stop();
+	}	
+	else
+	{
+		//update the status bar with the next
+		// message
+		std::string msg,tmpStr;
+		if(statusQueue.size() > 1)
+		{
+			stream_cast(tmpStr,statusQueue.size());
+			msg = tmpStr + string(" ") + TRANS("msgs");
+			msg+=" : ";
+		}
+		msg+= statusQueue.front().second,
+		showStatusMessage(msg.c_str(),
+				statusQueue.front().first);
+		statusQueue.pop_front();
+	}	
 }
 
 void MainWindowFrame::OnProgressTimer(wxTimerEvent &event)
@@ -4056,7 +4056,7 @@ void MainWindowFrame::OnAutosaveTimer(wxTimerEvent &event)
 	//with the title "autosave.xml"
 	//
 
-	wxString filePath = wxStr(configFile.getConfigDir());
+	wxString filePath = (configFile.getConfigDir());
 
 	unsigned int pid;
 	pid = wxGetProcessId();
@@ -4064,8 +4064,8 @@ void MainWindowFrame::OnAutosaveTimer(wxTimerEvent &event)
 	std::string pidStr;
 	stream_cast(pidStr,pid);
 
-	filePath+=wxFileName::GetPathSeparator()+ wxCStr(AUTOSAVE_PREFIX) + wxStr(pidStr) +
-				wxCStr(AUTOSAVE_SUFFIX);
+	filePath+=wxFileName::GetPathSeparator()+ string(AUTOSAVE_PREFIX) + (pidStr) +
+				string(AUTOSAVE_SUFFIX);
 	//Save to the autosave file
 	std::string s;
 	s=  stlStr(filePath);
@@ -4155,7 +4155,7 @@ void MainWindowFrame::OnUpdateTimer(wxTimerEvent &event)
 			wxListUint *l;
 			l =(wxListUint*)  comboCamera->GetClientObject(n);
 
-			visControl.updateCamPropertyGrid(gridCameraProperties,l->value);
+			visControl.updateCameraPropGrid(gridCameraProperties,l->value);
 		}
 
 		panelTop->clearCameraUpdates();
@@ -4185,50 +4185,79 @@ void MainWindowFrame::OnUpdateTimer(wxTimerEvent &event)
 
 void MainWindowFrame::statusMessage(const char *message, unsigned int type)
 {
-	bool sendMessage=true;
+
+	if(type == MESSAGE_NONE)
+	{
+		statusTimer->Stop();
+		statusQueue.clear();
+		
+		//clear the status bar colour, then wipe the status text from each field
+		MainFrame_statusbar->SetBackgroundColour(wxNullColour);
+		for(unsigned int ui=0; ui<3; ui++)
+			MainFrame_statusbar->SetStatusText(wxT(""),ui);
+		
+	}
+	else
+	{
+		if(statusTimer->IsRunning())
+		{
+			//go through and strip
+			// other hints
+			for(list<pair<unsigned int,string> >::iterator it=statusQueue.begin();
+				it!=statusQueue.end(); )
+			{
+				if(it->first != MESSAGE_HINT)
+				{
+					++it;	
+					continue;
+				}
+				
+				it=statusQueue.erase(it);
+			}
+				
+			//Emplace our message
+			statusQueue.push_back(make_pair(type,message));	
+
+			//keep only unique messages 
+			list<pair<unsigned int,string> >::iterator tmpIt;
+			tmpIt= std::unique(statusQueue.begin(),statusQueue.end());
+			statusQueue.erase(tmpIt,statusQueue.end());	
+			
+			if(!statusQueue.empty())
+			showStatusMessage(statusQueue.begin()->second.c_str(),statusQueue.begin()->first);	
+
+			
+		}
+		else
+		{
+			showStatusMessage(message,type);	
+			statusTimer->Start(STATUS_TIMER_DELAY);
+		}
+	}
+}
+
+void MainWindowFrame::showStatusMessage(const char *message, unsigned int type)
+{
+	//Wx does not support statusbar colouring under MSW
+	// using this can result in visual oddness
+	#if !(defined(__WIN32) || defined(__WIN64))
 	switch(type)
 	{
 		case MESSAGE_ERROR:
-		//Wx does not support statusbar colouring under MSW
-		// using this can result in visual oddness
-		#if !(defined(__WIN32) || defined(__WIN64))
 			MainFrame_statusbar->SetBackgroundColour(*wxGREEN);
-		#endif
 			break;
 		case MESSAGE_INFO:
-		//Wx does not support statusbar colouring under MSW, and using this can result in visual oddness
-		#if !(defined(__WIN32) || defined(__WIN64))
 			MainFrame_statusbar->SetBackgroundColour(*wxCYAN);
-		#endif
 			break;
 		case MESSAGE_HINT:
-			break;
-		//Pseudo-messages
-		case MESSAGE_NONE:
-			// No actions needed, just supply the message
-			ASSERT( string(message)== string(""));
 			MainFrame_statusbar->SetBackgroundColour(wxNullColour);
 			break;
-		case MESSAGE_NONE_BUT_HINT:
-			ASSERT( string(message)== string(""));
-			//we need to clear any messages other than "hintMessage"
-			sendMessage=(lastMessageType==MESSAGE_HINT);
-			break;
 		default:
 			ASSERT(false);
 	}
-
-	lastMessageType=type;
+	#endif
 	
-	if(sendMessage)
-	{
-		MainFrame_statusbar->SetStatusText(wxCStr(message),0);
-		for(size_t ui=1;ui<3; ui++)
-		{
-			MainFrame_statusbar->SetStatusText(wxT(""),ui);
-		}
-	}
-	statusTimer->Start(STATUS_TIMER_DELAY,wxTIMER_ONE_SHOT);
+	MainFrame_statusbar->SetStatusText((message),0);
 }
 
 void MainWindowFrame::updateProgressStatus()
@@ -4317,8 +4346,8 @@ void MainWindowFrame::updateProgressStatus()
 
 	MainFrame_statusbar->SetBackgroundColour(wxNullColour);
 	MainFrame_statusbar->SetStatusText(wxT(""),0);
-	MainFrame_statusbar->SetStatusText(wxStr(progressString),1);
-	MainFrame_statusbar->SetStatusText(wxStr(filterProg),2);
+	MainFrame_statusbar->SetStatusText((progressString),1);
+	MainFrame_statusbar->SetStatusText((filterProg),2);
 
 }
 
@@ -4397,15 +4426,15 @@ void MainWindowFrame::updatePostEffects()
 				float delta;
 				delta=bcTmp.getBound(0,1)-bcTmp.getBound(0,0);
 				stream_cast(s,delta);
-				textFxCropDx->SetValue(wxStr(s));
+				textFxCropDx->SetValue((s));
 				
 				delta=bcTmp.getBound(1,1)-bcTmp.getBound(1,0);
 				stream_cast(s,delta);
-				textFxCropDy->SetValue(wxStr(s));
+				textFxCropDy->SetValue((s));
 				
 				delta=bcTmp.getBound(2,1)-bcTmp.getBound(2,0);
 				stream_cast(s,delta);
-				textFxCropDz->SetValue(wxStr(s));
+				textFxCropDz->SetValue((s));
 			}
 			else
 			{
@@ -4554,76 +4583,18 @@ void MainWindowFrame::OnViewFullscreen(wxCommandEvent &event)
 
 	programmaticEvent=true;
 
-	//Toggle fullscreen, leave the menubar  & statusbar visible
-
-#ifdef __APPLE__
-	switch(fullscreenState)
-	{
-		case 0:
-			ShowFullScreen(true,wxFULLSCREEN_NOTOOLBAR);
-			menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: none"));	
-			break;
-		case 1:
-			menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: complete"));	
-			ShowFullScreen(false);
-			break;
-		case 2:
-			menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: none"));	
-			ShowFullScreen(true);
-			break;
-		case 3:
-			menuViewFullscreen->SetHelp(wxTRANS("Next Fullscreen mode: with toolbars"));	
-			ShowFullScreen(false);
-			break;
-
-		default:
-			ASSERT(false);
-
-	}
-	fullscreenState++;
-	fullscreenState%=4;
-#elif __LINUX__
-
-	switch(fullscreenState)
-	{
-		case 0:
-			ShowFullScreen(true,wxFULLSCREEN_NOTOOLBAR);
-			statusMessage(TRANS("Next Mode: No fullscreen"),MESSAGE_HINT);
-			break;
-		case 1:
-			ShowFullScreen(false);
-			statusMessage(TRANS("Next Mode: fullscreen w/o toolbar"),MESSAGE_HINT);
-			break;
-		case 2:
-			ShowFullScreen(true);
-			statusMessage(TRANS("Next Mode: fullscreen with toolbar"),MESSAGE_HINT);
-			break;
-		default:
-			ASSERT(false);
-	}
-	fullscreenState++;
-	fullscreenState%=3;
-#else
+	ShowFullScreen(!fullscreenState);
+	fullscreenState=(fullscreenState+1)%2;
 	
-	switch(fullscreenState)
-	{
-		case 0:
-			ShowFullScreen(true);
-			break;
-		case 1:
-			ShowFullScreen(false);
-			break;
-		default:
-			ASSERT(false);
-	}
-	fullscreenState++;
-	fullscreenState%=2;
-#endif
 	programmaticEvent=false;
 }
 
 void MainWindowFrame::OnButtonRefresh(wxCommandEvent &event)
 {
+	//TODO: Remove this line when wx bug 16222 is fixed
+	if(!gridCameraProperties || !gridFilterPropGroup)
+		return;
+
 	if(currentlyUpdatingScene || visControl.isRefreshing())
 		return;
 
@@ -4632,7 +4603,6 @@ void MainWindowFrame::OnButtonRefresh(wxCommandEvent &event)
 	if(wxm.ShiftDown())
 	{
 		visControl.purgeFilterCache();
-		statusMessage("",MESSAGE_NONE);
 	}
 	else
 	{
@@ -4657,10 +4627,6 @@ void MainWindowFrame::OnFilterPropDoubleClick(wxSplitterEvent &event)
 
 void MainWindowFrame::OnControlSplitMove(wxSplitterEvent &event)
 {
-	//Set the grid an event so that it can adapt the grid margins to fit
-	wxGridEvent gridEvent(ID_GRID_RAW_DATA,wxEVT_GRID_LABEL_LEFT_DCLICK,NULL);
-	wxPostEvent(gridFilterPropGroup,gridEvent);
-
 	//For some reason, the damage rectangle is not updated
 	// for the tree ctrl
 	treeFilters->Refresh();
@@ -4694,207 +4660,6 @@ void MainWindowFrame::OnSpectraUnsplit(wxSplitterEvent &event)
 	configFile.setPanelEnabled(CONFIG_STARTUPPANEL_PLOTLIST,false);
 }
 
-//This function modifies the properties before showing the cell content editor.
-//This is needed only for certain data types (colours, bools) other data types are edited
-//using the default editor and modified using ::OnGridFilterPropertyChange
-void MainWindowFrame::OnFilterGridCellEditorShow(wxGridEvent &event)
-{
-
-	if(programmaticEvent )
-	{
-		event.Skip();
-		return;
-	}
-
-
-	//Find where the event occurred (cell & property)
-	const GRID_PROPERTY *item;
-
-	unsigned int key;
-	key=gridFilterPropGroup->getKeyFromRow(event.GetRow());
-
-	item=gridFilterPropGroup->getProperty(key);
-
-	//Remove any icons that show filter errors or warning state
-	clearWxTreeImages(treeFilters);
-
-	bool needUpdate=false;
-
-	//If this occurs at run-time, then just abort, otherwise throw error
-	ASSERT(treeFilters->GetSelection() != treeFilters->GetRootItem());
-	if(treeFilters->GetSelection() == treeFilters->GetRootItem())
-		return;
-
-	//Get the filter ID value 
-	size_t filterId;
-	if(!getTreeFilterId(treeFilters->GetSelection(),filterId))
-		return;
-
-	switch(item->type)
-	{
-		case PROPERTY_TYPE_BOOL:
-		{
-			std::string s;
-			//Toggle the property in the grid
-			if(item->data == "0")
-				s= "1";
-			else
-				s="0";
-			visControl.setFilterProperty(filterId,key,s,needUpdate);
-
-			event.Veto();
-			break;
-		}
-		case PROPERTY_TYPE_COLOUR:
-		{
-			//Show a wxColour choose dialog. 
-			wxColourData d;
-
-			unsigned char r,g,b,a;
-			parseColString(item->data,r,g,b,a);
-
-			d.SetColour(wxColour(r,g,b,a));
-			wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d);
-						
-
-			if( colDg->ShowModal() == wxID_OK)
-			{
-				wxColour c;
-				//Change the colour
-				c=colDg->GetColourData().GetColour();
-				
-				std::string s;
-				genColString(c.Red(),c.Green(),c.Blue(),s);
-			
-				//Pass the new colour to the viscontrol system, which updates
-				//the filters	
-				visControl.setFilterProperty(filterId,key,s,needUpdate);
-			}
-
-			//Set the filter property
-			//Disallow direct editing of the grid cell
-			event.Veto();
-
-			break;
-		}	
-		default:
-		{
-			//we will handle this after the user has edited the cell contents
-			//but we must lock controls that can alter the active filter, and thereby changing the 
-			// filter grid in the meantime
-			setLockUI(true,WINDOW_LOCK_PROPEDIT);
-			break;
-		}
-	}
-
-	if(needUpdate)
-	{
-		visControl.updateFilterPropGrid(gridFilterPropGroup,filterId);
-
-		if(checkAutoUpdate->GetValue())
-			doSceneUpdate();
-		else
-			clearWxTreeImages(treeFilters);
-	}
-
-	setSaveStatus();
-}
-
-void MainWindowFrame::OnFilterGridCellEditorHide(wxGridEvent &event)
-{
-	//re-enable the controls that were locked during OnFilterGridCellEditorShow
-	setLockUI(false,WINDOW_LOCK_PROPEDIT);
-}
-
-void MainWindowFrame::OnCameraGridCellEditorShow(wxGridEvent &event)
-{
-	if(programmaticEvent)
-	{
-		event.Skip();
-		return;
-	}
-	//Find where the event occurred (cell & property)
-	const GRID_PROPERTY *item;
-
-	unsigned int key;
-	key=gridCameraProperties->getKeyFromRow(event.GetRow());
-
-	item=gridCameraProperties->getProperty(key);
-
-	//Get the camera ID
-	wxListUint *l;
-	int n = comboCamera->FindString(comboCamera->GetValue());
-	if( n == wxNOT_FOUND)
-		return;
-		
-	l =(wxListUint*)  comboCamera->GetClientObject(n);
-	if(!l)
-		return;
-	
-	size_t camUniqueID=l->value;
-
-
-	switch(item->type)
-	{
-		case PROPERTY_TYPE_BOOL:
-		{
-			std::string s;
-			//Toggle the property in the grid
-			if(item->data == "0")
-				s= "1";
-			else
-				s="0";
-			visControl.setCamProperties(camUniqueID,key,s);
-		
-			//For some reason this does not  redraw neatly. Force a redraw
-			visControl.updateCamPropertyGrid(gridCameraProperties,camUniqueID);
-
-			event.Veto();
-			break;
-		}
-		case PROPERTY_TYPE_COLOUR:
-		{
-			//Show a wxColour choose dialog. 
-			wxColourData d;
-
-			unsigned char r,g,b,a;
-			parseColString(item->data,r,g,b,a);
-
-			d.SetColour(wxColour(r,g,b,a));
-			wxColourDialog *colDg=new wxColourDialog(this->GetParent(),&d);
-						
-
-			if( colDg->ShowModal() == wxID_OK)
-			{
-				wxColour c;
-				//Change the colour
-				c=colDg->GetColourData().GetColour();
-				
-				std::string s;
-				genColString(c.Red(),c.Green(),c.Blue(),s);
-			
-				//Pass the new colour to the viscontrol system, which updates
-				//the filters	
-				visControl.setCamProperties(camUniqueID,key,s);
-			}
-
-			//Set the filter property
-			//Disallow direct editing of the grid cell
-			event.Veto();
-
-			break;
-		}	
-		default:
-			//we will handle this after the user has edited the cell contents
-			//Lock the camera combo, so the user can't alter the camera data while we are using the editor
-			comboCamera->Enable(false);
-			break;
-	}
-
-	panelTop->forceRedraw();
-
-	setSaveStatus();
-}
 
 void MainWindowFrame::OnButtonGridCopy(wxCommandEvent &event)
 {
@@ -4903,11 +4668,7 @@ void MainWindowFrame::OnButtonGridCopy(wxCommandEvent &event)
 
 void MainWindowFrame::OnButtonGridSave(wxCommandEvent &event)
 {
-#if wxCHECK_VERSION(2,9,0)
 	if(!gridRawData->GetNumberRows()||!gridRawData->GetNumberCols())
-#else
-	if(!gridRawData->GetRows()||!gridRawData->GetCols())
-#endif
 	{
 		statusMessage(TRANS("No data to save"),MESSAGE_ERROR);
 		return;
@@ -5036,7 +4797,7 @@ void MainWindowFrame::OnButtonRemoveCam(wxCommandEvent &event)
 		
 		programmaticEvent=true;
 		comboCamera->SetValue(wxT(""));
-		gridCameraProperties->clear();
+		gridCameraProperties->Clear();
 		programmaticEvent=false;
 
 		setSaveStatus();
@@ -5054,12 +4815,10 @@ void MainWindowFrame::OnSpectraListbox(wxCommandEvent &event)
 	//Spin through the selected items
 	for(unsigned int ui=0;ui<plotList->GetCount(); ui++)
 	{
-	 	wxListUint *l;
 		unsigned int plotID;
 
 		//Retrieve the uniqueID
-		l=(wxListUint*)plotList->GetClientObject(ui);
-		plotID = l->value;
+		plotID = visControl.getPlotID(ui);
 
 		panelSpectra->setPlotVisible(plotID,plotList->IsSelected(ui));
 
@@ -5087,8 +4846,8 @@ void MainWindowFrame::OnClose(wxCloseEvent &event)
 		else
 		{
 			wxMessageDialog wxD(this,
-					wxTRANS("Waiting for refresh to abort. Exiting could lead to the program backgrounding. Exit anyway? "),
-					wxTRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR);
+					TRANS("Waiting for refresh to abort. Exiting could lead to the program backgrounding. Exit anyway? "),
+					TRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR);
 
 			if(wxD.ShowModal() != wxID_OK)
 			{
@@ -5107,8 +4866,8 @@ void MainWindowFrame::OnClose(wxCloseEvent &event)
 			{
 				//Prompt for close
 				wxMessageDialog wxD(this,
-						wxTRANS("Are you sure you wish to exit 3Depict?"),\
-						wxTRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR);
+						TRANS("Are you sure you wish to exit 3Depict?"),\
+						TRANS("Confirmation request"),wxOK|wxCANCEL|wxICON_ERROR);
 				if(wxD.ShowModal() != wxID_OK)
 				{
 					event.Veto();
@@ -5129,8 +4888,8 @@ void MainWindowFrame::OnClose(wxCloseEvent &event)
 	pid=wxGetProcessId();
 	stream_cast(pidStr,pid);
 	
-	wxString filePath =wxStr(configFile.getConfigDir());
-	filePath+=wxCStr("/") + wxCStr(AUTOSAVE_PREFIX) + wxStr(pidStr)+ wxCStr(AUTOSAVE_SUFFIX);
+	wxString filePath =(configFile.getConfigDir());
+	filePath+=string("/") + string(AUTOSAVE_PREFIX) + pidStr+ string(AUTOSAVE_SUFFIX);
 
 	if(wxFileExists(filePath))
 		wxRemoveFile(filePath);
@@ -5346,7 +5105,7 @@ void MainWindowFrame::restoreConfigDefaults()
 	configFile.getRecentFiles(strVec);
 
 	for(unsigned int ui=0; ui<strVec.size(); ui++)
-		recentHistory->AddFileToHistory(wxStr(strVec[ui]));
+		recentHistory->AddFileToHistory((strVec[ui]));
 	
 	//Set the mouse zoom speeds
 	float zoomRate,moveRate;
@@ -5364,11 +5123,21 @@ void MainWindowFrame::restoreConfigDefaults()
 		std::string s;
 		stream_cast(s,configFile.getMaxPoints());
 
-		textLimitOutput->SetValue(wxStr(s));
+		textLimitOutput->SetValue((s));
 
 		visControl.setIonDisplayLimit(configFile.getMaxPoints());
 	}
 
+	
+	if(configFile.getWantStartupOrthoCam())
+	{
+		visControl.setCamProperties(visControl.getActiveCamId(), 
+					CAMERA_KEY_LOOKAT_PROJECTIONMODE,TRANS("Orthogonal"));
+	}
+}
+
+void MainWindowFrame::checkShowTips()
+{
 	//Show startup tip dialog as needed
 	if(configFile.wantStartupTips())
 	{
@@ -5377,13 +5146,12 @@ void MainWindowFrame::restoreConfigDefaults()
 		if(!tipFile.empty())
 		{
 			const unsigned int ROUGH_NUMBER_TIPS=22;
-			bool wantTipsAgain;
-			wxTipProvider *tipProvider = wxCreateFileTipProvider(wxStr(tipFile), 
+			wxTipProvider *tipProvider = wxCreateFileTipProvider((tipFile), 
 					(size_t) ((float)rand()/(float)RAND_MAX*(float)ROUGH_NUMBER_TIPS));
 
 			if(tipProvider)
 			{
-				wantTipsAgain=wxShowTip(this, tipProvider);
+				bool wantTipsAgain=wxShowTip(this, tipProvider);
 				delete tipProvider;
 				configFile.setWantStartupTips(wantTipsAgain);
 			}
@@ -5395,12 +5163,6 @@ void MainWindowFrame::restoreConfigDefaults()
 			WARN(false,"Tip file not found at startup, but user wanted it...");
 		}
 	}
-	
-	if(configFile.getWantStartupOrthoCam())
-	{
-		visControl.setCamProperties(visControl.getActiveCamId(), 
-					CAMERA_KEY_LOOKAT_PROJECTIONMODE,TRANS("Orthogonal"));
-	}
 }
 
 void MainWindowFrame::restoreConfigPanelDefaults()
@@ -5415,7 +5177,9 @@ void MainWindowFrame::restoreConfigPanelDefaults()
 	{
 		splitLeftRight->Unsplit(panelLeft);
 		checkMenuControlPane->Check(false);
-		
+	}
+	else
+	{
 		val=configFile.getLeftRightSashPos();
 		if(val > std::numeric_limits<float>::epsilon())
 		{
@@ -5485,33 +5249,24 @@ void MainWindowFrame::restoreConfigPanelDefaults()
 
 void MainWindowFrame::SetCommandLineFiles(wxArrayString &files)
 {
-	//WX Bug: Re-entrancy can occur during modal dialog display due to timers
-	// disable timer before showing dialog
-	updateTimer->Stop();
-	autoSaveTimer->Stop();
 	
 	textConsoleOut->Clear();
+	bool loadedOK=false;
 	//Load them up as data.
 	for(unsigned int ui=0;ui<files.size();ui++)
-		loadFile(files[ui],true);
-
-
-	if(files.GetCount())
 	{
-		//OK, we got here, so it must be loaded.
-		requireFirstUpdate=false;
+		loadedOK|=loadFile(files[ui],true);
 	}
 
-	//Restart timers
-	updateTimer->Start(UPDATE_TIMER_DELAY,wxTIMER_CONTINUOUS);
-	autoSaveTimer->Start(AUTOSAVE_DELAY*1000,wxTIMER_CONTINUOUS);
+	requireFirstUpdate=loadedOK;
+
 }
 
 void MainWindowFrame::OnNoteDataView(wxNotebookEvent &evt)
 {
 	//Get rid of the console page
 	if(evt.GetSelection() == NOTE_CONSOLE_PAGE_OFFSET)
-		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,wxTRANS("Cons."));
+		noteDataView->SetPageText(NOTE_CONSOLE_PAGE_OFFSET,TRANS("Cons."));
 
 	//Keep processing
 	evt.Skip();
@@ -5556,8 +5311,8 @@ void MainWindowFrame::OnCheckUpdatesThread(wxCommandEvent &evt)
 
 void MainWindowFrame::checkReloadAutosave()
 {
-	wxString configDirPath =wxStr(configFile.getConfigDir());
-	configDirPath+=wxCStr("/") ;
+	wxString configDirPath =(configFile.getConfigDir());
+	configDirPath+=("/") ;
 
 	if(!wxDirExists(configDirPath))
 		return;
@@ -5568,7 +5323,7 @@ void MainWindowFrame::checkReloadAutosave()
 	std::string s;
 	s=std::string(AUTOSAVE_PREFIX) +
 			std::string("*") + std::string(AUTOSAVE_SUFFIX);
-	wxString fileMask = wxStr(s);
+	wxString fileMask = (s);
 
 	wxDir::GetAllFiles(configDirPath,dirListing,fileMask,wxDIR_FILES);
 
@@ -5631,10 +5386,10 @@ void MainWindowFrame::checkReloadAutosave()
 	if(autosaveNamePIDMap.size() == 1)
 	{
 		//If we have exactly one autosave, ask the user about loading it
-		wxString filePath=wxStr(autosaveNamePIDMap.begin()->first);
+		wxString filePath=(autosaveNamePIDMap.begin()->first);
 		wxMessageDialog wxD(this,
-			wxTRANS("An auto-save state was found, would you like to restore it?.") 
-			,wxTRANS("Autosave"),wxCANCEL|wxOK|wxICON_QUESTION|wxYES_DEFAULT );
+			TRANS("An auto-save state was found, would you like to restore it?.") 
+			,TRANS("Autosave"),wxCANCEL|wxOK|wxICON_QUESTION|wxYES_DEFAULT );
 
 		if(wxD.ShowModal()!= wxID_CANCEL)
 		{
@@ -5669,7 +5424,7 @@ void MainWindowFrame::checkReloadAutosave()
 		for(map<string,unsigned int>::iterator it=autosaveNamePIDMap.begin();
 			it!=autosaveNamePIDMap.end();++it)
 		{
-			time_t timeStamp=wxFileModificationTime(wxStr(it->first));
+			time_t timeStamp=wxFileModificationTime((it->first));
 			filenamesAndTimes.push_back(make_pair(timeStamp,it->first));
 		}
 
@@ -5711,7 +5466,7 @@ void MainWindowFrame::checkReloadAutosave()
 				std::string tmpStr;
 				tmpStr =filenamesAndTimes[dlg->getSelectedItem()].second;
 
-				if(loadFile(wxStr(tmpStr),false,true))
+				if(loadFile((tmpStr),false,true))
 				{
 					//Prevent the program from allowing save menu usage
 					//into autosave file
@@ -5747,7 +5502,7 @@ void MainWindowFrame::checkReloadAutosave()
 	std::string tmpDir;
 	tmpDir = configFile.getConfigDir()  + stlStr(wxFileName::GetPathSeparator())
 		+string("oldAutosave");
-	wxString wxtmpDir=wxStr(tmpDir);
+	wxString wxtmpDir=(tmpDir);
 	
 	//Build the old autosave dir if needed
 	if(removeFiles.size() && !doErase)
@@ -5770,16 +5525,16 @@ void MainWindowFrame::checkReloadAutosave()
 	{
 		//move the autosave file elsewhere after loading it
 		std::string baseDir = tmpDir+ stlStr(wxFileName::GetPathSeparator()); 
-		wxtmpDir=wxStr(baseDir);
+		wxtmpDir=(baseDir);
 
 		//make a backup if needed 
 		if(!doErase)
 		{
-			wxFileName fileNaming(wxStr(removeFiles[ui]));
-			wxCopyFile(wxStr(removeFiles[ui]),wxtmpDir+fileNaming.GetFullName()); 
+			wxFileName fileNaming((removeFiles[ui]));
+			wxCopyFile((removeFiles[ui]),wxtmpDir+fileNaming.GetFullName()); 
 		}
 		//if the copy works or not, just delete the autsave anyway
-		wxRemoveFile(wxStr(removeFiles[ui]));	
+		wxRemoveFile((removeFiles[ui]));	
 	}
 }
 
@@ -5830,63 +5585,54 @@ wxSize MainWindowFrame::getNiceWindowSize() const
 void MainWindowFrame::set_properties()
 {
     // begin wxGlade: MainWindowFrame::set_properties
-    SetTitle(wxCStr(PROGRAM_NAME));
+    SetTitle((PROGRAM_NAME));
     comboFilters->SetSelection(-1);
     
-    comboFilters->SetToolTip(wxTRANS("List of available filters"));
+    comboFilters->SetToolTip(TRANS("List of available filters"));
 #ifdef __APPLE__
-    treeFilters->SetToolTip(wxTRANS("Tree - drag to move items, hold ⌘ for copy. Tap delete to remove items"));
+    treeFilters->SetToolTip(TRANS("Tree - drag to move items, hold ⌘ for copy. Tap delete to remove items"));
 #else
-    treeFilters->SetToolTip(wxTRANS("Tree - drag to move items, hold Ctrl for copy. Tap delete to remove items."));
+    treeFilters->SetToolTip(TRANS("Tree - drag to move items, hold Ctrl for copy. Tap delete to remove items."));
 #endif
-    checkAutoUpdate->SetToolTip(wxTRANS("Enable/Disable automatic updates of data when filter change takes effect"));
+    checkAutoUpdate->SetToolTip(TRANS("Enable/Disable automatic updates of data when filter change takes effect"));
     checkAutoUpdate->SetValue(true);
 
-    checkAlphaBlend->SetToolTip(wxTRANS("Enable/Disable \"Alpha blending\" (transparency) in rendering system. Blending is used to smooth objects (avoids artefacts known as \"jaggies\") and to make transparent surfaces. Disabling will provide faster rendering but look more blocky")); 
-    checkLighting->SetToolTip(wxTRANS("Enable/Disable lighting calculations in rendering, for objects that request this. Lighting provides important depth cues for objects comprised of 3D surfaces. Disabling may allow faster rendering in complex scenes"));
-    checkWeakRandom->SetToolTip(wxTRANS("Enable/Disable weak randomisation (Galois linear feedback shift register). Strong randomisation uses a much slower random selection method, but provides better protection against inadvertent correlations, and is recommended for final analyses"));
-
-    checkLimitOutput->SetToolTip(wxTRANS("Limit the number of points that can be displayed in the 3D  scene. Does not affect filter tree calculations. Disabling this can severely reduce performance, due to large numbers of points being visible at once."));
-    checkCaching->SetToolTip(wxTRANS("Enable/Disable caching of intermediate results during filter updates. Disabling caching will use less system RAM, though changes to any filter property will cause the entire filter tree to be recomputed, greatly slowing computations"));
-
-    gridFilterPropGroup->CreateGrid(0, 2);
-    gridFilterPropGroup->EnableDragRowSize(false);
-    gridFilterPropGroup->SetColLabelValue(0, wxTRANS("Property"));
-    gridFilterPropGroup->SetColLabelValue(1, wxTRANS("Value"));
-    gridCameraProperties->CreateGrid(4, 2);
-    gridCameraProperties->EnableDragRowSize(false);
-    gridCameraProperties->SetSelectionMode(wxGrid::wxGridSelectRows);
-    gridCameraProperties->SetColLabelValue(0, wxTRANS("Property"));
-    gridCameraProperties->SetColLabelValue(1, wxTRANS("Value"));
-    gridCameraProperties->SetToolTip(wxTRANS("Camera data information"));
+    checkAlphaBlend->SetToolTip(TRANS("Enable/Disable \"Alpha blending\" (transparency) in rendering system. Blending is used to smooth objects (avoids artefacts known as \"jaggies\") and to make transparent surfaces. Disabling will provide faster rendering but look more blocky")); 
+    checkLighting->SetToolTip(TRANS("Enable/Disable lighting calculations in rendering, for objects that request this. Lighting provides important depth cues for objects comprised of 3D surfaces. Disabling may allow faster rendering in complex scenes"));
+    checkWeakRandom->SetToolTip(TRANS("Enable/Disable weak randomisation (Galois linear feedback shift register). Strong randomisation uses a much slower random selection method, but provides better protection against inadvertent correlations, and is recommended for final analyses"));
+
+    checkLimitOutput->SetToolTip(TRANS("Limit the number of points that can be displayed in the 3D  scene. Does not affect filter tree calculations. Disabling this can severely reduce performance, due to large numbers of points being visible at once."));
+    checkCaching->SetToolTip(TRANS("Enable/Disable caching of intermediate results during filter updates. Disabling caching will use less system RAM, though changes to any filter property will cause the entire filter tree to be recomputed, greatly slowing computations"));
+
+    gridCameraProperties->SetToolTip(TRANS("Camera data information"));
     noteCamera->SetScrollRate(10, 10);
 
 #ifndef APPLE_EFFECTS_WORKAROUND
-    checkPostProcessing->SetToolTip(wxTRANS("Enable/disable visual effects on final 3D output"));
+    checkPostProcessing->SetToolTip(TRANS("Enable/disable visual effects on final 3D output"));
 #endif
-    checkFxCrop->SetToolTip(wxTRANS("Enable cropping post-process effect"));
+    checkFxCrop->SetToolTip(TRANS("Enable cropping post-process effect"));
     comboFxCropAxisOne->SetSelection(0);
     comboFxCropAxisTwo->SetSelection(0);
-    checkFxEnableStereo->SetToolTip(wxTRANS("Colour based 3D effect enable/disable - requires appropriate colour filter 3D glasses."));
-    comboFxStereoMode->SetToolTip(wxTRANS("Glasses colour mode"));
+    checkFxEnableStereo->SetToolTip(TRANS("Colour based 3D effect enable/disable - requires appropriate colour filter 3D glasses."));
+    comboFxStereoMode->SetToolTip(TRANS("Glasses colour mode"));
     comboFxStereoMode->SetSelection(0);
-    sliderFxStereoBaseline->SetToolTip(wxTRANS("Level of separation between left and right images, which sets 3D depth to visual distortion tradeoff"));
+    sliderFxStereoBaseline->SetToolTip(TRANS("Level of separation between left and right images, which sets 3D depth to visual distortion tradeoff"));
     gridRawData->CreateGrid(10, 2);
     gridRawData->EnableEditing(false);
     gridRawData->EnableDragRowSize(false);
-    gridRawData->SetColLabelValue(0, wxTRANS("X"));
-    gridRawData->SetColLabelValue(1, wxTRANS("Y"));
-    btnRawDataSave->SetToolTip(wxTRANS("Save raw data to file"));
-    btnRawDataClip->SetToolTip(wxTRANS("Copy raw data to clipboard"));
-    btnStashManage->SetToolTip(wxTRANS("Manage \"stashed\" data."));
-    textConsoleOut->SetToolTip(wxTRANS("Program text output"));
-    comboCamera->SetToolTip(wxTRANS("Select active camera, or type to create new named camera"));
-    buttonRemoveCam->SetToolTip(wxTRANS("Remove the selected camera"));
-    checkFxCropCameraFrame->SetToolTip(wxTRANS("Perform cropping from coordinate frame of camera"));
-    spinCachePercent->SetToolTip(wxTRANS("Set the maximum amount of RAM to use in order to speed repeat computations"));
-    btnFilterTreeCollapse->SetToolTip(wxTRANS("Collapse the filter tree"));
-    btnFilterTreeExpand->SetToolTip(wxTRANS("Expand the filter tree"));
-    refreshButton->SetToolTip (wxTRANS("Process the filter tree, hold shift to purge cached filter data"));
+    gridRawData->SetColLabelValue(0, TRANS("X"));
+    gridRawData->SetColLabelValue(1, TRANS("Y"));
+    btnRawDataSave->SetToolTip(TRANS("Save raw data to file"));
+    btnRawDataClip->SetToolTip(TRANS("Copy raw data to clipboard"));
+    btnStashManage->SetToolTip(TRANS("Manage \"stashed\" data."));
+    textConsoleOut->SetToolTip(TRANS("Program text output"));
+    comboCamera->SetToolTip(TRANS("Select active camera, or type to create new named camera"));
+    buttonRemoveCam->SetToolTip(TRANS("Remove the selected camera"));
+    checkFxCropCameraFrame->SetToolTip(TRANS("Perform cropping from coordinate frame of camera"));
+    spinCachePercent->SetToolTip(TRANS("Set the maximum amount of RAM to use in order to speed repeat computations"));
+    btnFilterTreeCollapse->SetToolTip(TRANS("Collapse the filter tree"));
+    btnFilterTreeExpand->SetToolTip(TRANS("Expand the filter tree"));
+    refreshButton->SetToolTip (TRANS("Process the filter tree, hold shift to purge cached filter data"));
 
     // end wxGlade
     //
@@ -5903,23 +5649,11 @@ void MainWindowFrame::set_properties()
 
 
     refreshButton->Enable(false);
-#if wxCHECK_VERSION(2, 9, 0)
     comboCamera->Bind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboCameraSetFocus, this);
     comboStash->Bind(wxEVT_SET_FOCUS, &MainWindowFrame::OnComboStashSetFocus, this);
     noteDataView->Bind(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, &MainWindowFrame::OnNoteDataView, this);
     treeFilters->Bind(wxEVT_KEY_DOWN,&MainWindowFrame::OnTreeKeyDown, this); //Only required for 2.9
-#else
-    comboCamera->Connect(wxID_ANY,
-                 wxEVT_SET_FOCUS,
-		   wxFocusEventHandler(MainWindowFrame::OnComboCameraSetFocus), NULL, this);
-    comboStash->Connect(wxID_ANY,
-                 wxEVT_SET_FOCUS,
-		   wxFocusEventHandler(MainWindowFrame::OnComboStashSetFocus), NULL, this);
-    noteDataView->Connect(wxID_ANY, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
-		    wxNotebookEventHandler(MainWindowFrame::OnNoteDataView),NULL,this);
-    
-#endif
-    gridCameraProperties->clear();
+    gridCameraProperties->Clear();
     int widths[] = {-4,-2,-1};
     MainFrame_statusbar->SetStatusWidths(3,widths);
 
@@ -5948,10 +5682,7 @@ void MainWindowFrame::do_layout()
     wxBoxSizer* topPanelSizer = new wxBoxSizer(wxHORIZONTAL);
     wxBoxSizer* sizerFxCropRHS = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* sizerFxCropLHS = new wxBoxSizer(wxVERTICAL);
-    wxBoxSizer* camPaneSizer = new wxBoxSizer(wxVERTICAL);
-    wxBoxSizer* camTopRowSizer = new wxBoxSizer(wxHORIZONTAL);
     wxBoxSizer* filterPaneSizer = new wxBoxSizer(wxVERTICAL);
-    wxBoxSizer* filterPropGridSizer = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* filterTreeLeftRightSizer = new wxBoxSizer(wxHORIZONTAL);
     wxBoxSizer* filterRightOfTreeSizer = new wxBoxSizer(wxVERTICAL);
     wxBoxSizer* filterMainCtrlSizer = new wxBoxSizer(wxVERTICAL);
@@ -5977,19 +5708,12 @@ void MainWindowFrame::do_layout()
     btnFilterTreeErrs->Show(false);
     filterTreeLeftRightSizer->Add(filterRightOfTreeSizer, 2, wxEXPAND, 0);
     filterTreePane->SetSizer(filterTreeLeftRightSizer);
-    filterPropGridSizer->Add(propGridLabel, 0, 0, 0);
-    filterPropGridSizer->Add(gridFilterPropGroup, 1, wxLEFT|wxEXPAND, 4);
-    filterPropertyPane->SetSizer(filterPropGridSizer);
+    do_filtergrid_prop_layout();
 //    filterSplitter->SplitHorizontally(filterTreePane, filterPropertyPane);//DISABLED This has to be done later to get the window to work.
     filterPaneSizer->Add(filterSplitter, 1, wxEXPAND, 0);
     noteData->SetSizer(filterPaneSizer);
-    camPaneSizer->Add(labelCameraName, 0, 0, 0);
-    camTopRowSizer->Add(comboCamera, 3, 0, 0);
-    camTopRowSizer->Add(buttonRemoveCam, 0, wxLEFT|wxRIGHT, 2);
-    camPaneSizer->Add(camTopRowSizer, 0, wxTOP|wxBOTTOM|wxEXPAND, 4);
-    camPaneSizer->Add(cameraNamePropertySepStaticLine, 0, wxEXPAND, 0);
-    camPaneSizer->Add(gridCameraProperties, 1, wxEXPAND, 0);
-    noteCamera->SetSizer(camPaneSizer);
+    do_cameragrid_prop_layout();
+
 #ifndef APPLE_EFFECTS_WORKAROUND
     postProcessSizer->Add(checkPostProcessing, 0, wxALL, 5);
 #endif
@@ -6026,8 +5750,8 @@ void MainWindowFrame::do_layout()
     sizerFxStereo->Add(sizerSetereoBaseline, 0, wxEXPAND, 0);
     sizerFxStereo->Add(checkFxStereoLensFlip, 0, wxLEFT, 5);
     noteFxPanelStereo->SetSizer(sizerFxStereo);
-    noteEffects->AddPage(noteFxPanelCrop, wxTRANS("Crop"));
-    noteEffects->AddPage(noteFxPanelStereo, wxTRANS("Stereo"));
+    noteEffects->AddPage(noteFxPanelCrop, TRANS("Crop"));
+    noteEffects->AddPage(noteFxPanelStereo, TRANS("Stereo"));
     postProcessSizer->Add(noteEffects, 1, wxEXPAND, 0);
     notePost->SetSizer(postProcessSizer);
     sizerTools->Add(labelAppearance, 0, wxTOP, 3);
@@ -6044,10 +5768,10 @@ void MainWindowFrame::do_layout()
     sizerToolsRamUsage->Add(spinCachePercent, 0, 0, 5);
     sizerTools->Add(sizerToolsRamUsage, 1, wxTOP|wxEXPAND, 5);
     noteTools->SetSizer(sizerTools);
-    notebookControl->AddPage(noteData, wxTRANS("Data"));
-    notebookControl->AddPage(noteCamera, wxTRANS("Cam"));
-    notebookControl->AddPage(notePost, wxTRANS("Post"));
-    notebookControl->AddPage(noteTools, wxTRANS("Tools"));
+    notebookControl->AddPage(noteData, TRANS("Data"));
+    notebookControl->AddPage(noteCamera, TRANS("Cam"));
+    notebookControl->AddPage(notePost, TRANS("Post"));
+    notebookControl->AddPage(noteTools, TRANS("Tools"));
     sizerLeft->Add(notebookControl, 1, wxLEFT|wxBOTTOM|wxEXPAND, 2);
     panelLeft->SetSizer(sizerLeft);
     topPanelSizer->Add(panelView, 1, wxEXPAND, 0);
@@ -6064,9 +5788,9 @@ void MainWindowFrame::do_layout()
     noteRaw->SetSizer(rawDataGridSizer);
     textConsoleSizer->Add(textConsoleOut, 1, wxEXPAND, 0);
     noteDataViewConsole->SetSizer(textConsoleSizer);
-    noteDataView->AddPage(splitterSpectra, wxTRANS("Plot"));
-    noteDataView->AddPage(noteRaw, wxTRANS("Raw"));
-    noteDataView->AddPage(noteDataViewConsole, wxTRANS("Cons."));
+    noteDataView->AddPage(splitterSpectra, TRANS("Plot"));
+    noteDataView->AddPage(noteRaw, TRANS("Raw"));
+    noteDataView->AddPage(noteDataViewConsole, TRANS("Cons."));
     splitTopBottom->SplitHorizontally(panelTop, noteDataView);
     rightPanelSizer->Add(splitTopBottom, 1, wxEXPAND, 0);
     panelRight->SetSizer(rightPanelSizer);
@@ -6085,9 +5809,44 @@ void MainWindowFrame::do_layout()
 
 	//Set the combo text
 	haveSetComboCamText=false;
-	comboCamera->SetValue(wxCStr(TRANS(cameraIntroString)));
+	comboCamera->SetValue((TRANS(cameraIntroString)));
 	haveSetComboStashText=false;
-	comboStash->SetValue(wxCStr(TRANS(stashIntroString)));
+	comboStash->SetValue((TRANS(stashIntroString)));
 
 }
 
+void MainWindowFrame::do_filtergrid_prop_layout()
+{
+	wxBoxSizer* filterPropGridSizer = new wxBoxSizer(wxVERTICAL);
+
+	filterPropGridSizer->Add(propGridLabel, 0, 0, 0);
+	filterPropGridSizer->Add(gridFilterPropGroup, 1, wxLEFT|wxEXPAND, 4);
+	filterPropertyPane->SetSizer(filterPropGridSizer);
+	filterPropertyPane->Fit();
+	filterPropGridSizer->Fit(filterPropertyPane);
+
+	Layout();
+	filterSplitter->UpdateSize();
+
+}
+
+void MainWindowFrame::do_cameragrid_prop_layout()
+{
+    wxBoxSizer* camPaneSizer = new wxBoxSizer(wxVERTICAL);
+    wxBoxSizer* camTopRowSizer = new wxBoxSizer(wxHORIZONTAL);
+    
+    camPaneSizer->Add(labelCameraName, 0, 0, 0);
+    camTopRowSizer->Add(comboCamera, 3, 0, 0);
+    camTopRowSizer->Add(buttonRemoveCam, 0, wxLEFT|wxRIGHT, 2);
+    camPaneSizer->Add(camTopRowSizer, 0, wxTOP|wxBOTTOM|wxEXPAND, 4);
+    camPaneSizer->Add(cameraNamePropertySepStaticLine, 0, wxEXPAND, 0);
+    camPaneSizer->Add(gridCameraProperties, 1, wxEXPAND, 0);
+
+    noteCamera->SetSizer(camPaneSizer);
+    noteCamera->Fit();
+    //camPaneSizer->Fit();
+
+    noteCamera->Layout();
+
+    //noteCamera->UpdateSize();
+}
diff --git a/src/gui/mainFrame.h b/src/gui/mainFrame.h
index 1e9fa28..57b73f2 100644
--- a/src/gui/mainFrame.h
+++ b/src/gui/mainFrame.h
@@ -28,9 +28,8 @@
 #include <wx/dnd.h>
 #include <wx/grid.h>
 #include <wx/treectrl.h>
-#if wxCHECK_VERSION(2,9,0)
+#include <wx/propgrid/propgrid.h>
 #include <wx/filehistory.h>
-#endif
 // end wxGlade
 
 //Local stuff
@@ -46,10 +45,6 @@
 #ifndef THREEDEPICT_H 
 #define THREEDEPICT_H
 
-//Workaround for keypress not detected under MSW wx3.0 and apple
-#if wxCHECK_VERSION(2,9,0) && ( defined(__WIN32) || defined(__WIN64) || defined(__APPLE__)) || wxCHECK_VERSION(3,0,0)
-#define WX_TREE_WORKAROUND
-#endif
 
 class FileDropTarget;
 
@@ -57,9 +52,8 @@ enum
 {
 	MESSAGE_ERROR=1,
 	MESSAGE_INFO,
-	MESSAGE_HINT,
-	MESSAGE_NONE_BUT_HINT,
-	MESSAGE_NONE
+	MESSAGE_HINT, //lowest priority message in the queue. Only one HINT can be in queue at a time
+	MESSAGE_NONE // pseudo-message to wipe all messages
 };
 
 class MainWindowFrame: public wxFrame {
@@ -88,8 +82,15 @@ private:
     void set_properties();
     void do_layout();
     // end wxGlade
+    //Force a re-layout of the filter property grid
+    void do_filtergrid_prop_layout();
+    //Force a re-layout of the camera property grid
+    void do_cameragrid_prop_layout();
    
-   	//!Give a message in the satus bar
+   	//!Queue up a status message for display
+    	void showStatusMessage(const char *message, unsigned int messageType=MESSAGE_ERROR); 
+   	
+	//!Queue up a status message for display
     	void statusMessage(const char *message, unsigned int messageType=MESSAGE_ERROR); 
 
 	//!Update the progress information in the status bar
@@ -141,9 +142,6 @@ private:
 	//!Did the main frame's constructor complete OK?
 	bool initedOK;
 
-	//The type of status message last sent to user
-	unsigned int lastMessageType;
-
 	//Pointer to version check thread, occasionally initialised at startup to
 	// check online for new program updates
 	VersionCheckThread *verCheckThread;
@@ -154,6 +152,10 @@ private:
 	//TODO: Refactor -  remove me.
 	// True if there are pending updates for the mahthgl window
 	bool plotUpdates;
+
+	//List of pending messages to show in status bar
+	// first int is priority (eg MESSAGE_ERROR), string is message
+	list<pair<unsigned int, std::string > > statusQueue;
 protected:
     wxTimer *statusTimer;
     wxTimer *progressTimer;
@@ -194,7 +196,8 @@ protected:
     wxBitmapButton* btnFilterTreeErrs;
     wxPanel* filterTreePane;
     wxStaticText* propGridLabel;
-    wxCustomPropGrid* gridFilterPropGroup;
+    wxPropertyGrid* gridFilterPropGroup;
+    wxPropertyGrid *backFilterPropGrid;
     wxPanel* filterPropertyPane;
     wxSplitterWindow* filterSplitter;
     wxPanel* noteData;
@@ -202,7 +205,8 @@ protected:
     wxComboBox* comboCamera;
     wxButton* buttonRemoveCam;
     wxStaticLine* cameraNamePropertySepStaticLine;
-    wxCustomPropGrid* gridCameraProperties;
+    wxPropertyGrid* gridCameraProperties;
+    wxPropertyGrid* backCameraPropGrid;
     wxScrolledWindow* noteCamera;
     wxCheckBox* checkPostProcessing;
     wxCheckBox* checkFxCrop;
@@ -287,11 +291,7 @@ public:
     virtual void OnComboStashEnter(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnComboStash(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnTreeEndDrag(wxTreeEvent &event); // wxGlade: <event_handler>
-#if defined(WX_TREE_WORKAROUND)
     virtual void OnTreeKeyDown(wxKeyEvent &event); // wxGlade: <event_handler>
-#else
-     virtual void OnTreeKeyDown(wxTreeEvent &event); // wxGlade: <event_handler>
-#endif
     virtual void OnTreeSelectionPreChange(wxTreeEvent &event); // wxGlade: <event_handler>
     virtual void OnTreeSelectionChange(wxTreeEvent &event); // wxGlade: <event_handler>
     virtual void OnTreeDeleteItem(wxTreeEvent &event); // wxGlade: <event_handler>
@@ -301,7 +301,8 @@ public:
     virtual void OnBtnFilterTreeErrs(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnComboCameraText(wxCommandEvent &event); // wxGlade: <event_handler>
 
-    virtual void OnGridFilterPropertyChange(wxGridEvent &event); // wxGlade: <event_handler>
+    virtual void OnGridFilterPropertyChange(wxPropertyGridEvent &event); // wxGlade: <event_handler>
+    virtual void OnGridFilterDClick(wxPropertyGridEvent &event); // wxGlade: <event_handler>
     virtual void OnComboCameraEnter(wxCommandEvent &event); // wxGlade: <event_handler>
     virtual void OnComboCamera(wxCommandEvent &event); // wxGlade: <event_handler>
     
@@ -334,12 +335,9 @@ public:
 
     virtual void OnComboFilterEnter(wxCommandEvent &event); // 
     virtual void OnComboFilter(wxCommandEvent &event); // 
+    virtual void OnComboFilterText(wxCommandEvent &event); // wxGlade: <event_handler>
     
     virtual void OnStatusBarTimer(wxTimerEvent &event); // 
-    virtual void OnFilterGridCellEditorShow(wxGridEvent &event); // 
-    virtual void OnFilterGridCellEditorHide(wxGridEvent &event); // 
-    virtual void OnCameraGridCellEditorShow(wxGridEvent &event); // 
-    virtual void OnCameraGridCellEditorHide(wxGridEvent &event); // 
     virtual void OnProgressTimer(wxTimerEvent &event);
     virtual void OnProgressAbort(wxCommandEvent &event);
     virtual void OnViewFullscreen(wxCommandEvent &event);
@@ -361,7 +359,7 @@ public:
     virtual void OnComboCameraSetFocus(wxFocusEvent &evt);
     virtual void OnComboStashSetFocus(wxFocusEvent &evt);
     virtual void OnNoteDataView(wxNotebookEvent &evt);
-    virtual void OnGridCameraPropertyChange(wxGridEvent &event); // wxGlade: <event_handler>
+    virtual void OnGridCameraPropertyChange(wxPropertyGridEvent &event); // wxGlade: <event_handler>
 
     virtual void OnFileExportVideo(wxCommandEvent &event);
     virtual void OnFileExportFilterVideo(wxCommandEvent &event);
@@ -375,6 +373,7 @@ public:
     virtual void OnAutosaveTimer(wxTimerEvent &evt);
 
     virtual void OnCheckUpdatesThread(wxCommandEvent &evt);
+    virtual void OnIdle(wxIdleEvent &evt);
 
     virtual void SetCommandLineFiles(wxArrayString &files);
     virtual void updateLastRefreshBox();
@@ -382,6 +381,10 @@ public:
     //return type of file, based upon heuristic check
     static unsigned int guessFileType(const std::string &file);
 
+
+    //Check to see if the user wants a tip file
+    void checkShowTips();
+
     //See if the user wants to save the current state
     void checkAskSaveState();
     
@@ -397,6 +400,8 @@ public:
     void onPanelSpectraUpdate() {plotUpdates=true;} ;
 
     bool initOK() const {return initedOK;}
+    
+    void finaliseStartup();
 
     //This is isolated from the layout code, due to "bug" 4815 in wx. The splitter window
     //does not know how to choose a good size until the window is shown
diff --git a/src/gui/mathglPane.cpp b/src/gui/mathglPane.cpp
index f6259e4..664c846 100644
--- a/src/gui/mathglPane.cpp
+++ b/src/gui/mathglPane.cpp
@@ -24,16 +24,13 @@
 
 #include "wx/wxcommon.h"
 #include "common/translation.h"
+#include "backend/plot.h"
 
 #ifndef pow10
 #define pow10(x) pow(10,x)
 #endif
 
-#ifdef USE_MGL2
-	#include <mgl2/canvas_wnd.h>
-#else
-	#include <mgl/mgl_eps.h>
-#endif
+#include <mgl2/canvas_wnd.h>
 
 //Panning speed modifier
 const float MGL_PAN_SPEED=2.0f;
@@ -51,7 +48,7 @@ enum
 };
 
 //Do the particular enums require a redraw?
-const bool MOUSE_ACTION_NEEDS_REDRAW[] = { false,true,true};
+const bool MOUSE_ACTION_NEEDS_REDRAW[] = { false,true,true,false};
 
 enum
 {
@@ -100,7 +97,7 @@ enum
 MathGLPane::MathGLPane(wxWindow* parent, int id) :
 wxPanel(parent, id,  wxDefaultPosition, wxDefaultSize)
 {
-	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(MOUSE_ACTION_NEEDS_REDRAW) == MOUSE_MODE_ENUM_END);
+	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(MOUSE_ACTION_NEEDS_REDRAW) == MOUSE_MODE_ENUM_END + 1);
 	COMPILE_ASSERT(THREEDEP_ARRAYSIZE(mglTextureFile) == PLOT_TEXTURE_ENUM_END);
 
 	hasResized=true;
@@ -127,6 +124,28 @@ MathGLPane::~MathGLPane()
 }
 
 
+void MathGLPane::setPanCoords() const
+{
+	float xMin,xMax,yMin,yMax;
+	thePlot->getBounds(xMin,xMax,yMin,yMax);
+
+	float pEndX, pStartX,dummy;
+	toPlotCoords(draggingCurrent.x,draggingCurrent.y,pEndX,dummy);
+	toPlotCoords(draggingStart.x,draggingStart.y,pStartX,dummy);
+	
+	float offX = pEndX-pStartX;
+
+	//This is not needed if re-using mgl object!
+	// - not sure why!
+	//offX*=xMax-xMin;
+
+	//Modify for speed
+	offX*=MGL_PAN_SPEED;
+
+	thePlot->setBounds(origPanMinX+offX/2,+origPanMaxX + offX/2.0,
+				yMin,yMax);
+}
+
 bool MathGLPane::readyForInput() const
 {
 	return (thePlot && gr && 
@@ -144,19 +163,11 @@ unsigned int MathGLPane::getAxisMask(int x, int y) const
 
 	unsigned int retVal=0;
 
-#ifdef USE_MGL2
 	if(mglCurX < gr->Self()->GetOrgX('x'))
 		retVal |=AXIS_POSITION_LOW_X;
 
 	if(mglCurY < gr->Self()->GetOrgY('y'))
 		retVal |=AXIS_POSITION_LOW_Y;
-#else
-	if(mglCurX < gr->Org.x)
-		retVal |=AXIS_POSITION_LOW_X;
-
-	if(mglCurY < gr->Org.y)
-		retVal |=AXIS_POSITION_LOW_Y;
-#endif
 
 	if(!retVal)
 		retVal=AXIS_POSITION_INTERIOR;
@@ -227,7 +238,7 @@ void MathGLPane::render(wxPaintEvent &event)
 		int clientW,clientH;
 		GetClientSize(&clientW,&clientH);
 		
-		wxString str=wxTRANS("No plots selected.");
+		wxString str=TRANS("No plots selected.");
 		dc->GetMultiLineTextExtent(str,&w,&h);
 		dc->DrawText(str,(clientW-w)/2, (clientH-h)/2);
 
@@ -246,23 +257,17 @@ void MathGLPane::render(wxPaintEvent &event)
 	if(!gr || hasChanged || hasResized || 
 		MOUSE_ACTION_NEEDS_REDRAW[mouseDragMode])
 	{
-		//TODO: There appears to be a bug in mathgl
-		// where attempting to clear the plot with ->SetSize()
-		// causes objects to become zero sized (eg ticks).
-		// using a brand "new" plot entity bypasses this
-		// at some computational cost.
-		// Need to make a minimal example.
-	
 		//clear the plot drawing entity
 		if(!gr)
 		{
-#ifdef USE_MGL2
-		gr = new mglGraph(0,w,h);
-#else
-		gr = new mglGraphZB(w,h);
+			gr = new mglGraph(0,w,h);
+#ifdef __APPLE__
+			//apparenty bug in mgl under osx - font wont load,
+			// use random string to force fallback
+			gr->LoadFont("asdfrandom");
 #endif
 		}
-		else 
+		else
 		{
 			gr->SetSize(w,h);
 		}
@@ -270,46 +275,25 @@ void MathGLPane::render(wxPaintEvent &event)
 		//change the plot by panningOneD it before we draw.
 		//if we need to 
 		if(mouseDragMode==MOUSE_MODE_DRAG_PAN)
-		{
-			float xMin,xMax,yMin,yMax;
-			thePlot->getBounds(xMin,xMax,yMin,yMax);
-		
-			float pEndX, pStartX,dummy;
-			toPlotCoords(draggingCurrent.x,draggingCurrent.y,pEndX,dummy);
-			toPlotCoords(draggingStart.x,draggingStart.y,pStartX,dummy);
-			
-			float offX = pEndX-pStartX;
-
-			//This is not needed if re-using mgl object!
-			// - not sure why!
-			//offX*=xMax-xMin;
-
-			//Modify for speed
-			offX*=MGL_PAN_SPEED;
-
-			thePlot->setBounds(origPanMinX+offX/2,+origPanMaxX + offX/2.0,
-						yMin,yMax);
-		}
+			setPanCoords();
 
 		//Draw the plot
-		thePlot->drawPlot(gr,plotIsLogarithmic);	
+		thePlot->drawPlot(gr,plotIsLogarithmic);
+#ifdef DEBUG
+		if(strlen(gr->Message()))
+		{
+			cerr << "Mathgl reports error:" << gr->Message() << endl;
+		}
+#endif
 		thePlot->resetChange();
 		hasResized=false;
 
 		//Copy the plot's memory buffer into a wxImage object, then draw it	
-	#ifdef USE_MGL2
 		char *rgbdata = (char*)malloc(w*h*3);
 		gr->GetRGB((char*)rgbdata,w*h*3);
 		
-		imageCacheBmp=wxImage(w,h,(unsigned char*)rgbdata,true);
+		imageCacheBmp=wxBitmap(wxImage(w,h,(unsigned char*)rgbdata,true));
 		free(rgbdata);
-	#else
-		unsigned char *tmp;
-		tmp=const_cast<unsigned char*>(gr->GetBits());
-		wxImage imTmp;
-		imTmp=wxImage(w,h,tmp,true);
-		imageCacheBmp=wxBitmap(imTmp);
-	#endif
 	}
 
 	dc->DrawBitmap(wxBitmap(imageCacheBmp),0,0);
@@ -485,13 +469,9 @@ bool MathGLPane::getRegionUnderCursor(const wxPoint  &mousePos, unsigned int &pl
 		return false;
 
 	//Only allow  range interaction within the plot bb
-#ifdef USE_MGL2
 	if(pMouse.x > gr->Self()->Max.x || pMouse.x < gr->Self()->Min.x)
 		return false;
-#else
-	if(pMouse.x > gr->Max.x || pMouse.x < gr->Min.x)
-		return false;
-#endif
+	
 	//check if we actually have a region
 	if(!thePlot->getRegionIdAtPosition(pMouse.x,pMouse.y,plotId,regionId))
 		return false;
@@ -613,7 +593,7 @@ void MathGLPane::oneDMouseDownAction(bool leftDown,bool middleDown,
 			thePlot->getRegion(plotId,regionId,r);
 
 			//TODO: Implement a more generic region handler?
-			ASSERT(thePlot->plotType(plotId) == PLOT_TYPE_ONED);
+			ASSERT(thePlot->plotType(plotId) == PLOT_MODE_1D);
 
 			float mglStartX,mglStartY;
 			toPlotCoords(draggingStart.x, draggingStart.y,mglStartX,mglStartY);
@@ -643,6 +623,35 @@ void MathGLPane::oneDMouseDownAction(bool leftDown,bool middleDown,
 
 }
 
+void MathGLPane::twoDMouseDownAction(bool leftDown,bool middleDown,
+		 bool alternateDown, int dragX,int dragY)
+{
+	ASSERT(thePlot->getNumVisible());
+	
+	float xMin,xMax,yMin,yMax;
+	thePlot->getBounds(xMin,xMax,yMin,yMax);
+
+	//Set the interaction mode
+	if(leftDown && !alternateDown )
+	{
+		draggingStart = wxPoint(dragX,dragY);
+		mouseDragMode=MOUSE_MODE_DRAG;
+	}
+	
+	
+	if( (leftDown && alternateDown) || middleDown)
+	{
+		mouseDragMode=MOUSE_MODE_DRAG_PAN;
+		draggingStart = wxPoint(dragX,dragY);
+		
+		origPanMinX=xMin;
+		origPanMaxX=xMax;
+		origPanMinY=yMin;
+		origPanMaxY=yMax;
+	}
+
+}
+
 void MathGLPane::leftMouseDown(wxMouseEvent& event)
 {
 	if(!readyForInput())
@@ -659,16 +668,21 @@ void MathGLPane::leftMouseDown(wxMouseEvent& event)
 		event.GetPosition().x < 0 || event.GetPosition().y < 0)
 		return;
 
-	switch(thePlot->getVisibleType())
+	switch(thePlot->getVisibleMode())
 	{
-		case PLOT_TYPE_ONED:
+		case PLOT_MODE_1D:
 			oneDMouseDownAction(event.LeftDown(),false,
 						event.ShiftDown(),
 						event.GetPosition().x,
 						event.GetPosition().y);
 			break;
-		case PLOT_TYPE_ENUM_END:
+		case PLOT_MODE_2D:
+		case PLOT_MODE_ENUM_END:
 			//Do nothing
+			twoDMouseDownAction(event.LeftDown(),false,
+						event.ShiftDown(),
+						event.GetPosition().x,
+						event.GetPosition().y);
 			break;
 		default:
 			ASSERT(false);
@@ -689,15 +703,15 @@ void MathGLPane::middleMouseDown(wxMouseEvent &event)
 	if(!w || !h)
 		return;
 	
-	switch(thePlot->getVisibleType())
+	switch(thePlot->getVisibleMode())
 	{
-		case PLOT_TYPE_ONED:
+		case PLOT_MODE_1D:
 			oneDMouseDownAction(false,event.MiddleDown(),
 						event.ShiftDown(),
 						event.GetPosition().x,
 						event.GetPosition().y);
 			break;
-		case PLOT_TYPE_ENUM_END:
+		case PLOT_MODE_ENUM_END:
 			//Do nothing
 			break;
 		default:
@@ -942,12 +956,9 @@ void MathGLPane::updateDragPos(const wxPoint &draggingEnd) const
 
 
 	mglPoint cA;
-#ifdef USE_MGL2
 	cA.x=gr->Self()->GetOrgX('x');
 	cA.y=gr->Self()->GetOrgY('y');
-#else
-	cA=gr->Org;
-#endif
+	
 	float currentAxisX,currentAxisY;
 	currentAxisX=cA.x;
 	currentAxisY=cA.y;
@@ -968,13 +979,8 @@ void MathGLPane::updateDragPos(const wxPoint &draggingEnd) const
 			//left of X-Axis event
 			//Reset the axes such that the
 			//zoom is only along one dimension (y)
-#ifdef USE_MGL2
 			pStart.x = gr->Self()->Min.x;
 			pEnd.x = gr->Self()->Max.x;
-#else
-			pStart.x = gr->Min.x;
-			pEnd.x = gr->Max.x;
-#endif
 		}
 	}
 	else if(pStart.y < currentAxisY  && pEnd.y < currentAxisY )
@@ -985,13 +991,8 @@ void MathGLPane::updateDragPos(const wxPoint &draggingEnd) const
 		//below Y axis event
 		//Reset the axes such that the
 		//zoom is only along one dimension (x)
-#ifdef USE_MGL2
 		pStart.y = gr->Self()->Min.y;
 		pEnd.y = gr->Self()->Max.y;
-#else				
-		pStart.y = gr->Min.y;
-		pEnd.y = gr->Max.y;
-#endif
 	}
 
 
@@ -1053,11 +1054,7 @@ unsigned int MathGLPane::savePNG(const std::string &filename,
 	ASSERT(filename.size());
 	try
 	{
-#ifdef USE_MGL2
 		gr = new mglGraph(0, width,height);
-#else
-		gr = new mglGraphZB(width,height);
-#endif
 	}
 	catch(std::bad_alloc)
 	{
@@ -1065,41 +1062,25 @@ unsigned int MathGLPane::savePNG(const std::string &filename,
 		return MGLPANE_ERR_BADALLOC;
 	}
 
-#ifdef USE_MGL2
 	gr->SetWarn(0,"");
-#else
-	char *mglWarnMsgBuf=new char[1024];
-	*mglWarnMsgBuf=0;
-	gr->SetWarn(0);
-	gr->Message=mglWarnMsgBuf;
-#endif
+	
 	bool dummy;
 	thePlot->drawPlot(gr,dummy);	
 
 	gr->WritePNG(filename.c_str());
 
 	bool doWarn;
-#ifdef USE_MGL2
 	doWarn=gr->GetWarn();
-#else
-	doWarn=gr->WarnCode;
-#endif
+	
 	if(doWarn)
 	{
-#ifdef USE_MGL2
 		lastMglErr= gr->Self()->Mess;
-#else
-		lastMglErr=mglWarnMsgBuf;
-		delete[] mglWarnMsgBuf;
-#endif
+		
 		delete gr;
 		gr=0;
 		return MGLPANE_ERR_MGLWARN;
 	}
 
-#ifndef USE_MGL2
-	delete[] mglWarnMsgBuf;
-#endif
 	delete gr;
 	gr=0;
 	//Hack. mathgl does not return an error value from its writer
@@ -1124,28 +1105,13 @@ unsigned int MathGLPane::saveSVG(const std::string &filename)
 	ASSERT(filename.size());
 
 
-#ifdef USE_MGL2
 	mglGraph *grS;
 	grS = new mglGraph();
-#else
-	mglGraphPS *grS;
-
-	//Width and height are not *really* important per se, 
-	//since this is scale-less data.
-	grS = new mglGraphPS(1024,768);
-#endif
 
 	bool dummy;
 	thePlot->drawPlot(grS,dummy);
 
-#ifdef USE_MGL2
 	grS->SetWarn(0,"");
-#else
-	char *mglWarnMsgBuf=new char[1024];
-	*mglWarnMsgBuf=0;
-	grS->SetWarn(0);
-	grS->Message=mglWarnMsgBuf;
-#endif	
 
 	//Mathgl does not set locale prior to writing SVG
 	// do this by hand
@@ -1155,20 +1121,11 @@ unsigned int MathGLPane::saveSVG(const std::string &filename)
 
 
 	bool doWarn;
-#ifdef USE_MGL2
 	doWarn=grS->GetWarn();
-#else
-	doWarn=grS->WarnCode;
-#endif
 
 	if(doWarn)
 	{
-#ifdef USE_MGL2
 		lastMglErr=grS->Self()->Mess;
-#else
-		lastMglErr=mglWarnMsgBuf;
-		delete[] mglWarnMsgBuf;
-#endif
 		delete grS;
 		grS=0;
 		return MGLPANE_ERR_MGLWARN;
@@ -1330,8 +1287,8 @@ void MathGLPane::drawInteractOverlay(wxDC *dc) const
 			//---------
 			string labelText;
 			labelText = r.getName();
-			wxSize textSize=dc->GetTextExtent(wxStr(labelText));
-			dc->DrawText(wxStr(labelText),curMouse.x-textSize.GetWidth()/2, 
+			wxSize textSize=dc->GetTextExtent((labelText));
+			dc->DrawText((labelText),curMouse.x-textSize.GetWidth()/2, 
 					h/2-(textSize.GetHeight() + 1.5*ARROW_SIZE));
 			//---------
 		}	
@@ -1354,35 +1311,43 @@ void MathGLPane::drawInteractOverlay(wxDC *dc) const
 		}
 
 		const float THUMB_FRACTION=0.1;
+		const unsigned int MIN_THUMB_SIZE=10;
 		unsigned int thumbSize=THUMB_FRACTION*std::min(h,w);
 
-		for(size_t ui=0;ui<textureIDs.size();ui++)
+		
+
+		if(thumbSize > MIN_THUMB_SIZE)
 		{
-			size_t textureID;
-			textureID = textureIDs[ui];
 
-			ASSERT(textureID < PLOT_TEXTURE_ENUM_END);
-			std::string filename;
-			filename=locateDataFile(mglTextureFile[textureID]);
-		
-			//Need to draw a picture
-			wxImage img;
-			if(wxFileExists(wxStr(filename)) && img.LoadFile(wxStr(filename) ))
+			for(size_t ui=0;ui<textureIDs.size();ui++)
 			{
-				int position[2];
-				float tmp;
-				
-				img.Rescale(thumbSize,thumbSize,wxIMAGE_QUALITY_HIGH);
+				size_t textureID;
+				textureID = textureIDs[ui];
 
-				wxBitmap bmp(img);
-				//Draw in upper right, by one fraction
-				tmp= (1.0-1.5*THUMB_FRACTION);
-				position[0] = tmp*w;
-				
-				//Compute the vertical spacing for each icon 
-				position[1] = (1.0-(tmp - 2.0*(float)ui*THUMB_FRACTION))*h;
-
-				dc->DrawBitmap(img,position[0],position[1]);
+				ASSERT(textureID < PLOT_TEXTURE_ENUM_END);
+				std::string filename;
+				filename=locateDataFile(mglTextureFile[textureID]);
+		
+					
+				//Need to draw a picture
+				wxImage img;
+				if(wxFileExists((filename)) && img.LoadFile((filename) ))
+				{
+					int position[2];
+					float tmp;
+					
+					img.Rescale(thumbSize,thumbSize,wxIMAGE_QUALITY_HIGH);
+
+					wxBitmap bmp(img);
+					//Draw in upper right, by one fraction
+					tmp= (1.0-1.5*THUMB_FRACTION);
+					position[0] = tmp*w;
+					
+					//Compute the vertical spacing for each icon 
+					position[1] = (1.0-(tmp - 2.0*(float)ui*THUMB_FRACTION))*h;
+
+					dc->DrawBitmap(img,position[0],position[1]);
+				}
 			}
 		}
 	}
@@ -1408,13 +1373,8 @@ bool MathGLPane::toPlotCoords(int winX, int winY,float &resX, float &resY) const
 	if(plotIsLogarithmic)
 	{
 		float plotMinY,plotMaxY;
-#if USE_MGL2
 		plotMinY=gr->Self()->Min.y;
 		plotMaxY=gr->Self()->Max.y;
-#else
-		plotMinY=gr->Min.y;
-		plotMaxY=gr->Max.y;
-#endif
 		float proportion =(pt.y-plotMinY)/(plotMaxY-plotMinY);
 		float tmp = proportion*(log10(plotMaxY)-log10(plotMinY)) + log10(plotMinY); 
 		
@@ -1427,17 +1387,9 @@ bool MathGLPane::toPlotCoords(int winX, int winY,float &resX, float &resY) const
 }
 bool MathGLPane::toWinCoords(float plotX, float plotY, float &winX, float &winY) const
 {
-#ifdef USE_MGL2
 	mglPoint tmp;
 	tmp=gr->CalcScr(mglPoint(plotX,plotY));
 	winX=tmp.x; winY=tmp.y;
-#else
-	
-	int iWinX,iWinY;
-	iWinX=winX;
-	iWinY=winY;
-	gr->CalcScr(mglPoint(plotX,plotY),&iWinX,&iWinY);
-#endif
 
 	if(plotIsLogarithmic)
 	{
@@ -1467,7 +1419,7 @@ void MathGLPane::drawRegionDraggingOverlay(wxDC *dc) const
 		return;
 
 
-	ASSERT(thePlot->plotType(startMousePlot) == PLOT_TYPE_ONED);
+	ASSERT(thePlot->plotType(startMousePlot) == PLOT_MODE_1D);
 
 	//See where extending the region is allowed up to.
 	thePlot->findRegionLimit(startMousePlot,startMouseRegion,
@@ -1483,7 +1435,7 @@ void MathGLPane::drawRegionDraggingOverlay(wxDC *dc) const
 	std::string str;
 	stream_cast(str,regionLimitX);
 	wxString wxs;
-	wxs=wxStr(str);
+	wxs=(str);
 	wxCoord textW,textH;
 	dc->GetTextExtent(wxs,&textW,&textH);
 
@@ -1542,7 +1494,7 @@ void MathGLPane::drawRegionDraggingOverlay(wxDC *dc) const
 		{
 			//This needs to be extended to support more
 			//plot types.
-			ASSERT(thePlot->plotType(startMousePlot) == PLOT_TYPE_ONED);
+			ASSERT(thePlot->plotType(startMousePlot) == PLOT_MODE_1D);
 			
 			//Draw "ghost" limits markers for move,
 			//these appear as moving vertical bars to outline
diff --git a/src/gui/mathglPane.h b/src/gui/mathglPane.h
index 834541a..b98c22b 100644
--- a/src/gui/mathglPane.h
+++ b/src/gui/mathglPane.h
@@ -22,11 +22,6 @@
 
 #include "backend/plot.h"
 
-#ifndef USE_MGL2
-	#include <mgl/mgl_zb.h>
-	#undef is_nan
-#endif
-
 // begin wxGlade: ::extracode
 // end wxGlade
 
@@ -68,6 +63,7 @@ private:
 	wxPoint draggingStart,draggingCurrent;
 	//!Original bounds during panning operations.
 	float origPanMinX, origPanMaxX; //1D and 2D actions
+	float origPanMinY, origPanMaxY; //2D actions
 
 	//!region used at mouse down
 	unsigned int startMouseRegion,startMousePlot,regionMoveType;
@@ -90,11 +86,8 @@ private:
 	bool  plotIsLogarithmic;
 
 	//!Pointer to the mathgl renderer
-#ifdef USE_MGL2
 	mglGraph *gr;	
-#else
-	mglGraphZB *gr;	
-#endif
+	
 	//!Caching check vector for plot visibility
 	std::vector<unsigned int> lastVisible;
 
@@ -122,6 +115,13 @@ private:
 	//Action to perform when showing 1D plots and mouse down event occurs
 	void oneDMouseDownAction(bool leftDown,bool middleMouseDown,
 		bool alternateDown, int dragX,int dragY);
+	
+	//Action to perform when showing 2D plots and mouse down event occurs
+	void twoDMouseDownAction(bool leftDown,bool middleMouseDown,
+		bool alternateDown, int dragX,int dragY);
+
+	//Update plot bounds with any user panning action
+	void setPanCoords() const;
 
 	bool readyForInput() const;
 
diff --git a/src/testing/filtertesting.cpp b/src/testing/filtertesting.cpp
index ab2cc0c..43038e5 100644
--- a/src/testing/filtertesting.cpp
+++ b/src/testing/filtertesting.cpp
@@ -157,7 +157,7 @@ bool filterCloneTests()
 			wxString wxs,tmpStr;
 
 			tmpStr=wxT("3Depict-unit-test-a");
-			tmpStr=tmpStr+wxStr(f->getUserString());
+			tmpStr=tmpStr+(f->getUserString());
 			
 			wxs= wxFileName::CreateTempFileName(tmpStr);
 			sOrig=stlStr(wxs);
@@ -176,7 +176,7 @@ bool filterCloneTests()
 
 			//write out file from cloned object
 			tmpStr=wxT("3Depict-unit-test-b");
-			tmpStr=tmpStr+wxStr(f->getUserString());
+			tmpStr=tmpStr+(f->getUserString());
 			wxs= wxFileName::CreateTempFileName(tmpStr);
 			sClone=stlStr(wxs);
 			fileOut.open(sClone.c_str());
@@ -201,11 +201,7 @@ bool filterCloneTests()
 
 		wxArrayString stdOut;
 		long res;
-#if wxCHECK_VERSION(2,9,0)
-		res=wxExecute(wxStr(command),stdOut, wxEXEC_BLOCK);
-#else
-		res=wxExecute(wxStr(command),stdOut);
-#endif
+		res=wxExecute((command),stdOut, wxEXEC_BLOCK);
 
 
 		string comment = f->getUserString() + string(" Orig: ")+ sOrig + string (" Clone:") +sClone+
@@ -247,19 +243,16 @@ bool filterCloneTests()
 			g->writeState(fileOut,STATE_FORMAT_XML);
 
 			//Re-run diff
-#if wxCHECK_VERSION(2,9,0)
-			res=wxExecute(wxStr(command),stdOut, wxEXEC_BLOCK);
-#else
-			res=wxExecute(wxStr(command),stdOut);
-#endif
+			res=wxExecute((command),stdOut, wxEXEC_BLOCK);
+			
 			comment = f->getUserString() + string("Orig: ")+ sOrig + string (" Clone:") +sClone+
 				string("Read-back filter output was different... (or diff not around?)");
 			TEST(res==0,comment.c_str());
 		}
 		//----
 		//clean up
-		wxRemoveFile(wxStr(sOrig));
-		wxRemoveFile(wxStr(sClone));
+		wxRemoveFile((sOrig));
+		wxRemoveFile((sClone));
 
 		delete f;
 		delete g;
@@ -428,15 +421,19 @@ bool filterTreeTests()
 				throw false;
 			
 			TEST(!fTree.loadXML(nodePtr,cerr,""),"Tree load test");
+
+		
+
+			xmlFreeDoc(doc);	
 			//-----
 		}
 		catch(bool)
 		{
 			WARN(false,"Couldn't run XML reparse of output file - write permission?" );
-			wxRemoveFile(wxStr(tmpName));
+			wxRemoveFile((tmpName));
 			return true;
 		}
-		wxRemoveFile(wxStr(tmpName));
+		wxRemoveFile((tmpName));
 	}
 	else
 	{
@@ -502,7 +499,7 @@ bool filterRefreshNoOut()
 	TEST(outData.empty(),"External program refresh test");
 	fTree.safeDeleteFilterList(outData);
 
-	wxRemoveFile(wxStr(strData));
+	wxRemoveFile((strData));
 
 	return true;
 }
diff --git a/src/testing/mglTesting.cpp b/src/testing/mglTesting.cpp
index 006eded..5b54cd9 100644
--- a/src/testing/mglTesting.cpp
+++ b/src/testing/mglTesting.cpp
@@ -1,3 +1,21 @@
+/*
+ *	mglTesting.cpp - unit testing implementation for mgl code
+ *	Copyright (C) 2014, D Haley 
+
+ *	This program is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, either version 3 of the License, or
+ *	(at your option) any later version.
+
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
 #ifdef DEBUG
 #include <iostream>
 #include <cstdlib>
@@ -8,7 +26,6 @@
 
 #include "common/assertion.h"
 
-#ifdef USE_MGL2
 #include <mgl2/canvas_wnd.h>
 
 #include "common/basics.h"
@@ -19,6 +36,10 @@
 // a reference image (if possible)
 bool mglTest()
 {
+	WARN(false,"Disabled until upstream fix propagates");
+	return true;
+	
+		
 	unsigned int w=1024,h=768;
 	mglGraph *grS;
 	grS = new mglGraph(0,w,h);
@@ -149,11 +170,4 @@ bool mglTest()
 	return true;
 }
 
-#else
-bool mglTest()
-{
-	WARN(false,"MGL tests not implemented for mgl 1.x");
-	return true;
-}
-#endif
 #endif
diff --git a/src/testing/mglTesting.h b/src/testing/mglTesting.h
index 3fb7f6d..a9da1d2 100644
--- a/src/testing/mglTesting.h
+++ b/src/testing/mglTesting.h
@@ -1,3 +1,21 @@
+/*
+ *	mglTesting.h - unit testing implementation for mgl code
+ *	Copyright (C) 2014, D Haley 
+
+ *	This program is free software: you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation, either version 3 of the License, or
+ *	(at your option) any later version.
+
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
 #ifndef MGLTESTING_H
 #define MGLTESTING_H
 
diff --git a/src/testing/testing.cpp b/src/testing/testing.cpp
index 9f91575..9c711ec 100644
--- a/src/testing/testing.cpp
+++ b/src/testing/testing.cpp
@@ -31,8 +31,10 @@
 #include "backend/state.h"
 #include "backend/configFile.h"
 #include "backend/filters/algorithms/binomial.h"
+#include "backend/filters/algorithms/K3DTree-mk2.h"
 #include "backend/APT/ionhit.h"
 #include "backend/APT/APTFileIO.h"
+#include "backend/APT/abundanceParser.h"
 
 #include "common/stringFuncs.h"
 #include "common/xmlHelper.h"
@@ -58,6 +60,8 @@ bool XMLTests();
 //!Check to see if manifest contents can be found
 bool locateDataTests();
 
+bool abundanceTests();
+
 bool basicFunctionTests()
 {
 	testStringFuncs();
@@ -110,6 +114,9 @@ bool runUnitTests()
 
 	cerr << "Running unit tests..." ;
 
+	if(!K3DMk2Tests())
+		return false;
+
 
 	if(!testIonHit())
 		return false;
@@ -117,9 +124,6 @@ bool runUnitTests()
 	if(!filterTests())
 		return false;
 
-	if(!filterCloneTests())
-		return false;
-
 	if(!rangeFileLoadTests())
 		return false;
 
@@ -130,9 +134,6 @@ bool runUnitTests()
 	if(!XMLTests())
 		return false;
 
-	if(!filterTreeTests())
-		return false;
-
 	if(!runVoxelTests())
 		return false;
 
@@ -151,6 +152,9 @@ bool runUnitTests()
 	if(!mglTest())
 		return false;
 
+	if(!abundanceTests())
+		return false;
+
 	cerr << " OK" << endl << endl;
 
 	return true;
@@ -164,7 +168,7 @@ bool rangeFileLoadTests()
 	bool haveDir=false;
 	for(unsigned int ui=0;ui<THREEDEP_ARRAYSIZE(TESTING_RESOURCE_DIRS);ui++)
 	{
-		testDir=wxCStr(TESTING_RESOURCE_DIRS[ui]);
+		testDir=(TESTING_RESOURCE_DIRS[ui]);
 		if(wxDirExists(testDir))
 		{
 			haveDir=true;
@@ -189,7 +193,7 @@ bool rangeFileLoadTests()
 		std::string tmp;
 		tmp = std::string("*.") + rangeExts[ui];
 		
-		wxDir::GetAllFiles(testDir,&tmpArr,wxStr(tmp));
+		wxDir::GetAllFiles(testDir,&tmpArr,(tmp));
 		for(unsigned int uj=0;uj<tmpArr.GetCount();uj++)
 			arrayStr.Add(tmpArr[uj]);
 		tmpArr.clear();
@@ -247,7 +251,7 @@ bool rangeFileLoadTests()
 		fileLongname=stlStr(arrayStr[ui]);
 
 		wxFileName filename;
-		filename=wxStr(fileLongname);
+		filename=(fileLongname);
 		//This returns the short name of the file. Yes, its badly named.
 		fileShortname=stlStr(filename.GetFullName());
 		{
@@ -326,7 +330,7 @@ bool rangeFileLoadTests()
 		wxFileName filename;
 		
 		fileLongname=stlStr(arrayStr[ui]);
-		filename=wxStr(fileLongname);
+		filename=(fileLongname);
 		fileShortname=stlStr(filename.GetFullName());
 
 		//Check to see that the auto-parser correctly identifies the type
@@ -336,7 +340,7 @@ bool rangeFileLoadTests()
 			errString="Range type detection : ";
 			errString+=fileLongname;
 
-			if(!wxFileExists(wxStr(fileLongname)))
+			if(!wxFileExists((fileLongname)))
 			{
 				cerr << "File expected, but not found during test:" <<
 					fileLongname << endl;
@@ -493,6 +497,29 @@ bool locateDataTests()
 		}
 	}
 
+
+
+	return true;
+}
+
+bool abundanceTests()
+{
+	const char *ABUNDANCE_FILE="../data/naturalAbundance.xml";
+	ifstream f(ABUNDANCE_FILE);
+
+	//Check that abundance file exists
+	if(f)
+	{
+		f.close();
+		//run abundance tests
+		if(!AbundanceData::runUnitTests(ABUNDANCE_FILE))
+			return false;
+	}
+	else
+	{
+		WARN(false,"Unable to locate natural abundance file, skipping");
+	}
+	
 	return true;
 }
 
diff --git a/src/testing/testing.h b/src/testing/testing.h
index d3f7951..0b94768 100644
--- a/src/testing/testing.h
+++ b/src/testing/testing.h
@@ -23,6 +23,7 @@
 #include "backend/filtertree.h"
 #include "testing/mglTesting.h"
 
+
 //Run all the built-in unit tests.
 bool runUnitTests();
 
diff --git a/src/wx/propertyGridUpdater.cpp b/src/wx/propertyGridUpdater.cpp
new file mode 100644
index 0000000..228a54c
--- /dev/null
+++ b/src/wx/propertyGridUpdater.cpp
@@ -0,0 +1,320 @@
+/*
+ * propertyGridUpdater.cpp  - Update a  propertgy grid, using 3depict backend data
+ * Copyright (C) 2014  D Haley
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include  "propertyGridUpdater.h"
+
+#include "wxcommon.h"
+#include "common/stringFuncs.h"
+#include "common/basics.h"
+
+//For colour property
+#include <wx/propgrid/advprops.h>
+
+//workaround for decimal separator bug
+#include <wx/numformatter.h>
+
+
+void updateFilterPropertyGrid(wxPropertyGrid *g, const Filter *f, const string &stateString)
+{
+
+	ASSERT(f);
+	ASSERT(g);
+
+
+
+	FilterPropGroup p;
+	f->getProperties(p);
+#ifdef DEBUG
+	//If debugging, test self consistency
+	p.checkConsistent();
+#endif	
+	g->Clear();
+	//Create the keys to add to the grid
+	for(size_t ui=0;ui<p.numGroups();ui++)
+	{
+		vector<FilterProperty> propGrouping;
+		p.getGroup(ui,propGrouping);
+
+		std::string title;
+		p.getGroupTitle(ui,title);
+		
+		//Title must be present, or restorestate doesn't work correctly
+		ASSERT(!title.empty());
+
+		//Set the name that is to be displayed for this grouping
+		// of properties
+		g->Append(new wxPropertyCategory(string("") + title,title));
+		
+		
+		//Set the children of thies property
+		for(size_t uj=0;uj<propGrouping.size();uj++)
+		{
+			FilterProperty fp;
+			fp =propGrouping[uj];
+
+			std::string keyStr;
+			stream_cast(keyStr,fp.key);
+			
+			wxPGProperty *pgp;
+			switch(fp.type)
+			{
+				case PROPERTY_TYPE_BOOL:
+				{
+					bool boolVal,decOK;
+					decOK=boolStrDec(fp.data,boolVal);
+					ASSERT(decOK);
+
+					pgp =new wxBoolProperty( fp.name, keyStr,
+							boolVal);
+					break;
+				};
+				case PROPERTY_TYPE_INTEGER:
+				{
+					long long iV;
+					stream_cast(iV,fp.data);
+
+					pgp =new wxIntProperty(fp.name,keyStr,iV);
+					break;
+				}
+				case PROPERTY_TYPE_REAL:
+				{
+					//workaround for bug in wxFloatProperty under non-english locales.
+					if(wxNumberFormatter::GetDecimalSeparator() == '.')
+					{
+						float fV;
+						stream_cast(fV,fp.data);
+						pgp =new wxFloatProperty(fp.name,keyStr,fV);
+					}
+					else
+						pgp =new wxStringProperty(fp.name,keyStr,fp.data);
+					break;
+				};
+				case PROPERTY_TYPE_POINT3D:
+				case PROPERTY_TYPE_STRING:
+				{
+					pgp =new wxStringProperty(fp.name,keyStr, fp.data);
+					break;
+				}
+				case PROPERTY_TYPE_CHOICE:
+				{
+					vector<string> choices;
+					unsigned int selected;
+					choiceStringToVector(fp.data,choices,selected);
+
+					wxPGChoices pgChoices;
+					for(unsigned int ui=0;ui<choices.size();ui++)
+					{
+						pgChoices.Add(choices[ui],ui);
+					}
+					pgp = new wxEnumProperty(fp.name,keyStr,pgChoices,selected);
+					break;
+				}
+				case PROPERTY_TYPE_COLOUR:
+				{
+					bool res;
+					ColourRGBA rgba;
+
+					res=rgba.parse(fp.data);
+	
+					ASSERT(res);
+					pgp =  new wxColourProperty(fp.name,keyStr,
+								 wxColour(rgba.r(),rgba.g(),rgba.b()) ) ;
+					break;
+				}
+				case PROPERTY_TYPE_FILE:
+				{
+					pgp =new wxFileProperty(fp.name,keyStr, fp.data);
+					
+					if(fp.dataSecondary.size())
+						pgp->SetAttribute(wxPG_FILE_WILDCARD,fp.dataSecondary);
+					
+					break;
+				}
+			}
+
+			pgp->SetHelpString(fp.helpText);
+
+			g->Append(pgp);
+
+			switch(fp.type)
+			{
+				case PROPERTY_TYPE_BOOL:
+				{
+					g->SetPropertyEditor(pgp,wxPGEditor_CheckBox);
+					break;
+				}
+				default:
+					;
+			}
+		}
+	}
+
+	//Restore the selected property, if possible
+	if(stateString.size())
+		g->RestoreEditableState(stateString);
+}
+
+void updateCameraPropertyGrid(wxPropertyGrid *g, const Camera *c)
+{
+	ASSERT(c);
+	ASSERT(g);
+
+	g->Clear();
+
+	//Obtain the properties of the currently active camera
+	CameraProperties p;
+	c->getProperties(p);
+	
+	for(unsigned int ui=0;ui<p.props.size();ui++)
+	{
+		for(unsigned int uj=0;uj<p.props[ui].size();uj++)
+		{
+			CameraProperty camProp;
+			camProp=p.props[ui][uj];
+
+			string keyStr;
+			stream_cast(keyStr,camProp.key);
+			
+			wxPGProperty *pgp;
+			switch(camProp.type)
+			{
+				case PROPERTY_TYPE_BOOL:
+				{
+
+					bool boolVal,decOK;
+					decOK=boolStrDec(camProp.data,boolVal);
+					ASSERT(decOK);
+
+					pgp =new wxBoolProperty( camProp.name, keyStr, boolVal);
+							
+					break;
+				};
+				case PROPERTY_TYPE_INTEGER:
+				{
+					long long iV;
+					stream_cast(iV,camProp.data);
+
+					pgp =new wxIntProperty(camProp.name,keyStr,iV);
+					break;
+				}
+				case PROPERTY_TYPE_REAL:
+				{
+					float fV;
+					stream_cast(fV,camProp.data);
+					pgp =new wxFloatProperty(camProp.name,keyStr,fV);
+					break;
+				};
+				case PROPERTY_TYPE_POINT3D:
+				case PROPERTY_TYPE_STRING:
+				{
+					pgp =new wxStringProperty(camProp.name,keyStr, camProp.data);
+					break;
+				}
+				case PROPERTY_TYPE_CHOICE:
+				{
+					vector<string> choices;
+					unsigned int selected;
+					choiceStringToVector(camProp.data,choices,selected);
+
+					wxPGChoices pgChoices;
+					for(unsigned int ui=0;ui<choices.size();ui++)
+					{
+						pgChoices.Add(choices[ui],ui);
+					}
+					pgp = new wxEnumProperty(camProp.name,keyStr,pgChoices,selected);
+					break;
+				}
+				case PROPERTY_TYPE_COLOUR:
+				{
+					ColourRGBA rgba;
+					bool res;
+					res=rgba.parse(camProp.data);
+	
+					ASSERT(res);
+					pgp =  new wxColourProperty(camProp.name,keyStr,
+								 wxColour(rgba.r(),rgba.g(),rgba.b()) ) ;
+					break;
+				}
+			}
+			g->Append(pgp);
+
+			switch(camProp.type)
+			{
+				case PROPERTY_TYPE_BOOL:
+				{
+					g->SetPropertyEditor(pgp,wxPGEditor_CheckBox);
+					break;
+				}
+				default:
+					;
+			}
+
+		}
+	}
+}
+
+
+std::string getPropValueFromEvent(wxPropertyGridEvent &event)
+{
+	std::string newValue;
+
+	std::string eventType;
+	eventType=event.GetValue().GetType();
+	if(eventType == "wxColour")
+	{
+		wxColour col;
+		col << event.GetValue();
+		//Convert the colour to a string, so we can 
+		// send it to the backend.
+		ColourRGBA rgba(col.Red(),col.Green(),col.Blue());
+		newValue=rgba.rgbString();
+	}
+	else if (eventType == "long")
+	{
+		//So wx is a bit confused here
+		// we can either be an integer property, OR
+		// we can be an enum property.
+
+		//integer property
+		wxLongLong ll;
+		ll=event.GetValue().GetLong();
+		
+		const wxPGChoices &choices = event.GetProperty()->GetChoices();
+		if(!choices.IsOk())
+		{
+			stream_cast(newValue,ll);
+		}
+		else
+		{
+			//So wx makes life hard here. We need to do a dance to get the selection
+			// as a string
+			unsigned int ul;
+			ul=ll.ToLong();
+
+			wxArrayString arrStr;
+			arrStr=choices.GetLabels();
+			newValue=arrStr[ul];
+		}
+	}
+	else
+	{
+		newValue =  event.GetValue().GetString();
+	}
+
+	return newValue;
+}
diff --git a/src/wx/propertyGridUpdater.h b/src/wx/propertyGridUpdater.h
new file mode 100644
index 0000000..aeddbb6
--- /dev/null
+++ b/src/wx/propertyGridUpdater.h
@@ -0,0 +1,43 @@
+/*
+ * propertyGridUpdater.h  - Update a  propertgy grid, using 3depict backend data
+ * Copyright (C) 2014  D Haley
+ * 
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PROPERTYGRIDUPDATER_H
+#define PROPERTYGRIDUPDATER_H
+
+#include <wx/propgrid/propgrid.h>
+#include "backend/filter.h"
+
+#include <map>
+
+const long PROPERTY_GRID_STYLE= 0;
+const long PROPERTY_GRID_EXTRA_STYLE= wxPG_EX_HELP_AS_TOOLTIPS;
+
+//Build a property grid for the 
+// The filter key is stored as a string in the property name, for
+// each grid item in the property.
+// Due to a wx bug, the grid cannot contain items and be shown
+// when passed ot this function
+// statestring contains the previous grid' state (also part of bug workaround)
+void updateFilterPropertyGrid(wxPropertyGrid *g, const Filter *f, const std::string &stateString);
+
+void updateCameraPropertyGrid(wxPropertyGrid *g, const Camera *c); 
+
+//Convert the property grid value into a 3depict-usable string
+std::string getPropValueFromEvent(wxPropertyGridEvent &event);
+
+#endif
diff --git a/src/wx/wxcommon.cpp b/src/wx/wxcommon.cpp
index 9750c69..4a3be51 100644
--- a/src/wx/wxcommon.cpp
+++ b/src/wx/wxcommon.cpp
@@ -87,12 +87,18 @@ std::string locateDataFile(const char *name)
 
 			s+=name;
 
-			if(wxFileExists(wxStr(s)))
+			if(wxFileExists((s)))
 				return s;
 		}
 	}
-	else if(wxFileExists(wxStr(s)))
-		return s;
+	
+	std::string s;
+	s =name; 
+	
+	if(s.size() && wxFileExists((s)))
+	{
+		return string(name);
+	}
 	else
 		return std::string("");
 #elif defined( __linux__)
@@ -115,7 +121,7 @@ std::string locateDataFile(const char *name)
 	{
 		s=std::string(possibleDirs[ui]) + name;
 
-		if(wxFileExists(wxStr(s)))
+		if(wxFileExists((s)))
 			return s;
 	}
 
@@ -132,8 +138,10 @@ std::string locateDataFile(const char *name)
     }
     CFRelease(resourcesURL);
 	std::string s=std::string(path) + "/" + name;
-		if(wxFileExists(wxStr(s)))
+		if(wxFileExists((s)))
 			return s;
+		else
+			return std::string("");
 #else
 
 	//	- Look in cwd
@@ -169,7 +177,7 @@ void *VersionCheckThread::Entry()
 	strUrl = std::string(RSS_FEED_LOCATION) + std::string("?progver=") + std::string(PROGRAM_VERSION) + 
 				std::string("&os=") + stlStr(::wxGetOsDescription());
 
-	wxURI uri(wxStr(strUrl));
+	wxURI uri((strUrl));
 	rssUrl = uri.BuildURI();
 
 	url.SetURL(rssUrl); 
@@ -289,8 +297,8 @@ void *VersionCheckThread::Entry()
 
 void wxErrMsg(wxWindow *win, const std::string &title, const std::string &mesg)
 {
-	wxMessageDialog *wxMesD  =new wxMessageDialog(win,wxStr(mesg)
-					,wxStr(title),wxOK|wxICON_ERROR);
+	wxMessageDialog *wxMesD  =new wxMessageDialog(win,(mesg)
+					,(title),wxOK|wxICON_ERROR);
 	wxMesD->ShowModal();
 	wxMesD->Destroy();
 }
@@ -305,11 +313,7 @@ bool processMatchesName(size_t processID, const std::string &procName)
 	
 	wxArrayString stdOut;
 	long res;
-#if wxCHECK_VERSION(2,9,0)
 	res=wxExecute(wxT("ps ax"),stdOut, wxEXEC_BLOCK);
-#else
-	res=wxExecute(wxT("ps ax"),stdOut);
-#endif
 
 	if(res !=0 )
 		return false;
@@ -338,7 +342,7 @@ bool processMatchesName(size_t processID, const std::string &procName)
 		procNameFound=pidFound=false;
 		for(unsigned int ui=0;ui<strVec.size(); ui++)
 		{
-			wxFileName fName(wxStr(strVec[ui]));
+			wxFileName fName((strVec[ui]));
 			std::string maybeProcName;
 			maybeProcName = stlStr(fName.GetFullName());
 			
@@ -465,6 +469,88 @@ bool processMatchesName(size_t processID, const std::string &procName)
 
 	}
 #endif
+
+
+
+void copyRGBAtoWXImage(unsigned int width, unsigned int height,
+		const unsigned char *rgbaBuf, wxImage &image, 
+		const unsigned char *mask)
+
+{
+	//wx image must have an alpha channel
+	ASSERT(image.HasAlpha());
+	ASSERT(image.GetWidth() == width && 
+		image.GetHeight() == height);
+
+	//FIXME: This will likely be very slow
+	const unsigned char *p=rgbaBuf;
+	for(unsigned int uj=0;uj<height;uj++)
+	{
+		for(unsigned int ui=0;ui<width;ui++)
+		{	
+			image.SetRGB(ui,uj,*p, *(p+1), *(p+2)); 
+
+			if( (*p == *mask) && 
+			    ( *(mask+1) == *(p+1)) &&
+			    ( *(mask+2) == *(p+2)) )
+				image.SetAlpha(ui,uj,0);
+			else
+				image.SetAlpha(ui,uj,255);
+			p+=4;
+		}
+	}
+
+}
+
+void combineWxImage(wxImage &base, const wxImage &overlay)
+{
+	ASSERT(base.GetWidth() == overlay.GetWidth());
+	ASSERT(base.GetHeight() == overlay.GetHeight());
+	ASSERT(overlay.HasAlpha());
+	ASSERT(base.IsOk() && overlay.IsOk());
+
+
+	unsigned int width=base.GetWidth();
+	unsigned int height=base.GetHeight();
+
+
+	wxImage debugIm(width,height);
+	//Now loop through each pixel and perform
+	// combine operation
+	#pragma omp parallel for
+	for(unsigned int uj=0;uj<height;uj++)
+	{
+		unsigned char rgbIm[3],rgbaOv[4];
+		for(unsigned int ui=0;ui<width;ui++)
+		{
+			rgbaOv[3] = overlay.GetAlpha(ui,uj);
+
+			debugIm.SetRGB(ui,uj,rgbaOv[3], rgbaOv[3],rgbaOv[3]);
+			if(rgbaOv[3])
+			{
+				//obtain src rgb
+				rgbIm[0]=base.GetRed(ui,uj);
+				rgbIm[1]=base.GetGreen(ui,uj);
+				rgbIm[2]=base.GetBlue(ui,uj);
+				//obtain overlay rgb	
+				rgbaOv[0]=overlay.GetRed(ui,uj);
+				rgbaOv[1]=overlay.GetGreen(ui,uj);
+				rgbaOv[2]=overlay.GetBlue(ui,uj);
+		
+		
+				for(unsigned int chan=0;chan<3;chan++)
+				{
+					rgbIm[chan] = (unsigned char) (float(255-rgbaOv[3])/255.0f*rgbIm[chan] + float(rgbaOv[3]/255.0f)*rgbaOv[chan]);
+				}
+				
+				base.SetRGB(ui,uj,rgbIm[0],rgbIm[1],rgbIm[2]);	
+			}
+		}
+	}	
+
+	debugIm.SaveFile("debug.png",wxBITMAP_TYPE_PNG);
+}
+
 	
 TreePersistNode::TreePersistNode(const wxTreeCtrl *treeCtrl,wxTreeItemId t)
 {
diff --git a/src/wx/wxcommon.h b/src/wx/wxcommon.h
index a4ee534..7d45756 100644
--- a/src/wx/wxcommon.h
+++ b/src/wx/wxcommon.h
@@ -1,6 +1,6 @@
 /*
  * wxcommon.h  - Common wxwidgets header stuff
- * Copyright (C) 2013  D Haley
+ * Copyright (C) 2014  D Haley
  * 
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -26,9 +26,6 @@
 #include "common/basics.h"
 #include "backend/tree.hh"
 
-#define wxCStr(a) wxString(a,*wxConvCurrent)
-#define wxStr(a) wxString(a.c_str(),*wxConvCurrent)
-
 
 //This function is adapted from
 //http://www.creatis.insa-lyon.fr/software/public/creatools/bbtk/v0_9_2/doc/doxygen/bbtk/bbtkWx_8h-source.html
@@ -135,6 +132,13 @@ extern wxEventType RemoteUpdateAvailEvent;
 //Return true IFF process ID and process name match running process
 bool processMatchesName(size_t processID, const std::string &procName);
 
+//Copy data into a wx image from an unpadded RGBA block of given width/eight
+// image sould already have been initialised, with RGBA and size
+void copyRGBAtoWXImage(unsigned int width, unsigned int height,
+		const unsigned char *rgbaBuf, wxImage &image, const unsigned char *mask);
+
+//Combine an overlay using the alpha channel
+void combineWxImage(wxImage &base, const wxImage &overlay);
 
 //!Remote version thread checker, downloads RSS file from remote system and then
 // parses the file for the latest remote version number
diff --git a/src/wx/wxcomponents.cpp b/src/wx/wxcomponents.cpp
index ca72ced..57de867 100644
--- a/src/wx/wxcomponents.cpp
+++ b/src/wx/wxcomponents.cpp
@@ -89,7 +89,7 @@ void upWxTreeCtrl(const FilterTree &filterTree, wxTreeCtrl *t,
 	
 		//This will use the user label or the type string.	
 		tid=t->AppendItem(treeIDs.top(),
-			wxStr((*filtIt)->getUserString()));
+			((*filtIt)->getUserString()));
 		t->SetItemData(tid,new wxTreeUint(nextID));
 	
 
@@ -165,480 +165,6 @@ std::string choiceStringToCommaDelim(std::string choiceString)
 	return retStr;
 }
 
-BEGIN_EVENT_TABLE(wxCustomPropGrid, wxGrid)
-	EVT_GRID_CELL_LEFT_CLICK(wxCustomPropGrid::OnCellLeftClick )
-	EVT_GRID_LABEL_LEFT_DCLICK(wxCustomPropGrid::OnLabelDClick) 
-	EVT_MOTION(wxCustomPropGrid::OnMouseMove) 
-END_EVENT_TABLE()
-
-wxCustomPropGrid::wxCustomPropGrid(wxWindow* parent, wxWindowID id, 
-		const wxPoint& pos , const wxSize& size , long style ) :
-					wxGrid(parent, id, pos, size , style)
-{
-	lastGridHoverCol=lastGridHoverRow=-1;
-	//Perform wx event connecting/binding
-#if wxCHECK_VERSION(2, 9, 0)
-	GetGridWindow()->Bind(wxEVT_MOTION, &wxCustomPropGrid::OnMouseMove, this);
-#else
-    	GetGridWindow()->Connect(wxID_ANY,
-                 wxEVT_MOTION, wxMouseEventHandler(wxCustomPropGrid::OnMouseMove), NULL, this);
-#endif
-}
-
-
-void wxCustomPropGrid::setGroupName(unsigned int set, const std::string &name) 
-{
-	ASSERT(set < sectionNames.size());
-	sectionNames[set]=name;
-}
-
-void wxCustomPropGrid::OnSize(wxSizeEvent &event)
-{
-
-}
-
-void wxCustomPropGrid::OnLabelDClick(wxGridEvent &event)
-{
-#if wxCHECK_VERSION(2,9,0)
-	if(!this->GetNumberCols())
-#else
-	if(!this->GetCols())
-#endif
-		return;
-	wxSize s;
-	s=this->GetSize();
-	fitCols(s);
-	SelectBlock(-1,-1,-1,-1); //Select empty block
-}
-
-void wxCustomPropGrid::fitCols(wxSize &size)
-{
-	int wc = size.GetWidth()-this->GetScrollThumb(wxVERTICAL)-15;
-	int colSize = this->GetColSize(0) ;
-
-	//SetColSize complains with negative argument
-	if(wc - colSize < 0)
-		return;
-
-	this->SetColSize(1, wc-colSize);
-
-	Refresh();
-}
-
-wxCustomPropGrid::~wxCustomPropGrid()
-{
-#if wxCHECK_VERSION(2, 9, 0)
-   GetGridWindow()->Unbind(wxEVT_MOTION, &wxCustomPropGrid::OnMouseMove, this);
-#else
-   GetGridWindow()->Disconnect();
-#endif
-}
-
-//Function adapted from nomadsync.sourceforge.net (GPL)
-void wxGridCellChoiceRenderer::Draw(wxGrid& grid, wxGridCellAttr& attr, wxDC& dc,
-	const wxRect& rectCell, int row, int col, bool isSelected)
-{
-    wxGridCellRenderer::Draw(grid, attr, dc, rectCell, row, col, isSelected);
-	// first calculate button size
-	// don't draw outside the cell
-	int nButtonWidth = 17;
-	if (rectCell.height < 2) return;	
-	wxRect rectButton;
-	rectButton.x = rectCell.x + rectCell.width - nButtonWidth;
-	rectButton.y = rectCell.y + 1;
-	int cell_rows, cell_cols;
-	attr.GetSize(&cell_rows, &cell_cols);
-	rectButton.width = nButtonWidth;
-	if (cell_rows == 1)
-		rectButton.height = rectCell.height-2;
-	else
-		rectButton.height = nButtonWidth;
-
-	SetTextColoursAndFont(grid, attr, dc, isSelected);
-	int hAlign, vAlign;
-	attr.GetAlignment(&hAlign, &vAlign);
-	// leave room for button
-	wxRect rect = rectCell;
-	rect.SetWidth(rectCell.GetWidth() - rectButton.GetWidth()-2);
-	rect.Inflate(-1);
-	grid.DrawTextRectangle(dc, grid.GetCellValue(row, col), rect, hAlign, vAlign);
-
-	// don't bother drawing if the cell is too small
-	if (rectButton.height < 4 || rectButton.width < 4) return;
-	// draw 3-d button
-	wxColour colourBackGround = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
-	dc.SetBrush(wxBrush(colourBackGround, wxSOLID));
-	dc.SetPen(wxPen(colourBackGround, 1, wxSOLID));
-	dc.DrawRectangle(rectButton);
-	dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), 1, wxSOLID));
-	dc.DrawLine(rectButton.GetLeft(), rectButton.GetBottom(), 
-		rectButton.GetRight(), rectButton.GetBottom());
-	dc.DrawLine(rectButton.GetRight(), rectButton.GetBottom(), 
-		rectButton.GetRight(), rectButton.GetTop()-1);
-	dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNSHADOW), 
-		1, wxSOLID));
-	dc.DrawLine(rectButton.GetLeft()+1, rectButton.GetBottom()-1, 
-		rectButton.GetRight()-1, rectButton.GetBottom()-1);
-	dc.DrawLine(rectButton.GetRight()-1, rectButton.GetBottom()-1, 
-		rectButton.GetRight()-1, rectButton.GetTop());
-	dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNHIGHLIGHT), 
-		1, wxSOLID));
-	dc.DrawLine(rectButton.GetRight()-2, rectButton.GetTop()+1, 
-		rectButton.GetLeft()+1, rectButton.GetTop()+1);
-	dc.DrawLine(rectButton.GetLeft()+1, rectButton.GetTop()+1, 
-		rectButton.GetLeft()+1, rectButton.GetBottom()-1);
-	// Draw little triangle
-	int nTriWidth = 7;
-	int nTriHeight = 4;
-	wxPoint point[3];
-	point[0] = wxPoint(rectButton.GetLeft() + (rectButton.GetWidth()-nTriWidth)/2, 
-		rectButton.GetTop()+(rectButton.GetHeight()-nTriHeight)/2);
-	point[1] = wxPoint(point[0].x+nTriWidth-1, point[0].y);
-	point[2] = wxPoint(point[0].x+3, point[0].y+nTriHeight-1);
-	dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), wxSOLID));
-	dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT), 1, wxSOLID));
-	dc.DrawPolygon(3, point);
-	if (m_border == wxLAYOUT_TOP)
-	{
-		dc.SetPen(wxPen(*wxBLACK, 1, wxDOT));
-		dc.DrawLine(rectCell.GetRight(), rectCell.GetTop(), 
-			rectCell.GetLeft(), rectCell.GetTop());
-	}
-}
-
-bool wxCustomPropGrid::isSeparatorRow(int row) const
-{
-	//TODO: Consider moving to map, this does not scale well.
-	// for now we have usually five or six items tho
-	return std::find(sepRows.begin(),sepRows.end(),row)!=sepRows.end();
-}
-
-void wxCustomPropGrid::OnMouseMove(wxMouseEvent &event)
-{
-
-	int xPos,yPos;
-	int xMouse,yMouse;
-	event.GetPosition(&xMouse,&yMouse);
-
-	CalcUnscrolledPosition(xMouse,yMouse,&xPos,&yPos);
-
-	int row,col;
-	row=YToRow(yPos);
-	col=XToCol(xPos);
-
-	//Check if the column or row was different
-	if(col != lastGridHoverCol || row != lastGridHoverRow)
-	{
-		lastGridHoverRow = row;
-		lastGridHoverCol = col;
-
-		//If we are hovering over a "spacer" row,
-		//the null row, or not on the prop
-		//column, then bail out
-		if(isSeparatorRow(row) || row == -1  || col == 1)
-		{
-			GetGridWindow()->SetToolTip(NULL); //Hide the tooltip
-			event.Skip();
-			return;
-		}
-
-		//Set the help text based upon the group property
-		const GRID_PROPERTY *p;
-		p=getProperty(getKeyFromRow(row));
-	
-		GetGridWindow()->SetToolTip(wxStr(p->helpText));
-	}
-
-	event.Skip();
-}
-
-//Function adapted from nomadsync.sourceforge.net (GPL)
-void wxCustomPropGrid::OnCellLeftClick(wxGridEvent &ev)
-{
-	// This forces the cell to go into edit mode directly
-	m_waitForSlowClick = true;
-	SetGridCursor(ev.GetRow(), ev.GetCol());
-
-	// hack to prevent selection from being lost when click combobox
-	if (ev.GetCol() == 0 && IsInSelection(ev.GetRow(), ev.GetCol()))
-	{
-		m_selection = NULL;
-	}
-	ev.Skip();
-}
-
-void wxCustomPropGrid::clear()
-{
-	this->BeginBatch();
-	//Empty the grid
-	if(this->GetNumberCols())
-		this->DeleteCols(0,this->GetNumberCols());
-	if(this->GetNumberRows())
-		this->DeleteRows(0,this->GetNumberRows());
-	
-	
-	propertyKeys.clear();
-	this->EndBatch();
-
-	GetGridWindow()->SetToolTip(wxT(""));
-	lastGridHoverRow=lastGridHoverCol=-1;
-}
-
-bool wxCustomPropGrid::isComboEditing() 
-{
-	bool retVal;
-	retVal= IsCellEditControlEnabled();
-#if wxCHECK_VERSION(2,9,0)
-	retVal = retVal &&getTypeFromRow(this->GetGridCursorRow()) == PROPERTY_TYPE_CHOICE;
-#else
-	retVal = retVal && getTypeFromRow(this->GetCursorRow()) == PROPERTY_TYPE_CHOICE;
-#endif
-	return retVal;
-};
-
-unsigned int wxCustomPropGrid::getTypeFromRow(int row) const
-{
-	for(unsigned int ui=0;ui<propertyKeys.size();ui++)
-	{
-
-		for(unsigned int uj=0;uj<propertyKeys[ui].size();uj++)
-		{
-			if(propertyKeys[ui][uj].renderPosition == row)
-				return propertyKeys[ui][uj].type;
-		}
-	}
-
-	ASSERT(false);
-	return 0; // Shut gcc up
-}
-
-void  wxCustomPropGrid::clearKeys()
-{
-	propertyKeys.clear();
-	sectionNames.clear();
-}
-
-void wxCustomPropGrid::addKey(const std::string &name, unsigned int group,
-		unsigned int newKey, unsigned int type, const std::string &data,
-		const std::string &helpText)
-{
-
-	GRID_PROPERTY newProp;
-	newProp.key=newKey;
-	newProp.type=type;
-	newProp.name=name;
-	newProp.data=data;
-	newProp.helpText = helpText;
-	propertyKeys[group].push_back(newProp);
-}
-
-//Layout the property vector
-void wxCustomPropGrid::propertyLayout()
-{
-	this->BeginBatch();
-
-	//Empty the grid
-	if(this->GetNumberCols())
-		this->DeleteCols(0,this->GetNumberCols());
-	if(this->GetNumberRows())
-		this->DeleteRows(0,this->GetNumberRows());
-
-	this->AppendCols(2);
-	this->SetColLabelValue(0,wxTRANS("Param"));
-	this->SetColLabelValue(1,wxTRANS("Value"));
-
-	sepRows.clear();
-	sepRows.resize(propertyKeys.size());
-	int rows=0;
-	for (unsigned int ui=0; ui<propertyKeys.size(); ui++)
-	{
-		//One row for each property
-		for (unsigned uj=0; uj<propertyKeys[ui].size(); uj++)
-			propertyKeys[ui][uj].renderPosition=rows+uj;
-
-		rows+=propertyKeys[ui].size();
-
-		//One row for separator
-		sepRows[ui] = rows;
-		rows++;
-	}
-
-	//Remove last separator row.
-	if (rows)
-		rows--;
-	this->AppendRows(rows);
-
-	for (unsigned int ui=0; ui<propertyKeys.size(); ui++)
-	{
-		for (unsigned int uj=0; uj<propertyKeys[ui].size(); uj++)
-		{
-			//set the title
-			this->SetCellValue(propertyKeys[ui][uj].renderPosition,
-			                   0,wxStr(propertyKeys[ui][uj].name));
-
-			//Set the cell renderer
-			wxGridCellAttr *attr = this->GetOrCreateCellAttr(
-			                           propertyKeys[ui][uj].renderPosition, 1);
-
-			//Attr will return 0 if the grid is not created.
-			//you must create the grid before calling this function 
-			//(see wxGrd::CreateGrid(i,j)
-			ASSERT(attr);
-			//The datatype determines the appearance of the combo box
-			switch (propertyKeys[ui][uj].type)
-			{
-			case PROPERTY_TYPE_BOOL:
-				attr->SetRenderer(new wxGridCellBoolRenderer());
-				//set the data
-				this->SetCellValue(propertyKeys[ui][uj].renderPosition,
-				                   1,wxStr(propertyKeys[ui][uj].data));
-				break;
-			case PROPERTY_TYPE_INTEGER:
-				attr->SetRenderer(new wxGridCellNumberRenderer());
-				//set the data
-				this->SetCellValue(propertyKeys[ui][uj].renderPosition,
-				                   1,wxStr(propertyKeys[ui][uj].data));
-				break;
-			case PROPERTY_TYPE_REAL:
-				attr->SetRenderer(new wxGridCellFloatRenderer());
-				//set the data
-				this->SetCellValue(propertyKeys[ui][uj].renderPosition,
-				                   1,wxStr(propertyKeys[ui][uj].data));
-				break;
-			case PROPERTY_TYPE_COLOUR:
-				//OK, this is totally inefficient, and hacky. but set the colour
-				//based upon the colour string. Then when user edits, use a colour
-				//dialog (handled elsewhere)
-				unsigned char r,g,b,a;
-				parseColString(propertyKeys[ui][uj].data,r,g,b,a);
-				attr->SetBackgroundColour(wxColour(r,g,b,a));
-
-				break;
-			case PROPERTY_TYPE_CHOICE:
-			{
-				//set up the renderer
-				std::string s;
-				s=getActiveChoice(propertyKeys[ui][uj].data);
-				attr->SetRenderer(new wxGridCellChoiceRenderer());
-				this->SetCellValue(propertyKeys[ui][uj].renderPosition,
-				                   1,wxStr(s));
-
-				//construct a wxStringArray of possible choices.
-				s=choiceStringToCommaDelim(propertyKeys[ui][uj].data);
-				vector<std::string> splitStrs;
-				wxArrayString a;
-				splitStrsRef(s.c_str(),',',splitStrs);
-				for (unsigned int uk=0; uk<splitStrs.size(); uk++)
-					a.Add(wxStr(splitStrs[uk]));
-				//Set up the editor
-				wxGridCellChoiceEditor *choiceEd=new wxFastComboEditor(a,false);
-				this->SetCellEditor(propertyKeys[ui][uj].renderPosition,
-				                    1,choiceEd);
-
-				//Required to prevent wx from asserting,
-				// "GetEventHandler == this" failed in ~wxWindowBase(), any pushed event handlers must be removed".
-				// I posted on the wxwidgets forum and got the reply that I should try this, but they were not sure.
-				// seems to work
-				attr->DecRef();
-				break;
-			}
-			case PROPERTY_TYPE_STRING:
-			case PROPERTY_TYPE_POINT3D:
-				//set the data
-				this->SetCellValue(propertyKeys[ui][uj].renderPosition,
-				                   1,wxStr(propertyKeys[ui][uj].data));
-				break;
-			}
-
-
-		}
-
-		//Add a blank, light grey, read only row, but not if it is the last
-		//use to denote spacing between sets to user.
-		if (ui+1 < propertyKeys.size())
-		{
-			//Optionally give it a description; if one has been provided
-			if(sectionNames[ui+1].size())
-			{
-				this->SetCellValue(sepRows[ui],0,wxStr(sectionNames[ui+1]));
-				wxFont f;
-				f=*wxSMALL_FONT;
-				f.SetStyle(wxFONTSTYLE_ITALIC);
-				f.SetPointSize((int)(f.GetPointSize()*FONT_HEADING_SCALEFACTOR));
-				this->SetCellFont(sepRows[ui],0,f);
-			}
-
-			wxGridCellAttr *readOnlyRowAttr=new wxGridCellAttr;
-			readOnlyRowAttr->SetReadOnly(true);
-			readOnlyRowAttr->SetBackgroundColour(wxColour(*wxLIGHT_GREY));
-			this->SetRowAttr(sepRows[ui],readOnlyRowAttr);
-
-		}
-	}
-
-	//First column is read only
-	wxGridCellAttr *readOnlyGridAttr=new wxGridCellAttr;
-	readOnlyGridAttr->SetReadOnly(true);
-	SetColAttr(0,readOnlyGridAttr);
-	//Remove labels for column lead-in
-	SetRowLabelSize(0);
-	SetMargins(0,0);
-
-	AutoSizeColumn(0,true);
-	EndBatch();
-
-	//Expand the column contents to fit current size	
-	wxSize s;
-	s=GetSize();
-	fitCols(s);
-}
-
-unsigned int  wxCustomPropGrid::getKeyFromRow(int row) const
-{
-	for(unsigned int ui=0;ui<propertyKeys.size();ui++)
-	{
-
-		for(unsigned int uj=0;uj<propertyKeys[ui].size();uj++)
-		{
-			if(propertyKeys[ui][uj].renderPosition == row)
-				return propertyKeys[ui][uj].key;
-		}
-	}
-
-	ASSERT(false);
-	return 0; // Shut gcc up
-}
-
-const GRID_PROPERTY *wxCustomPropGrid::getProperty(unsigned int key) const
-{
-	for(unsigned int group=0;group<propertyKeys.size();group++)
-	{
-		for(unsigned int ui=0;ui<propertyKeys[group].size(); ui++)
-		{
-			if(propertyKeys[group][ui].key == key)
-				return &(propertyKeys[group][ui]);
-		}
-	}
-	return 0;
-}
-
-void wxFastComboEditor::BeginEdit(int row, int col, wxGrid* grid)
-{
-	wxGridCellChoiceEditor::BeginEdit(row, col, grid);
-	// unfortunately I don't know how to send a left button down message to a 
-	// control in GTK, if anyone can give me a hint it would be greatly appreciated :)
-#ifdef __WINDOWS__
-	DWORD style = ::GetWindowLong((HWND)Combo()->GetHandle(), GWL_STYLE);
-	style &= ~WS_TABSTOP;
-	::SetWindowLong((HWND)Combo()->GetHandle(), GWL_STYLE, style);
-	if (m_pointActivate.x > -1 && m_pointActivate.y > -1)
-	{
-		m_pointActivate = Combo()->ScreenToClient(m_pointActivate);
-		SendMessage((HWND)Combo()->GetHandle(), WM_LBUTTONDOWN, 0,
-			MAKELPARAM(m_pointActivate.x, m_pointActivate.y));
-	}
-#endif
-}
 
 BEGIN_EVENT_TABLE(CopyGrid, wxGrid)
 	EVT_KEY_DOWN(CopyGrid::OnKey) 
@@ -658,8 +184,8 @@ void CopyGrid::selectData()
 
 void CopyGrid::saveData()
 {
-	wxFileDialog *wxF = new wxFileDialog(this,wxTRANS("Save Data..."), wxT(""),
-		wxT(""),wxTRANS("Text File (*.txt)|*.txt|All Files (*)|*"),wxFD_SAVE);
+	wxFileDialog *wxF = new wxFileDialog(this,TRANS("Save Data..."), wxT(""),
+		wxT(""),TRANS("Text File (*.txt)|*.txt|All Files (*)|*"),wxFD_SAVE);
 
 	if( (wxF->ShowModal() == wxID_CANCEL))
 		return;
@@ -671,7 +197,7 @@ void CopyGrid::saveData()
 	if(!f)
 	{
 		wxMessageDialog *wxD  =new wxMessageDialog(this,
-			wxTRANS("Error saving file. Check output dir is writable."),wxTRANS("Save error"),wxOK|wxICON_ERROR);
+			TRANS("Error saving file. Check output dir is writable."),TRANS("Save error"),wxOK|wxICON_ERROR);
 
 		wxD->ShowModal();
 		wxD->Destroy();
@@ -681,13 +207,8 @@ void CopyGrid::saveData()
 
         // Number of rows and cols
         int rows,cols;
-#if wxCHECK_VERSION(2,9,0)
 	rows=GetNumberRows();
 	cols=GetNumberCols();
-#else
-	rows=GetRows();
-	cols=GetCols();
-#endif
         // data variable contain text that must be set in the clipboard
         // For each cell in selected range append the cell value in the data
 	//variable
@@ -883,7 +404,7 @@ void CopyGrid::copyData()
 	{
 		wxTextDataObject* clipData= new wxTextDataObject;
 		// Set data object value
-		clipData->SetText(wxStr(data));
+		clipData->SetText((data));
 		wxTheClipboard->UsePrimarySelection(false);
 		wxTheClipboard->SetData(clipData);
 		wxTheClipboard->Close();
@@ -934,7 +455,7 @@ void TextTreeCtrl::OnTreePaint(wxPaintEvent &event)
 	if(font.IsOk())
 		dc->SetFont(font);
 	
-	wxSize textSize=dc->GetTextExtent(wxStr(messageStrs[idx]));
+	wxSize textSize=dc->GetTextExtent((messageStrs[idx]));
 
 	//Don't go ahead with the drawing if the text
 	// won't fit in the control
@@ -948,23 +469,26 @@ void TextTreeCtrl::OnTreePaint(wxPaintEvent &event)
 	}
 
 	//Draw each text in turn, advancing by spacing
-	
+
+//FIXME dc->DrawText missing under windows?
+#ifndef __WIN32__
 	// start far enough back so that 
 	float startY= 0.5*(h - blockHeight);
 
 	for(size_t ui=0;ui<messageStrs.size();ui++)
 	{
-		textSize=dc->GetTextExtent(wxStr(messageStrs[ui]));
+		textSize=dc->GetTextExtent((messageStrs[ui]));
 		int startX;
 		startX=w/2 - textSize.GetWidth()/2; 
 
-		dc->DrawText(wxStr(messageStrs[ui]),
+		dc->DrawText((messageStrs[ui]),
 					startX,startY);	
 		
 		startY+=HEIGHT_SPACING*textSize.GetHeight();
 	}
 
 	delete dc;
+#endif
 }
 
 std::string TTFFinder::findFont(const char *fontFile)
@@ -999,14 +523,14 @@ std::string TTFFinder::macFindFont(const char *fontFile)
 	//Try a few standard locations
 	while(strlen(dirs[ui]))
 	{
-		p->Add(wxCStr(dirs[ui]));
+		p->Add((dirs[ui]));
 		ui++;
 	};
 
 	wxString s;
 
 	//execute the search for the file
-	s= p->FindValidPath(wxCStr(fontFile));
+	s= p->FindValidPath((fontFile));
 
 
 	std::string res;
@@ -1045,14 +569,14 @@ std::string TTFFinder::nxFindFont(const char *fontFile)
 	//Try a few standard locations
 	while(strlen(dirs[ui]))
 	{
-		p->Add(wxCStr(dirs[ui]));
+		p->Add((dirs[ui]));
 		ui++;
 	};
 
 	wxString s;
 
 	//execute the search for the file
-	s= p->FindValidPath(wxCStr(fontFile));
+	s= p->FindValidPath((fontFile));
 
 
 	std::string res;
@@ -1081,7 +605,7 @@ std::string TTFFinder::winFindFont(const char *fontFile)
 	//Try a few standard locations
 	while(strlen(dirs[ui]))
 	{
-		p->Add(wxCStr(dirs[ui]));
+		p->Add((dirs[ui]));
 		ui++;
 	};
 
@@ -1090,7 +614,7 @@ std::string TTFFinder::winFindFont(const char *fontFile)
   
  
 	//execute the search for the file
-	s= p->FindValidPath(wxCStr(fontFile));
+	s= p->FindValidPath((fontFile));
 
 
 	std::string res;
diff --git a/src/wx/wxcomponents.h b/src/wx/wxcomponents.h
index b10d790..0405ef3 100644
--- a/src/wx/wxcomponents.h
+++ b/src/wx/wxcomponents.h
@@ -30,22 +30,6 @@
 
 #include "backend/filtertree.h"
 
-//Shut wxwidgets assertion errors up by defining a "safe" cb_sort wrapper macro
-#if defined(__WXMAC__) || defined(__WXGTK20__)
-	       
-    #include <wx/version.h>
-    #if wxCHECK_VERSION(2,9,0)
-    //Sorted combos not supported under gtk in 2.8 series 
-    // http://trac.wxwidgets.org/ticket/4398
-    //and not supported in mac.
-    // http://trac.wxwidgets.org/ticket/12419
-        #define SAFE_CB_SORT 0 
-    #else
-        #define SAFE_CB_SORT wxCB_SORT
-	#endif
-#else
-	#define SAFE_CB_SORT wxCB_SORT
-#endif
 
 
 //!3D combo grid renderer, from
@@ -122,88 +106,7 @@ class wxListUint : public wxClientData
 		unsigned int value;
 };
 
-struct GRID_PROPERTY
-{
-	unsigned int key;
-	unsigned int type;
-	int renderPosition;
-	std::string name;
-	std::string data; //String version of data stored
-	std::string helpText; //Hover tool-tip help text
-};
-
-class wxCustomPropGrid;
-
-//!WxGrid derived class to hold and display property data
-//So it turns out that someone has MADE a property grid.
-//http://wxpropgrid.sourceforge.ne
-//This code is not from there. Maybe I should 
-//use their code instead, its bound to be better. 
-//Also, this appears up in the wxwidgets SVN, 
-//so maybe there will be a name clash in future
-class wxCustomPropGrid : public wxGrid
-{
-	protected:
-		//First element is key number. Second element is key type
-		std::vector<std::vector<GRID_PROPERTY> > propertyKeys;
-		//Names of each of the grouped keys in propertyKeys
-		std::vector<std::string> sectionNames;
-
-		//Fit the columns to the specified size
-		void fitCols(wxSize &size);
-
-		//Rows used for separators
-		std::vector<int> sepRows;
-		//The last coordinates of mouse hovering 
-		size_t lastGridHoverCol,lastGridHoverRow;
-
-		//Is the nth row a separator row?
-		bool isSeparatorRow(int row) const;
-	public:
-		wxCustomPropGrid(wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition, 
-					const wxSize& size = wxDefaultSize, long style = wxWANTS_CHARS);
-		~wxCustomPropGrid();
-		
-		void OnSize(wxSizeEvent &size);
-		void OnLabelDClick(wxGridEvent &size);
-		void OnMouseMove(wxMouseEvent &mouse);
-		void clearKeys();
-
-		//!Set the number of separator groups to use 
-		void setNumGroups(unsigned int newGroupCount){propertyKeys.resize(newGroupCount); sectionNames.resize(newGroupCount);};
-
-		//Set the names for each group. This will appear as a small text in the blank rows
-		void setGroupName(unsigned int set, const std::string &name); 
-
-		//!This adds the item to the property key vector of a specified group 
-		//!	key must be unique 
-		void addKey(const std::string &name, unsigned int group,
-				unsigned int newKey, unsigned int type, 
-				const std::string &data,const std::string &helpText);
-		
-		//!Click event
-		virtual void OnCellLeftClick(wxGridEvent &e);
 
-		//!Cause grid to layout its elements
-		void propertyLayout();
-
-		//!Get the key from the row
-		unsigned int getKeyFromRow(int row) const;
-
-		//!Get the type from the row
-		unsigned int getTypeFromRow(int row) const;
-
-		//!Get the property from key and set 
-		const GRID_PROPERTY* getProperty(unsigned int key) const;
-
-		//!Clear the grid
-		void clear();
-
-		//!Are we editing a combo box? 
-		bool isComboEditing() ;
-
-		DECLARE_EVENT_TABLE()
-};
 
 //A wx Grid with copy & paste support
 class CopyGrid : public wxGrid
diff --git a/test/dogtail/test.py b/test/dogtail/test.py
index 039fc9d..6e66890 100755
--- a/test/dogtail/test.py
+++ b/test/dogtail/test.py
@@ -293,7 +293,7 @@ def prefTests(app3depict):
 	prefDialog=app3depict.findChild(element("Preferences","frame"));
 
 	#Get defaults tab
-	tabFilterDefaults=prefDialog.findChild(element("Pref","page tab",));
+	tabFilterDefaults=prefDialog.findChild(element("Filt. Default","page tab",));
 	#Walk through all the filter entries in the list, clicking each one
 	listFilters=tabFilterDefaults.findChild(element("","table"))
 	listFilterEntries=tabFilterDefaults.findChildren(element("","table cell"))	
diff --git a/translations/3Depict_base.pot b/translations/3Depict_base.pot
index 6ae63d3..2c9adb0 100644
--- a/translations/3Depict_base.pot
+++ b/translations/3Depict_base.pot
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-04-12 18:12+0200\n"
+"POT-Creation-Date: 2014-08-23 15:32+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
 "Language-Team: LANGUAGE <LL at li.org>\n"
@@ -17,25 +17,25 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: ../src/gl/cameras.cpp:598 ../src/gl/cameras.cpp:600
+#: ../src/gl/cameras.cpp:596
 msgid "Lock"
 msgstr ""
 
-#: ../src/gl/cameras.cpp:607 ../src/backend/filters/ionClip.cpp:526
-#: ../src/backend/filters/ionClip.cpp:548
-#: ../src/backend/filters/ionClip.cpp:570
-#: ../src/backend/filters/ionClip.cpp:610
-#: ../src/backend/filters/compositionProfile.cpp:1015
-#: ../src/backend/filters/compositionProfile.cpp:1056
-#: ../src/backend/filters/spatialAnalysis.cpp:599
-#: ../src/backend/filters/transform.cpp:1264
-#: ../src/backend/filters/transform.cpp:1291
-#: ../src/backend/filters/transform.cpp:1317
-#: ../src/backend/filters/annotation.cpp:569
+#: ../src/gl/cameras.cpp:603 ../src/backend/filters/ionClip.cpp:519
+#: ../src/backend/filters/ionClip.cpp:541
+#: ../src/backend/filters/ionClip.cpp:563
+#: ../src/backend/filters/ionClip.cpp:600
+#: ../src/backend/filters/compositionProfile.cpp:964
+#: ../src/backend/filters/compositionProfile.cpp:1002
+#: ../src/backend/filters/spatialAnalysis.cpp:774
+#: ../src/backend/filters/transform.cpp:1216
+#: ../src/backend/filters/transform.cpp:1243
+#: ../src/backend/filters/transform.cpp:1269
+#: ../src/backend/filters/annotation.cpp:563
 msgid "Origin"
 msgstr ""
 
-#: ../src/gl/cameras.cpp:612 ../src/backend/filters/spatialAnalysis.cpp:518
+#: ../src/gl/cameras.cpp:611 ../src/backend/filters/spatialAnalysis.cpp:697
 msgid "Target"
 msgstr ""
 
@@ -43,12 +43,12 @@ msgstr ""
 msgid "Up Dir."
 msgstr ""
 
-#: ../src/gl/cameras.cpp:625 ../src/gl/cameras.cpp:729
+#: ../src/gl/cameras.cpp:625 ../src/gl/cameras.cpp:728
 msgid "Perspective"
 msgstr ""
 
-#: ../src/gl/cameras.cpp:627 ../src/gl/cameras.cpp:731
-#: ../src/gui/mainFrame.cpp:5396
+#: ../src/gl/cameras.cpp:627 ../src/gl/cameras.cpp:730
+#: ../src/gui/mainFrame.cpp:5134
 msgid "Orthogonal"
 msgstr ""
 
@@ -56,167 +56,135 @@ msgstr ""
 msgid "Projection"
 msgstr ""
 
-#: ../src/gl/cameras.cpp:639
+#: ../src/gl/cameras.cpp:640
 msgid "Field of View (deg)"
 msgstr ""
 
-#: ../src/gl/cameras.cpp:645
+#: ../src/gl/cameras.cpp:646
 msgid "View size"
 msgstr ""
 
-#: ../src/wx/wxcomponents.cpp:441 ../src/gui/dialogs/ExportRngDialog.cpp:88
-#: ../src/gui/dialogs/prefDialog.cpp:110
-msgid "Param"
-msgstr ""
-
-#: ../src/wx/wxcomponents.cpp:442 ../src/gui/dialogs/ExportRngDialog.cpp:89
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:109
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:356
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1186
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1211
-#: ../src/gui/dialogs/prefDialog.cpp:111 ../src/gui/mainFrame.cpp:5849
-#: ../src/gui/mainFrame.cpp:5854 ../src/backend/filters/dataLoad.cpp:575
-msgid "Value"
-msgstr ""
-
-#: ../src/wx/wxcomponents.cpp:655
+#: ../src/wx/wxcomponents.cpp:187
 msgid "Save Data..."
 msgstr ""
 
-#: ../src/wx/wxcomponents.cpp:656
+#: ../src/wx/wxcomponents.cpp:188
 msgid "Text File (*.txt)|*.txt|All Files (*)|*"
 msgstr ""
 
-#: ../src/wx/wxcomponents.cpp:668
+#: ../src/wx/wxcomponents.cpp:200
 msgid "Error saving file. Check output dir is writable."
 msgstr ""
 
-#: ../src/wx/wxcomponents.cpp:668 ../src/gui/dialogs/ExportRngDialog.cpp:170
-#: ../src/gui/mainFrame.cpp:1422 ../src/gui/mainFrame.cpp:1548
-#: ../src/gui/mainFrame.cpp:1583 ../src/gui/mainFrame.cpp:1659
-#: ../src/gui/mainFrame.cpp:2213 ../src/gui/mainFrame.cpp:2279
-#: ../src/gui/mainFrame.cpp:2371 ../src/gui/mainFrame.cpp:2486
+#: ../src/wx/wxcomponents.cpp:200 ../src/gui/dialogs/ExportRngDialog.cpp:170
+#: ../src/gui/mainFrame.cpp:1446 ../src/gui/mainFrame.cpp:1572
+#: ../src/gui/mainFrame.cpp:1621 ../src/gui/mainFrame.cpp:1697
+#: ../src/gui/mainFrame.cpp:2253 ../src/gui/mainFrame.cpp:2319
+#: ../src/gui/mainFrame.cpp:2411 ../src/gui/mainFrame.cpp:2526
 msgid "Save error"
 msgstr ""
 
-#: ../src/common/basics.cpp:62 ../src/backend/APT/APTFileIO.cpp:65
-#: ../src/backend/APT/APTFileIO.cpp:89
-msgid "Error opening file"
-msgstr ""
-
-#: ../src/common/basics.cpp:63
-msgid "Error whilst reading file contents"
-msgstr ""
-
-#: ../src/common/basics.cpp:64 ../src/backend/APT/APTFileIO.cpp:69
-msgid "Error interpreting field in file"
-msgstr ""
-
-#: ../src/common/basics.cpp:65
-msgid "Inconsistent number of columns found"
-msgstr ""
-
-#: ../src/common/basics.cpp:197
+#: ../src/common/basics.cpp:183
 msgid "in the future?"
 msgstr ""
 
-#: ../src/common/basics.cpp:248
+#: ../src/common/basics.cpp:234
 msgid "a decade ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:249
+#: ../src/common/basics.cpp:235
 msgid "a year ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:250
+#: ../src/common/basics.cpp:236
 msgid "a month ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:251
+#: ../src/common/basics.cpp:237
 msgid "a week ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:252
+#: ../src/common/basics.cpp:238
 msgid "a day ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:253
+#: ../src/common/basics.cpp:239
 msgid "an hour ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:254
+#: ../src/common/basics.cpp:240
 msgid "45 minutes ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:255
+#: ../src/common/basics.cpp:241
 msgid "30 minutes ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:256
+#: ../src/common/basics.cpp:242
 msgid "20 minutes ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:257
+#: ../src/common/basics.cpp:243
 msgid "15 minutes ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:258
+#: ../src/common/basics.cpp:244
 msgid "10 minutes ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:259
+#: ../src/common/basics.cpp:245
 msgid "5 minutes ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:260
+#: ../src/common/basics.cpp:246
 msgid "a minute ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:261
+#: ../src/common/basics.cpp:247
 msgid "30 seconds ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:262
+#: ../src/common/basics.cpp:248
 msgid "10 seconds ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:263
+#: ../src/common/basics.cpp:249
 msgid "a second ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:268
+#: ../src/common/basics.cpp:254
 msgid "a few decades ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:269
+#: ../src/common/basics.cpp:255
 msgid "a few years ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:270
+#: ../src/common/basics.cpp:256
 msgid "a few months ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:271
+#: ../src/common/basics.cpp:257
 msgid "a few weeks ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:272
+#: ../src/common/basics.cpp:258
 msgid "a few days ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:273
+#: ../src/common/basics.cpp:259
 msgid "a few hours ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:280
+#: ../src/common/basics.cpp:266
 msgid "a few minutes ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:283
+#: ../src/common/basics.cpp:269
 msgid "a few seconds ago"
 msgstr ""
 
-#: ../src/common/basics.cpp:310
+#: ../src/common/basics.cpp:296
 msgid "moments ago"
 msgstr ""
 
@@ -252,40 +220,43 @@ msgstr ""
 msgid "Pseudo-Random"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:670
+#: ../src/common/constants.cpp:22
+msgid ""
+"Range Files (*.rng; *.env; *.rrng)|*.rng;*.env;*.rrng;*.RRNG;*.RNG;*.ENV|RNG "
+"File (*.rng)|*.rng;*.RNG|Environment File (*.env)|*.env;*.ENV|RRNG Files (*."
+"rrng)|*.rrng;*.RRNG|All Files (*)|*"
+msgstr ""
+
+#: ../src/gui/glPane.cpp:637
 msgid "Use shift/ctrl-space or double tap to alter reset axis"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:934
+#: ../src/gui/glPane.cpp:910
 msgid "Image progress"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:935
+#: ../src/gui/glPane.cpp:911
 msgid "Rendering tiles..."
 msgstr ""
 
-#: ../src/gui/glPane.cpp:969
-msgid "Tile "
-msgstr ""
-
-#: ../src/gui/glPane.cpp:969 ../src/gui/glPane.cpp:1080
-#: ../src/gui/mainFrame.cpp:4279 ../src/gui/mainFrame.cpp:4283
-#: ../src/gui/mainFrame.cpp:4296 ../src/backend/filters/dataLoad.cpp:311
-msgid " of "
-msgstr ""
-
-#: ../src/gui/glPane.cpp:1041
+#: ../src/gui/glPane.cpp:1097
 msgid "Animation progress"
 msgstr ""
 
-#: ../src/gui/glPane.cpp:1042
+#: ../src/gui/glPane.cpp:1098
 msgid "Rendering sequence..."
 msgstr ""
 
-#: ../src/gui/glPane.cpp:1080
+#: ../src/gui/glPane.cpp:1136
 msgid "Saving Image "
 msgstr ""
 
+#: ../src/gui/glPane.cpp:1136 ../src/gui/mainFrame.cpp:4309
+#: ../src/gui/mainFrame.cpp:4313 ../src/gui/mainFrame.cpp:4326
+#: ../src/backend/filters/dataLoad.cpp:307
+msgid " of "
+msgstr ""
+
 #: ../src/gui/dialogs/ExportRngDialog.cpp:40
 msgid "Range Sources"
 msgstr ""
@@ -299,15 +270,29 @@ msgid "Source Filter"
 msgstr ""
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:54
+#: ../src/backend/filters/rangeFile.cpp:665
 msgid "Ions"
 msgstr ""
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:55
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1606
-#: ../src/backend/filters/rangeFile.cpp:729
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1586
+#: ../src/backend/filters/voxelise.cpp:876
+#: ../src/backend/filters/rangeFile.cpp:732
 msgid "Ranges"
 msgstr ""
 
+#: ../src/gui/dialogs/ExportRngDialog.cpp:88
+msgid "Param"
+msgstr ""
+
+#: ../src/gui/dialogs/ExportRngDialog.cpp:89
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:105
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:352
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1173
+#: ../src/backend/filters/dataLoad.cpp:566
+msgid "Value"
+msgstr ""
+
 #: ../src/gui/dialogs/ExportRngDialog.cpp:90
 msgid "Value2"
 msgstr ""
@@ -321,7 +306,7 @@ msgid "Num Ranges"
 msgstr ""
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:116
-#: ../src/gui/dialogs/rangeEditDialog.cpp:710 ../src/backend/filter.cpp:43
+#: ../src/gui/dialogs/rangeEditDialog.cpp:695 ../src/backend/filter.cpp:44
 msgid "Ion"
 msgstr ""
 
@@ -333,7 +318,7 @@ msgstr ""
 msgid "Range end"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2315
+#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2355
 msgid "Save pos..."
 msgstr ""
 
@@ -341,10 +326,10 @@ msgstr ""
 msgid "ORNL format RNG (*.rng)|*.rng|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1422
-#: ../src/gui/mainFrame.cpp:1584 ../src/gui/mainFrame.cpp:1659
-#: ../src/gui/mainFrame.cpp:2214 ../src/gui/mainFrame.cpp:2372
-#: ../src/gui/mainFrame.cpp:2487
+#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1446
+#: ../src/gui/mainFrame.cpp:1622 ../src/gui/mainFrame.cpp:1697
+#: ../src/gui/mainFrame.cpp:2254 ../src/gui/mainFrame.cpp:2412
+#: ../src/gui/mainFrame.cpp:2527
 msgid "Unable to save. Check output destination can be written to."
 msgstr ""
 
@@ -368,86 +353,84 @@ msgstr ""
 msgid "e.g. H2O"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:575
-#: ../src/gui/dialogs/rangeEditDialog.cpp:709 ../src/gui/mainFrame.cpp:6061
-#: ../src/backend/filter.cpp:44
+#: ../src/gui/dialogs/rangeEditDialog.cpp:560
+#: ../src/gui/dialogs/rangeEditDialog.cpp:694 ../src/gui/mainFrame.cpp:5800
+#: ../src/backend/filter.cpp:45
 msgid "Plot"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:576
+#: ../src/gui/dialogs/rangeEditDialog.cpp:561
 msgid "Short Name"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:577
+#: ../src/gui/dialogs/rangeEditDialog.cpp:562
 msgid "Long Name"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:578
-#: ../src/backend/filters/voxelise.cpp:1022
-#: ../src/backend/filters/compositionProfile.cpp:1156
-#: ../src/backend/filters/annotation.cpp:903
-#: ../src/backend/filters/spectrumPlot.cpp:472
+#: ../src/gui/dialogs/rangeEditDialog.cpp:563
+#: ../src/backend/filters/voxelise.cpp:1020
+#: ../src/backend/filters/compositionProfile.cpp:1100
+#: ../src/backend/filters/annotation.cpp:896
+#: ../src/backend/filters/spectrumPlot.cpp:452
 msgid "Colour"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:711
-#: ../src/backend/filters/annotation.cpp:606
-#: ../src/backend/filters/annotation.cpp:645
-#: ../src/backend/filters/annotation.cpp:812
+#: ../src/gui/dialogs/rangeEditDialog.cpp:696
+#: ../src/backend/filters/annotation.cpp:600
+#: ../src/backend/filters/annotation.cpp:641
+#: ../src/backend/filters/annotation.cpp:810
 msgid "Start"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:712
-#: ../src/backend/filters/annotation.cpp:614
-#: ../src/backend/filters/annotation.cpp:654
-#: ../src/backend/filters/annotation.cpp:820
+#: ../src/gui/dialogs/rangeEditDialog.cpp:697
+#: ../src/backend/filters/annotation.cpp:608
+#: ../src/backend/filters/annotation.cpp:650
+#: ../src/backend/filters/annotation.cpp:818
 msgid "End"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1275
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1278
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1259
 msgid "Range or ion?"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1276
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1279
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1260
 msgid "Select type to add"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1561
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1541
 msgid "Range Editor"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1565
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1545
 msgid "Enable or disable all overlays"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1566
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1546
 msgid "Entered overlays, use delete to remove"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1567
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1547
 msgid "Available plots for ranging"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1568
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1548
 msgid "Enter species to display as overlay, e.g. SiO2"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1569
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1549
 msgid "Editable ranges"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1570
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1550
 msgid "Editable ions"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1605
-#: ../src/gui/dialogs/animateFilterDialog.cpp:172
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1585
+#: ../src/gui/dialogs/animateFilterDialog.cpp:173
 msgid "Plots"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1607
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1587
 msgid "Overlay"
 msgstr ""
 
@@ -463,8 +446,8 @@ msgstr ""
 msgid "Multiple autosave states were found; would you like to restore one?"
 msgstr ""
 
-#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:388
-#: ../src/backend/filter.cpp:391
+#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:435
+#: ../src/backend/filter.cpp:438
 msgid "Error"
 msgstr ""
 
@@ -477,46 +460,46 @@ msgstr ""
 msgid "Filter Errors"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:45
+#: ../src/gui/dialogs/StashDialog.cpp:46
 msgid "Stashes"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:48
+#: ../src/gui/dialogs/StashDialog.cpp:49
 msgid "Stashed Tree"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:50
+#: ../src/gui/dialogs/StashDialog.cpp:51
 msgid "Properties"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:86
+#: ../src/gui/dialogs/StashDialog.cpp:57
+msgid "Stash Name"
+msgstr ""
+
+#: ../src/gui/dialogs/StashDialog.cpp:58
+msgid "Filter Count"
+msgstr ""
+
+#: ../src/gui/dialogs/StashDialog.cpp:91
 msgid "Stashed Trees"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:89
+#: ../src/gui/dialogs/StashDialog.cpp:94
 msgid "Erase stashed item"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:90
+#: ../src/gui/dialogs/StashDialog.cpp:95
 msgid "Filter view for current stash"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:91
+#: ../src/gui/dialogs/StashDialog.cpp:96
 msgid "Settings for selected filter in current stash"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:92
+#: ../src/gui/dialogs/StashDialog.cpp:97
 msgid "Available stashes"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:153
-msgid "Stash Name"
-msgstr ""
-
-#: ../src/gui/dialogs/StashDialog.cpp:154
-msgid "Filter Count"
-msgstr ""
-
 #: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:45
 msgid "Start Frame: "
 msgstr ""
@@ -529,57 +512,57 @@ msgstr ""
 msgid "From Table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:108
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:354
-#: ../src/gui/dialogs/animateFilterDialog.cpp:191
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:104
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:350
+#: ../src/gui/dialogs/animateFilterDialog.cpp:192
 msgid "Frame"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:244
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:240
 msgid "Select text file..."
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:245
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:241
 msgid "Text files (*.txt)|*.txt;|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:346
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:342
 msgid "String Keyframes"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:348
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:344
 msgid "Frame at which to start string sequence"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:349
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:345
 msgid "Frame offset for data start"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:350
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:346
 msgid "File to use as string data source, one value per row"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:351
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:347
 msgid "Select file to use as data source"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:352
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:348
 msgid "Use table below for data source"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:358
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:354
 msgid "Add new data rows to table, hold shift/cmd to insert multiple rows"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:359
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:355
 msgid "Remove selected strings from table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:360
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:356
 msgid "Abort value selection and return to previous window"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:361
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:357
 msgid "Accept data values"
 msgstr ""
 
@@ -600,12 +583,12 @@ msgid "Ramp"
 msgstr ""
 
 #: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:64
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1192
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1154
 msgid "Start Frame"
 msgstr ""
 
 #: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:66
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1193
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1155
 msgid "End Frame"
 msgstr ""
 
@@ -625,219 +608,221 @@ msgstr ""
 msgid "endColour"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:237
+#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:235
 msgid "Key Frame : Colour"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:239
+#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:237
 msgid "Colour at the start of the transtition"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:240
+#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:238
 msgid "Colour at end of transition"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:91
+#: ../src/gui/dialogs/animateFilterDialog.cpp:92
 msgid "Oak-Ridge RNG"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:92
+#: ../src/gui/dialogs/animateFilterDialog.cpp:93
 msgid "Cameca/Ametek RRNG"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:93
+#: ../src/gui/dialogs/animateFilterDialog.cpp:94
 msgid "Cameca/Ametek ENV"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:151
+#: ../src/gui/dialogs/animateFilterDialog.cpp:152
 msgid "Key frames"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:152
+#: ../src/gui/dialogs/animateFilterDialog.cpp:153
 msgid "Output Data"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:153
+#: ../src/gui/dialogs/animateFilterDialog.cpp:154
 msgid "Filters and properties"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:159
+#: ../src/gui/dialogs/animateFilterDialog.cpp:160
 msgid "Dir : "
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:162
+#: ../src/gui/dialogs/animateFilterDialog.cpp:163
 msgid "Output only when refresh required"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:164
+#: ../src/gui/dialogs/animateFilterDialog.cpp:165
 msgid "Data Types:"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:165
+#: ../src/gui/dialogs/animateFilterDialog.cpp:166
 msgid "3D Images"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:166
+#: ../src/gui/dialogs/animateFilterDialog.cpp:167
 msgid "File Suffix: "
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:168
+#: ../src/gui/dialogs/animateFilterDialog.cpp:169
 msgid "Size : "
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:170
+#: ../src/gui/dialogs/animateFilterDialog.cpp:171
 msgid "..."
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:171
+#: ../src/gui/dialogs/animateFilterDialog.cpp:172
 msgid "Point data"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:173
+#: ../src/gui/dialogs/animateFilterDialog.cpp:174
 msgid "Voxel data"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:174
+#: ../src/gui/dialogs/animateFilterDialog.cpp:175
 msgid "Range files"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:175
+#: ../src/gui/dialogs/animateFilterDialog.cpp:176
 msgid "Format"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:672
+#: ../src/gui/dialogs/animateFilterDialog.cpp:677
 msgid "transition frame"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:672
-#: ../src/gui/mainFrame.cpp:1636
+#: ../src/gui/dialogs/animateFilterDialog.cpp:677
+#: ../src/gui/mainFrame.cpp:1674
 msgid "Frame count"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:744
+#: ../src/gui/dialogs/animateFilterDialog.cpp:749
 msgid "Key frame : Colour"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:797
+#: ../src/gui/dialogs/animateFilterDialog.cpp:802
 msgid "File existed, but was unable to read or interpret file contents."
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:798
+#: ../src/gui/dialogs/animateFilterDialog.cpp:803
 msgid "String load failed"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:819
+#: ../src/gui/dialogs/animateFilterDialog.cpp:824
 msgid "Keyframe : decimal"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:828
+#: ../src/gui/dialogs/animateFilterDialog.cpp:833
 msgid "Keyframe : integer"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:837
+#: ../src/gui/dialogs/animateFilterDialog.cpp:842
 msgid "Keyframe : 3D Point"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:962
+#: ../src/gui/dialogs/animateFilterDialog.cpp:967
 msgid "Select or create new folder"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1182
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1147
 msgid "Export Animation"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1183
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1148
 msgid "Select filter"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1185
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1190
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1210
-#: ../src/gui/mainFrame.cpp:5848 ../src/gui/mainFrame.cpp:5853
-msgid "Property"
-msgstr ""
-
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1187
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1149
 msgid "Select property"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1189
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1209
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1151
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1171
 msgid "Filter"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1191
-#: ../src/backend/filters/transform.cpp:1182
-#: ../src/backend/filters/annotation.cpp:547
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1152
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1172
+msgid "Property"
+msgstr ""
+
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1153
+#: ../src/backend/filters/voxelise.cpp:903
+#: ../src/backend/filters/spatialAnalysis.cpp:906
+#: ../src/backend/filters/transform.cpp:1133
+#: ../src/backend/filters/annotation.cpp:540
+#: ../src/backend/filters/annotation.cpp:546
+#: ../src/backend/filters/ionDownsample.cpp:463
 msgid "Mode"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1194
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1156
 msgid "Keyframe table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1195
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1157
 msgid "Remove the selected keyframe from the table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1196
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1158
 msgid "Enter where the animation frames will be exported to"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1197
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1159
 msgid "Browse to directory where the animation frames will be exported to"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1199
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1161
 msgid ""
 "Title for files, result will be saved as #-name.png, where # is image number."
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1200
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1162
 msgid "Target resolution (image size)"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1202
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1164
 msgid "Select frame for property display"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1203
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1165
 msgid "Enter frame number to change frame (eg 1/20)"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1204
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1166
 msgid "Save point data (POS files) in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1205
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1167
 msgid "Save plots (as text files) in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1206
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1168
 msgid "Save voxel data (raw files) in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1207
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1169
 msgid "Save range files  in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1212
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1174
 msgid "Animation parameters for current frame"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1213
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1175
 msgid "Abort animation"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1214
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1176
 msgid "Run Animation"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1285
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1247
 msgid "Filter view"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1286
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1248
 msgid "Frame view"
 msgstr ""
 
@@ -850,11 +835,11 @@ msgid "Height :"
 msgstr ""
 
 #: ../src/gui/dialogs/resolutionDialog.cpp:50
-#: ../src/gui/dialogs/prefDialog.cpp:83
+#: ../src/gui/dialogs/prefDialog.cpp:85
 msgid "Reset"
 msgstr ""
 
-#: ../src/gui/dialogs/resolutionDialog.cpp:350
+#: ../src/gui/dialogs/resolutionDialog.cpp:336
 msgid "Resolution Selection"
 msgstr ""
 
@@ -863,7 +848,7 @@ msgid "Export:"
 msgstr ""
 
 #: ../src/gui/dialogs/ExportPos.cpp:76
-#: ../src/backend/filters/boundingBox.cpp:520
+#: ../src/backend/filters/boundingBox.cpp:521
 msgid "Visible"
 msgstr ""
 
@@ -884,783 +869,787 @@ msgid "Index"
 msgstr ""
 
 #: ../src/gui/dialogs/ExportPos.cpp:111 ../src/gui/dialogs/ExportPos.cpp:114
-#: ../src/backend/filters/compositionProfile.cpp:549
-#: ../src/backend/filters/spatialAnalysis.cpp:1953
-#: ../src/backend/filters/spatialAnalysis.cpp:2022
-#: ../src/backend/filters/spatialAnalysis.cpp:3002
-#: ../src/backend/filters/spatialAnalysis.cpp:3221
-#: ../src/backend/filters/spatialAnalysis.cpp:3290
-#: ../src/backend/filters/spectrumPlot.cpp:240
+#: ../src/backend/filters/compositionProfile.cpp:581
+#: ../src/backend/filters/spatialAnalysis.cpp:2199
+#: ../src/backend/filters/spatialAnalysis.cpp:2259
+#: ../src/backend/filters/spatialAnalysis.cpp:3224
+#: ../src/backend/filters/spatialAnalysis.cpp:3436
+#: ../src/backend/filters/spatialAnalysis.cpp:3495
+#: ../src/backend/filters/spectrumPlot.cpp:237
 msgid "Count"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:450
+#: ../src/gui/dialogs/ExportPos.cpp:457
 msgid "Export Pos Data"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:453
+#: ../src/gui/dialogs/ExportPos.cpp:460
 msgid "Tree of filters, select leaves to show ion data."
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:455
+#: ../src/gui/dialogs/ExportPos.cpp:462
 msgid "Add all data from all filters"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:456
+#: ../src/gui/dialogs/ExportPos.cpp:463
 msgid "Add all data from currently selected filter"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:457
+#: ../src/gui/dialogs/ExportPos.cpp:464
 msgid "Add selected data from currently selected filter"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:72
+#: ../src/gui/dialogs/prefDialog.cpp:73
 msgid "Panel Display"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:74
+#: ../src/gui/dialogs/prefDialog.cpp:75
 msgid "Online Updates"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:76 ../src/gui/dialogs/prefDialog.cpp:654
+#: ../src/gui/dialogs/prefDialog.cpp:77 ../src/gui/dialogs/prefDialog.cpp:560
 msgid "Startup"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:77
-msgid "Camera Speed"
-msgstr ""
-
 #: ../src/gui/dialogs/prefDialog.cpp:78
-msgid "Filter Defaults"
+msgid "Camera Speed"
 msgstr ""
 
 #: ../src/gui/dialogs/prefDialog.cpp:79
 msgid "Available Filters"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:82
+#: ../src/gui/dialogs/prefDialog.cpp:84
 msgid "Reset All"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:85
+#: ../src/gui/dialogs/prefDialog.cpp:87
 msgid "Show all panels"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:86
+#: ../src/gui/dialogs/prefDialog.cpp:88
 msgid "Remember last"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:87
+#: ../src/gui/dialogs/prefDialog.cpp:89
 msgid "Show Selected"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:90
+#: ../src/gui/dialogs/prefDialog.cpp:92
 msgid "Control Pane"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:91
+#: ../src/gui/dialogs/prefDialog.cpp:93
 msgid "Raw Data Panel"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:92 ../src/gui/mainFrame.cpp:652
+#: ../src/gui/dialogs/prefDialog.cpp:94 ../src/gui/mainFrame.cpp:663
 msgid "Plot List"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:94
+#: ../src/gui/dialogs/prefDialog.cpp:96
 msgid "Periodically notify about available updates"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:96
+#: ../src/gui/dialogs/prefDialog.cpp:98
 msgid "Prefer orthographic at startup"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:97
+#: ../src/gui/dialogs/prefDialog.cpp:99
 msgid "Move Rate"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:98 ../src/gui/dialogs/prefDialog.cpp:102
+#: ../src/gui/dialogs/prefDialog.cpp:100 ../src/gui/dialogs/prefDialog.cpp:104
 msgid "(slow)"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:100 ../src/gui/dialogs/prefDialog.cpp:104
+#: ../src/gui/dialogs/prefDialog.cpp:102 ../src/gui/dialogs/prefDialog.cpp:106
 msgid "(fast)"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:101
+#: ../src/gui/dialogs/prefDialog.cpp:103
 msgid "Zoom Rate"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:456
-msgid "Notice"
-msgstr ""
-
-#: ../src/gui/dialogs/prefDialog.cpp:459
-msgid "For security reasons, defaults are not modifiable for this filter"
-msgstr ""
-
-#: ../src/gui/dialogs/prefDialog.cpp:496
+#: ../src/gui/dialogs/prefDialog.cpp:416
 msgid "Show all panels when starting program"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:499
+#: ../src/gui/dialogs/prefDialog.cpp:419
 msgid "Show panels visible at last shutdown when starting program"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:506
+#: ../src/gui/dialogs/prefDialog.cpp:426
 msgid "Show selected panels when starting program"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:555
+#: ../src/gui/dialogs/prefDialog.cpp:475
 msgid "Preferences"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:557
+#: ../src/gui/dialogs/prefDialog.cpp:477
 msgid "Set the method of panel layout when starting the program"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:560
+#: ../src/gui/dialogs/prefDialog.cpp:480
 msgid ""
 "Lets the program check the internet to see if updates to the program version "
 "are available, then notifies you about updates now and again."
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:562
+#: ../src/gui/dialogs/prefDialog.cpp:482
 msgid ""
 "By default, use an orthographic camera at startup. State files will override "
 "this preference."
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:563
+#: ../src/gui/dialogs/prefDialog.cpp:483
 msgid "Camera translation, orbit and swivel rates. "
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:564
+#: ../src/gui/dialogs/prefDialog.cpp:484
 msgid "Camera zooming rate."
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:566
+#: ../src/gui/dialogs/prefDialog.cpp:486
 msgid "Reset the filter initial values back to program defaults"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:567
+#: ../src/gui/dialogs/prefDialog.cpp:487
 msgid "Reset all filter initial values back to program defaults"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:653
-msgid "Pref"
+#: ../src/gui/dialogs/prefDialog.cpp:559
+msgid "Filt. Default"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:655
+#: ../src/gui/dialogs/prefDialog.cpp:561
 msgid "Camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:91
+#: ../src/gui/mainFrame.cpp:105
 msgid "New camera name..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:92
-msgid "New stash name...."
+#: ../src/gui/mainFrame.cpp:106
+msgid "New stash name..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/annotation.cpp:561
-#: ../src/backend/filters/annotation.cpp:663
+#: ../src/gui/mainFrame.cpp:111
+msgid "New Filter..."
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:128 ../src/backend/filters/annotation.cpp:555
+#: ../src/backend/filters/annotation.cpp:659
 #: ../src/backend/filters/annotation.h:96
 msgid "Annotation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:109
+#: ../src/gui/mainFrame.cpp:129
 msgid "Bounding Box"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:110 ../src/backend/filters/ionClip.h:66
+#: ../src/gui/mainFrame.cpp:130 ../src/backend/filters/ionClip.cpp:619
+#: ../src/backend/filters/ionClip.h:66
 msgid "Clipping"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:111 ../src/backend/filters/clusterAnalysis.h:140
+#: ../src/gui/mainFrame.cpp:131 ../src/backend/filters/clusterAnalysis.h:143
 msgid "Cluster Analysis"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:112
+#: ../src/gui/mainFrame.cpp:132
 msgid "Compos. Profiles"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:113
+#: ../src/gui/mainFrame.cpp:133
 msgid "Downsampling"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:114
+#: ../src/gui/mainFrame.cpp:134
 msgid "Extern. Prog."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:115
+#: ../src/gui/mainFrame.cpp:135
 msgid "Ion Colour"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:116
+#: ../src/gui/mainFrame.cpp:136
 msgid "Ion Info"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:117
+#: ../src/gui/mainFrame.cpp:137
 msgid "Ion Transform"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/spectrumPlot.h:53
+#: ../src/gui/mainFrame.cpp:138 ../src/backend/filters/spectrumPlot.h:53
 msgid "Spectrum"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:119
+#: ../src/gui/mainFrame.cpp:139
 msgid "Range File"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:120 ../src/backend/filters/spatialAnalysis.h:172
+#: ../src/gui/mainFrame.cpp:140 ../src/backend/filters/spatialAnalysis.h:193
 msgid "Spat. Analysis"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:121 ../src/backend/filters/voxelise.h:121
+#: ../src/gui/mainFrame.cpp:141 ../src/backend/filters/voxelise.h:121
 msgid "Voxelisation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:421
+#: ../src/gui/mainFrame.cpp:429
 msgid "OpenGL Failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:422 ../src/gui/mainFrame.cpp:424
+#: ../src/gui/mainFrame.cpp:430 ../src/gui/mainFrame.cpp:432
 msgid ""
 "Unable to initialise the openGL (3D) panel. Program cannot start. Please "
 "check your video drivers."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:444
+#: ../src/gui/mainFrame.cpp:452
 msgid "&Open...\tCtrl+O"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:444
+#: ../src/gui/mainFrame.cpp:452
 msgid "Open state file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:445
+#: ../src/gui/mainFrame.cpp:453
 msgid "&Merge...\tCtrl+Shift+O"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:445
+#: ../src/gui/mainFrame.cpp:453
 msgid "Merge other file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:449
+#: ../src/gui/mainFrame.cpp:457
 msgid "&Recent"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:458
 msgid "&Save\tCtrl+S"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:458
 msgid "Save state to file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:452
+#: ../src/gui/mainFrame.cpp:460
 msgid "Save &As...\tCtrl+Shift+S"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:452
+#: ../src/gui/mainFrame.cpp:460
 msgid "Save current state to new file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:455
+#: ../src/gui/mainFrame.cpp:463
 msgid "&Plot...\tCtrl+P"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:455
+#: ../src/gui/mainFrame.cpp:463
 msgid "Export Current Plot"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:464
 msgid "&Image...\tCtrl+I"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:464
 msgid "Export Current 3D View"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:457
+#: ../src/gui/mainFrame.cpp:465
 msgid "Ion&s...\tCtrl+N"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:457
+#: ../src/gui/mainFrame.cpp:465
 msgid "Export Ion Data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:458
+#: ../src/gui/mainFrame.cpp:466
 msgid "Ran&ges...\tCtrl+G"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:458
+#: ../src/gui/mainFrame.cpp:466
 msgid "Export Range Data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:459
+#: ../src/gui/mainFrame.cpp:467
 msgid "&Animate Filters...\tCtrl+A"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:459
+#: ../src/gui/mainFrame.cpp:467
 msgid "Export Animated Filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:460
+#: ../src/gui/mainFrame.cpp:468
 msgid "Ani&mate Camera...\tCtrl+M"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:460
+#: ../src/gui/mainFrame.cpp:468
 msgid "Export Animated Camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:461
+#: ../src/gui/mainFrame.cpp:469
 msgid "Pac&kage...\tCtrl+K"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:461
+#: ../src/gui/mainFrame.cpp:469
 msgid "Export analysis package"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:463
+#: ../src/gui/mainFrame.cpp:471
 msgid "&Export"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:466
+#: ../src/gui/mainFrame.cpp:474
 msgid "&Quit\tCtrl+Q"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:466 ../src/gui/mainFrame.cpp:468
+#: ../src/gui/mainFrame.cpp:474 ../src/gui/mainFrame.cpp:476
 msgid "Exit Program"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:468
+#: ../src/gui/mainFrame.cpp:476
 msgid "E&xit"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:470
+#: ../src/gui/mainFrame.cpp:478
 msgid "&File"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:474
+#: ../src/gui/mainFrame.cpp:482
 msgid "&Background Colour...\tCtrl+B"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:474
+#: ../src/gui/mainFrame.cpp:482
 msgid "Change background colour"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:478
+#: ../src/gui/mainFrame.cpp:486
 msgid "&Control Pane\tF2"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:478 ../src/gui/mainFrame.cpp:481
+#: ../src/gui/mainFrame.cpp:486 ../src/gui/mainFrame.cpp:489
 msgid "Toggle left control pane"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:481
+#: ../src/gui/mainFrame.cpp:489
 msgid "&Control Pane\tAlt+C"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:487
+#: ../src/gui/mainFrame.cpp:495
 msgid "&Raw Data Pane\tF3"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:487 ../src/gui/mainFrame.cpp:490
+#: ../src/gui/mainFrame.cpp:495 ../src/gui/mainFrame.cpp:498
 msgid "Toggle raw data  pane (bottom)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:490
+#: ../src/gui/mainFrame.cpp:498
 msgid "&Raw Data Pane\tAlt+R"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:494
+#: ../src/gui/mainFrame.cpp:502
 msgid "&Plot List\tF4"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:494 ../src/gui/mainFrame.cpp:496
+#: ../src/gui/mainFrame.cpp:502 ../src/gui/mainFrame.cpp:504
 msgid "Toggle plot list"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:496
+#: ../src/gui/mainFrame.cpp:504
 msgid "&Plot List\tAlt+P"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:502
+#: ../src/gui/mainFrame.cpp:510
 msgid "&Legend\tCtrl+L"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:502
+#: ../src/gui/mainFrame.cpp:510
 msgid "Toggle Legend display"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:504
+#: ../src/gui/mainFrame.cpp:512
 msgid "P&lot..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:505
+#: ../src/gui/mainFrame.cpp:513
 msgid "&Axis\tCtrl+Shift+I"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:505
+#: ../src/gui/mainFrame.cpp:513
 msgid "Toggle World Axis display"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:510
+#: ../src/gui/mainFrame.cpp:518
 msgid "&Fullscreen mode\tF11"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:510 ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:518 ../src/gui/mainFrame.cpp:520
 msgid "Next fullscreen mode: with toolbars"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:520
 msgid "&Fullscreen mode\tCtrl+Shift+F"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:517
+#: ../src/gui/mainFrame.cpp:525
 msgid "&Undo\tCtrl+Z"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:519
+#: ../src/gui/mainFrame.cpp:527
 msgid "&Redo\tCtrl+Y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:522
+#: ../src/gui/mainFrame.cpp:530
 msgid "&Range"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:525
+#: ../src/gui/mainFrame.cpp:533
 msgid "&Preferences"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:527
+#: ../src/gui/mainFrame.cpp:535
 msgid "&Edit"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:530
+#: ../src/gui/mainFrame.cpp:538
 msgid "&View"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:532
+#: ../src/gui/mainFrame.cpp:540
 msgid "&Help...\tCtrl+H"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:532
+#: ../src/gui/mainFrame.cpp:540
 msgid "Show help files and documentation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:533
+#: ../src/gui/mainFrame.cpp:541
 msgid "&Contact..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:533
+#: ../src/gui/mainFrame.cpp:541
 msgid "Open contact page"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:535
+#: ../src/gui/mainFrame.cpp:543
 msgid "&About..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:535
+#: ../src/gui/mainFrame.cpp:543
 msgid "Information about this program"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:536
+#: ../src/gui/mainFrame.cpp:544
 msgid "&Help"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:538
+#: ../src/gui/mainFrame.cpp:546
 msgid "Stashed Filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:543
+#: ../src/gui/mainFrame.cpp:551
 msgid "New Filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:571
+#: ../src/gui/mainFrame.cpp:580
 msgid "Last Outputs"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:573
+#: ../src/gui/mainFrame.cpp:582
 msgid "Auto Refresh"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:579
+#: ../src/gui/mainFrame.cpp:588
 msgid "Filter settings"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:581
+#: ../src/gui/mainFrame.cpp:591
 msgid "Camera Name"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:587
+#: ../src/gui/mainFrame.cpp:598
 msgid "3D Post-processing"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:589
+#: ../src/gui/mainFrame.cpp:600
 msgid "Enable Cropping"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:591 ../src/gui/mainFrame.cpp:602
+#: ../src/gui/mainFrame.cpp:602 ../src/gui/mainFrame.cpp:613
 msgid "x-y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:592 ../src/gui/mainFrame.cpp:603
+#: ../src/gui/mainFrame.cpp:603 ../src/gui/mainFrame.cpp:614
 msgid "x-z"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:593 ../src/gui/mainFrame.cpp:604
+#: ../src/gui/mainFrame.cpp:604 ../src/gui/mainFrame.cpp:615
 msgid "y-x"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:594 ../src/gui/mainFrame.cpp:605
+#: ../src/gui/mainFrame.cpp:605 ../src/gui/mainFrame.cpp:616
 msgid "y-z"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:595 ../src/gui/mainFrame.cpp:606
+#: ../src/gui/mainFrame.cpp:606 ../src/gui/mainFrame.cpp:617
 msgid "z-x"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:596 ../src/gui/mainFrame.cpp:607
+#: ../src/gui/mainFrame.cpp:607 ../src/gui/mainFrame.cpp:618
 msgid "z-y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:611
+#: ../src/gui/mainFrame.cpp:622
 msgid "Use camera coordinates"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:612
+#: ../src/gui/mainFrame.cpp:623
 msgid "dX"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:614
+#: ../src/gui/mainFrame.cpp:625
 msgid "dY"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:616
+#: ../src/gui/mainFrame.cpp:627
 msgid "dZ"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:618
+#: ../src/gui/mainFrame.cpp:629
 msgid "Enable Anaglyphic Stereo"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:619
+#: ../src/gui/mainFrame.cpp:630
 msgid "Flip Channels"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:620
+#: ../src/gui/mainFrame.cpp:631
 msgid "Anaglyph Mode"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:622
+#: ../src/gui/mainFrame.cpp:633
 msgid "Red-Blue"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:623
+#: ../src/gui/mainFrame.cpp:634
 msgid "Red-Green"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:624
+#: ../src/gui/mainFrame.cpp:635
 msgid "Red-Cyan"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:625
+#: ../src/gui/mainFrame.cpp:636
 msgid "Green-Magenta"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:629
+#: ../src/gui/mainFrame.cpp:640
 msgid "Baseline Separation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:631 ../src/backend/filters/voxelise.cpp:981
-#: ../src/backend/filters/voxelise.cpp:1037
-#: ../src/backend/filters/compositionProfile.cpp:1165
+#: ../src/gui/mainFrame.cpp:642 ../src/backend/filters/voxelise.cpp:982
+#: ../src/backend/filters/voxelise.cpp:1142
+#: ../src/backend/filters/compositionProfile.cpp:1109
 #: ../src/backend/filters/boundingBox.cpp:648
-#: ../src/backend/filters/dataLoad.cpp:660
+#: ../src/backend/filters/annotation.cpp:901
+#: ../src/backend/filters/dataLoad.cpp:651
+#: ../src/backend/filters/spectrumPlot.cpp:459
 msgid "Appearance"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:632
+#: ../src/gui/mainFrame.cpp:643
 msgid "Smooth && translucent objects"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:634
+#: ../src/gui/mainFrame.cpp:645
 msgid "3D lighting"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:637
+#: ../src/gui/mainFrame.cpp:648
 msgid "Performance"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:638
+#: ../src/gui/mainFrame.cpp:649
 msgid "Fast and weak randomisation."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:640
+#: ../src/gui/mainFrame.cpp:651
 msgid "Limit Output Pts"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:646
+#: ../src/gui/mainFrame.cpp:657
 msgid "Filter caching"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:648
+#: ../src/gui/mainFrame.cpp:659
 msgid "Max. Ram usage (%)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:705
+#: ../src/gui/mainFrame.cpp:718
 msgid "Type"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:706
+#: ../src/gui/mainFrame.cpp:719
 msgid "Num"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:721
+#: ../src/gui/mainFrame.cpp:734
 msgid "Warning: Your configuration file appears to be invalid:\n"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:722
+#: ../src/gui/mainFrame.cpp:735
 msgid "\tConfig Load: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:974
+#: ../src/gui/mainFrame.cpp:984
 msgid "Current state has not been saved, would you like to save it now?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:975
+#: ../src/gui/mainFrame.cpp:985
 msgid "State changed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:995
+#: ../src/gui/mainFrame.cpp:1005
 msgid "Readable files (*.xml, *.pos, *.txt,*.csv, *.ato)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:997
+#: ../src/gui/mainFrame.cpp:1007
 msgid "XML State File (*.xml)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:998
+#: ../src/gui/mainFrame.cpp:1008
 msgid "POS File (*.pos)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:999
+#: ../src/gui/mainFrame.cpp:1009
 msgid "LAWATAP ATO File (*.ato)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1000
+#: ../src/gui/mainFrame.cpp:1010
 msgid "Text File (*.txt, *.csv)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1001
+#: ../src/gui/mainFrame.cpp:1011
 msgid "All Files (*)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1014 ../src/gui/mainFrame.cpp:1068
+#: ../src/gui/mainFrame.cpp:1024 ../src/gui/mainFrame.cpp:1080
 msgid "Select Data or State File..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1056 ../src/gui/mainFrame.cpp:1387
+#: ../src/gui/mainFrame.cpp:1068 ../src/gui/mainFrame.cpp:1407
 msgid "Loaded file."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1069
+#: ../src/gui/mainFrame.cpp:1081
 msgid ""
 "3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|"
 "XML State File (*.xml)|*.xml|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1080
+#: ../src/gui/mainFrame.cpp:1092
 msgid "Merged file."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1182
+#: ../src/gui/mainFrame.cpp:1199
 msgid "Tip: You can use ⌘ (command) to merge"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1184
+#: ../src/gui/mainFrame.cpp:1201
 msgid "Tip: You can use ctrl to merge"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1221
+#: ../src/gui/mainFrame.cpp:1241
 msgid "Load error"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1222
+#: ../src/gui/mainFrame.cpp:1242
 msgid ""
 "Error loading state file.\n"
 "See console for more info."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1230
+#: ../src/gui/mainFrame.cpp:1250
 msgid ""
 "This state file contains filters that can be unsafe to run\n"
 "Do you wish to remove these before continuing?."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1231
+#: ../src/gui/mainFrame.cpp:1251
 msgid "Security warning"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1444 ../src/gui/mainFrame.cpp:1540
-#: ../src/gui/mainFrame.cpp:1957
+#: ../src/gui/mainFrame.cpp:1468 ../src/gui/mainFrame.cpp:1564
+#: ../src/gui/mainFrame.cpp:1997
 msgid "Unable to save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1445
+#: ../src/gui/mainFrame.cpp:1469
 msgid "No plot available. Please create a plot before exporting."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1449
+#: ../src/gui/mainFrame.cpp:1473
 msgid "Save plot..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1450
+#: ../src/gui/mainFrame.cpp:1474
 msgid ""
 "By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*."
 "svg|PNG File (*.png)|*.png|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1504
+#: ../src/gui/mainFrame.cpp:1528
 msgid "Select type for save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1505
+#: ../src/gui/mainFrame.cpp:1529
 msgid "Choose file type"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1525 ../src/gui/mainFrame.cpp:1568
-#: ../src/gui/mainFrame.cpp:1604
+#: ../src/gui/mainFrame.cpp:1549 ../src/gui/mainFrame.cpp:1606
+#: ../src/gui/mainFrame.cpp:1642
 msgid "Choose resolution"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1541
+#: ../src/gui/mainFrame.cpp:1565
 msgid "Unknown file extension. Please use \"svg\" or \"png\""
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1552
+#: ../src/gui/mainFrame.cpp:1576
 msgid "Saved plot: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1559 ../src/gui/mainFrame.cpp:1597
+#: ../src/gui/mainFrame.cpp:1583 ../src/gui/mainFrame.cpp:1635
 msgid "Save Image..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1560 ../src/gui/mainFrame.cpp:1598
+#: ../src/gui/mainFrame.cpp:1584 ../src/gui/mainFrame.cpp:1636
 msgid "PNG File (*.png)|*.png|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1588 ../src/gui/mainFrame.cpp:1664
+#: ../src/gui/mainFrame.cpp:1598
+msgid "File already exists. Overwrite?"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:1599 ../src/gui/mainFrame.cpp:2385
+#: ../src/gui/mainFrame.cpp:2483 ../src/gui/mainFrame.cpp:2507
+msgid "Overwrite?"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:1626 ../src/gui/mainFrame.cpp:1702
 msgid "Saved 3D View :"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1618
+#: ../src/gui/mainFrame.cpp:1656
 msgid "Program limitation"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1619
+#: ../src/gui/mainFrame.cpp:1657
 msgid ""
 "Limitation on the screenshot dimension; please ensure that both width and "
 "height exceed the initial values,\n"
@@ -1668,402 +1657,371 @@ msgid ""
 " If this bothers, please submit a bug."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1636
+#: ../src/gui/mainFrame.cpp:1674
 msgid "Number of frames"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1791
+#: ../src/gui/mainFrame.cpp:1829
 msgid "Cannot animate with no filters."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1868
+#: ../src/gui/mainFrame.cpp:1908
 msgid "Animating"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1869
+#: ../src/gui/mainFrame.cpp:1909
 msgid "Performing refresh"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1898
+#: ../src/gui/mainFrame.cpp:1938
 msgid "Filter property change failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1918
+#: ../src/gui/mainFrame.cpp:1958
 msgid "Refresh failed on frame :"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1943
+#: ../src/gui/mainFrame.cpp:1983
 msgid "Scene generation failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1944
+#: ../src/gui/mainFrame.cpp:1984
 msgid "Unable to generate scene for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1958
+#: ../src/gui/mainFrame.cpp:1998
 msgid "Image save failed for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1983
+#: ../src/gui/mainFrame.cpp:2023
 msgid "Ion save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1984
+#: ../src/gui/mainFrame.cpp:2024
 msgid "Unable to save ions for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2015
+#: ../src/gui/mainFrame.cpp:2055
 msgid "Plot save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2016
+#: ../src/gui/mainFrame.cpp:2056
 msgid "Unable to save plot or frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2057
+#: ../src/gui/mainFrame.cpp:2097
 msgid "Range save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2058
+#: ../src/gui/mainFrame.cpp:2098
 msgid "Unable to save range for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2087
+#: ../src/gui/mainFrame.cpp:2127
 msgid "Voxel save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2088
+#: ../src/gui/mainFrame.cpp:2128
 msgid "Unable to save voxels for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2118
+#: ../src/gui/mainFrame.cpp:2158
 msgid "Animate failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2143 ../src/gui/mainFrame.cpp:2301
-#: ../src/gui/mainFrame.cpp:2397
+#: ../src/gui/mainFrame.cpp:2183 ../src/gui/mainFrame.cpp:2341
+#: ../src/gui/mainFrame.cpp:2437
 msgid "No filters means no data to export"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2157
+#: ../src/gui/mainFrame.cpp:2197
 msgid "Package name"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2158
+#: ../src/gui/mainFrame.cpp:2198
 msgid "Package directory name"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2160
+#: ../src/gui/mainFrame.cpp:2200
 msgid "AnalysisPackage"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2173
+#: ../src/gui/mainFrame.cpp:2213
 msgid "Package folder already exists, won't overwrite."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2174
+#: ../src/gui/mainFrame.cpp:2214
 msgid "Not available"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2199
+#: ../src/gui/mainFrame.cpp:2239
 msgid ""
 "Package folder creation failed\n"
 "check writing to this location is possible."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2200
+#: ../src/gui/mainFrame.cpp:2240
 msgid "Folder creation failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2219
+#: ../src/gui/mainFrame.cpp:2259
 msgid "Copying"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2220
+#: ../src/gui/mainFrame.cpp:2260
 msgid "Copying referenced files"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2279
+#: ../src/gui/mainFrame.cpp:2319
 msgid "Error copying file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2288
+#: ../src/gui/mainFrame.cpp:2328
 msgid "Saved package: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2311
+#: ../src/gui/mainFrame.cpp:2351
 msgid "Export"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2316
+#: ../src/gui/mainFrame.cpp:2356
 msgid "POS Data (*.pos)|*.pos|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2344 ../src/gui/mainFrame.cpp:2442
+#: ../src/gui/mainFrame.cpp:2384 ../src/gui/mainFrame.cpp:2482
 msgid "File already exists, overwrite?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2345 ../src/gui/mainFrame.cpp:2443
-#: ../src/gui/mainFrame.cpp:2467
-msgid "Overwrite?"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:2376
+#: ../src/gui/mainFrame.cpp:2416
 msgid "Saved ions: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2401
+#: ../src/gui/mainFrame.cpp:2441
 msgid "Export Ranges"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2424
+#: ../src/gui/mainFrame.cpp:2464
 msgid "Save state..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2425
+#: ../src/gui/mainFrame.cpp:2465
 msgid "XML state file (*.xml)|*.xml|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2466
+#: ../src/gui/mainFrame.cpp:2506
 msgid "Files have been referred to using relative paths. Keep relative paths?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2499
+#: ../src/gui/mainFrame.cpp:2539
 msgid "Saved state: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2576
+#: ../src/gui/mainFrame.cpp:2616
 msgid "Range editor"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2872
+#: ../src/gui/mainFrame.cpp:2871
 msgid "Manual not found locally. Launching web browser"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2881
+#: ../src/gui/mainFrame.cpp:2880
 msgid "Opening contact page in external web browser"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2893
+#: ../src/gui/mainFrame.cpp:2892
 msgid "No filter stashes to edit."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2897
+#: ../src/gui/mainFrame.cpp:2896
 msgid "Filter Stashes"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2926
+#: ../src/gui/mainFrame.cpp:2925
 msgid "Quick and dirty analysis for point data."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2936
+#: ../src/gui/mainFrame.cpp:2935
 msgid "Compiled with wx Version: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2957
+#: ../src/gui/mainFrame.cpp:2956
 msgid "Press enter to store new stash"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2963
+#: ../src/gui/mainFrame.cpp:2962
 msgid "Press enter to restore stash"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2998
+#: ../src/gui/mainFrame.cpp:2997
 msgid "Unable to create stash, selection invalid"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3006
+#: ../src/gui/mainFrame.cpp:3005
 msgid "Created new filter tree stash"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3128
+#: ../src/gui/mainFrame.cpp:3132
 msgid "Filter type not a data source - can't be at tree base"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3302
+#: ../src/gui/mainFrame.cpp:3309
 msgid "Moving - Hold ⌘ (command) to copy"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3304
+#: ../src/gui/mainFrame.cpp:3311
 msgid "Moving - Hold control to copy"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3647
+#: ../src/gui/mainFrame.cpp:3630
 msgid "Press enter to store new camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3649
+#: ../src/gui/mainFrame.cpp:3632
 msgid "Press enter to restore camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3674 ../src/gui/mainFrame.cpp:3715
+#: ../src/gui/mainFrame.cpp:3657 ../src/gui/mainFrame.cpp:3698
 msgid "Restored camera: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3694
+#: ../src/gui/mainFrame.cpp:3677
 msgid "Stored camera: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3775
+#: ../src/gui/mainFrame.cpp:3759
 msgid "Select an item from the filter tree before choosing a new filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3777
+#: ../src/gui/mainFrame.cpp:3761
 msgid "Load data source (file->open) before choosing a new filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3798
+#: ../src/gui/mainFrame.cpp:3785
 msgid "Select RNG File..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3799
-msgid ""
-"Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
-"Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:3819
+#: ../src/gui/mainFrame.cpp:3806
 msgid "Failed reading range file."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3823
+#: ../src/gui/mainFrame.cpp:3810
 msgid "Error loading file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3881 ../src/gui/mainFrame.cpp:3947
-#: ../src/gui/mainFrame.cpp:5508 ../src/gui/mainFrame.cpp:6063
+#: ../src/gui/mainFrame.cpp:3870 ../src/gui/mainFrame.cpp:3937
+#: ../src/gui/mainFrame.cpp:5268 ../src/gui/mainFrame.cpp:5802
 msgid "Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3914
+#: ../src/gui/mainFrame.cpp:3904
 msgid "Refresh Aborted."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3951
+#: ../src/gui/mainFrame.cpp:3941
 msgid "*Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3953
+#: ../src/gui/mainFrame.cpp:3943
 msgid "§Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4076
+#: ../src/gui/mainFrame.cpp:4037
+msgid "msgs"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:4077
 msgid "Autosave complete."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4243
+#: ../src/gui/mainFrame.cpp:4273
 msgid "Aborted."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4294
+#: ../src/gui/mainFrame.cpp:4324
 msgid "Updated."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4301
+#: ../src/gui/mainFrame.cpp:4331
 msgid "\\% Done (Esc aborts)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4303
+#: ../src/gui/mainFrame.cpp:4333
 msgid "\\% Done"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4562 ../src/gui/mainFrame.cpp:4569
-msgid "Next Fullscreen mode: none"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:4565
-msgid "Next Fullscreen mode: complete"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:4573
-msgid "Next Fullscreen mode: with toolbars"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:4589
-msgid "Next Mode: No fullscreen"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:4593
-msgid "Next Mode: fullscreen w/o toolbar"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:4597
-msgid "Next Mode: fullscreen with toolbar"
-msgstr ""
-
-#: ../src/gui/mainFrame.cpp:4638
+#: ../src/gui/mainFrame.cpp:4609
 msgid "Tip: You can shift-click to force full refresh, if required"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:4910
+#: ../src/gui/mainFrame.cpp:4672
 msgid "No data to save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5082
+#: ../src/gui/mainFrame.cpp:4842
 msgid "Aborting..."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5088
+#: ../src/gui/mainFrame.cpp:4848
 msgid ""
 "Waiting for refresh to abort. Exiting could lead to the program "
 "backgrounding. Exit anyway? "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5089 ../src/gui/mainFrame.cpp:5109
+#: ../src/gui/mainFrame.cpp:4849 ../src/gui/mainFrame.cpp:4869
 msgid "Confirmation request"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5108
+#: ../src/gui/mainFrame.cpp:4868
 msgid "Are you sure you wish to exit 3Depict?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5536
+#: ../src/gui/mainFrame.cpp:5296
 msgid "Update Notice: New version "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5536
+#: ../src/gui/mainFrame.cpp:5296
 msgid " found online."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5540
+#: ../src/gui/mainFrame.cpp:5300
 msgid "Online Check: "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5540
+#: ../src/gui/mainFrame.cpp:5300
 msgid " is up-to-date."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5630
+#: ../src/gui/mainFrame.cpp:5395
 msgid "An auto-save state was found, would you like to restore it?."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5631
+#: ../src/gui/mainFrame.cpp:5396
 msgid "Autosave"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5638
+#: ../src/gui/mainFrame.cpp:5403
 msgid "Unable to load autosave file.."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5830
+#: ../src/gui/mainFrame.cpp:5600
 msgid "List of available filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5832
+#: ../src/gui/mainFrame.cpp:5602
 msgid "Tree - drag to move items, hold ⌘ for copy. Tap delete to remove items"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5834
+#: ../src/gui/mainFrame.cpp:5604
 msgid ""
 "Tree - drag to move items, hold Ctrl for copy. Tap delete to remove items."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5836
+#: ../src/gui/mainFrame.cpp:5606
 msgid ""
 "Enable/Disable automatic updates of data when filter change takes effect"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5839
+#: ../src/gui/mainFrame.cpp:5609
 msgid ""
 "Enable/Disable \"Alpha blending\" (transparency) in rendering system. "
 "Blending is used to smooth objects (avoids artefacts known as \"jaggies\") "
@@ -2071,14 +2029,14 @@ msgid ""
 "but look more blocky"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5840
+#: ../src/gui/mainFrame.cpp:5610
 msgid ""
 "Enable/Disable lighting calculations in rendering, for objects that request "
 "this. Lighting provides important depth cues for objects comprised of 3D "
 "surfaces. Disabling may allow faster rendering in complex scenes"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5841
+#: ../src/gui/mainFrame.cpp:5611
 msgid ""
 "Enable/Disable weak randomisation (Galois linear feedback shift register). "
 "Strong randomisation uses a much slower random selection method, but "
@@ -2086,14 +2044,14 @@ msgid ""
 "recommended for final analyses"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5843
+#: ../src/gui/mainFrame.cpp:5613
 msgid ""
 "Limit the number of points that can be displayed in the 3D  scene. Does not "
 "affect filter tree calculations. Disabling this can severely reduce "
 "performance, due to large numbers of points being visible at once."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5844
+#: ../src/gui/mainFrame.cpp:5614
 msgid ""
 "Enable/Disable caching of intermediate results during filter updates. "
 "Disabling caching will use less system RAM, though changes to any filter "
@@ -2101,156 +2059,145 @@ msgid ""
 "computations"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5855
+#: ../src/gui/mainFrame.cpp:5616
 msgid "Camera data information"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5859
+#: ../src/gui/mainFrame.cpp:5620
 msgid "Enable/disable visual effects on final 3D output"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5861
+#: ../src/gui/mainFrame.cpp:5622
 msgid "Enable cropping post-process effect"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5864
+#: ../src/gui/mainFrame.cpp:5625
 msgid ""
 "Colour based 3D effect enable/disable - requires appropriate colour filter "
 "3D glasses."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5865
+#: ../src/gui/mainFrame.cpp:5626
 msgid "Glasses colour mode"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5867
+#: ../src/gui/mainFrame.cpp:5628
 msgid ""
 "Level of separation between left and right images, which sets 3D depth to "
 "visual distortion tradeoff"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5871
+#: ../src/gui/mainFrame.cpp:5632
 msgid "X"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5872
+#: ../src/gui/mainFrame.cpp:5633
 msgid "Y"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5873
+#: ../src/gui/mainFrame.cpp:5634
 msgid "Save raw data to file"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5874
+#: ../src/gui/mainFrame.cpp:5635
 msgid "Copy raw data to clipboard"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5875
+#: ../src/gui/mainFrame.cpp:5636
 msgid "Manage \"stashed\" data."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5876
+#: ../src/gui/mainFrame.cpp:5637
 msgid "Program text output"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5877
+#: ../src/gui/mainFrame.cpp:5638
 msgid "Select active camera, or type to create new named camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5878
+#: ../src/gui/mainFrame.cpp:5639
 msgid "Remove the selected camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5879
+#: ../src/gui/mainFrame.cpp:5640
 msgid "Perform cropping from coordinate frame of camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5880
+#: ../src/gui/mainFrame.cpp:5641
 msgid ""
 "Set the maximum amount of RAM to use in order to speed repeat computations"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5881
+#: ../src/gui/mainFrame.cpp:5642
 msgid "Collapse the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5882
+#: ../src/gui/mainFrame.cpp:5643
 msgid "Expand the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5883
+#: ../src/gui/mainFrame.cpp:5644
 msgid "Process the filter tree, hold shift to purge cached filter data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6023
+#: ../src/gui/mainFrame.cpp:5762
 msgid "Crop"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6024
+#: ../src/gui/mainFrame.cpp:5763
 msgid "Stereo"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6041
+#: ../src/gui/mainFrame.cpp:5780
+#: ../src/backend/filters/externalProgram.cpp:577
+#: ../src/backend/filters/ionColour.cpp:312
+#: ../src/backend/filters/spectrumPlot.cpp:418
 msgid "Data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6042
+#: ../src/gui/mainFrame.cpp:5781
 msgid "Cam"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6043
+#: ../src/gui/mainFrame.cpp:5782
 msgid "Post"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6044
+#: ../src/gui/mainFrame.cpp:5783
 msgid "Tools"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6062
+#: ../src/gui/mainFrame.cpp:5801
 msgid "Raw"
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:230
+#: ../src/gui/mathglPane.cpp:241
 msgid "No plots selected."
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1202
+#: ../src/gui/mathglPane.cpp:1165
 msgid ""
 "Unable to allocate requested memory.\n"
 " Try a lower resolution, or save as vector (SVG)."
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1204
+#: ../src/gui/mathglPane.cpp:1167
 msgid "Plotting functions returned an error:\n"
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1206
+#: ../src/gui/mathglPane.cpp:1169
 msgid "File readback check failed"
 msgstr ""
 
-#: ../src/gui/mathglPane.cpp:1208
+#: ../src/gui/mathglPane.cpp:1171
 msgid "Filesize during readback appears to be zero."
 msgstr ""
 
-#: ../src/3Depict.cpp:78
-msgid "displays this message"
-msgstr ""
-
-#: ../src/3Depict.cpp:80
-msgid "inputfile"
-msgstr ""
-
-#: ../src/3Depict.cpp:89
-msgid ""
-"Run debug unit tests, returns nonzero on test failure, zero on success.\n"
-"\t\tXML files may be passed to run, instead of default tests"
-msgstr ""
-
-#: ../src/3Depict.cpp:383
+#: ../src/3Depict.cpp:381
 msgid "File : "
 msgstr ""
 
-#: ../src/3Depict.cpp:383
+#: ../src/3Depict.cpp:381
 msgid " does not exist. Skipping"
 msgstr ""
 
@@ -2266,1497 +2213,1472 @@ msgstr ""
 msgid "Unable to determine filter type in defaults listing."
 msgstr ""
 
-#: ../src/backend/configFile.cpp:610
+#: ../src/backend/configFile.cpp:604
 msgid "Online access for non win32/apple platforms is intentionally disabled, "
 msgstr ""
 
-#: ../src/backend/configFile.cpp:611
+#: ../src/backend/configFile.cpp:605
 msgid ""
 "regardless of the settings you use here. Use your package manager to keep up-"
 "to-date"
 msgstr ""
 
-#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:122
-#: ../src/backend/filters/voxelise.cpp:132
+#: ../src/backend/plot.cpp:28 ../src/backend/filters/voxelise.cpp:123
+#: ../src/backend/filters/voxelise.cpp:133
 msgid "None"
 msgstr ""
 
-#: ../src/backend/plot.cpp:31
+#: ../src/backend/plot.cpp:29
 msgid "Moving avg."
 msgstr ""
 
-#: ../src/backend/plot.cpp:35
+#: ../src/backend/plot.cpp:33
 msgid "Lines"
 msgstr ""
 
-#: ../src/backend/plot.cpp:36
+#: ../src/backend/plot.cpp:34
 msgid "Bars"
 msgstr ""
 
-#: ../src/backend/plot.cpp:37
+#: ../src/backend/plot.cpp:35
 msgid "Steps"
 msgstr ""
 
-#: ../src/backend/plot.cpp:38
+#: ../src/backend/plot.cpp:36
 msgid "Stem"
 msgstr ""
 
-#: ../src/backend/plot.cpp:39
+#: ../src/backend/plot.cpp:37
 msgid "Points"
 msgstr ""
 
-#: ../src/backend/plot.cpp:841 ../src/backend/plot.cpp:849
+#: ../src/backend/plot.cpp:39
+msgid "Density"
+msgstr ""
+
+#: ../src/backend/plot.cpp:40
+msgid "Scatter"
+msgstr ""
+
+#: ../src/backend/plot.cpp:787 ../src/backend/plot.cpp:795
 msgid "Multiple data types"
 msgstr ""
 
-#: ../src/backend/plot.cpp:1550
+#: ../src/backend/plot.cpp:1559
 msgid "error"
 msgstr ""
 
-#: ../src/backend/filtertree.cpp:1051
+#: ../src/backend/plot.cpp:1772
+msgid "Amplitude"
+msgstr ""
+
+#: ../src/backend/filtertree.cpp:1060
 msgid "WARNING: Skipping node "
 msgstr ""
 
-#: ../src/backend/filtertree.cpp:1051
+#: ../src/backend/filtertree.cpp:1060
 msgid " as it was not recognised"
 msgstr ""
 
-#: ../src/backend/filtertree.cpp:1089
+#: ../src/backend/filtertree.cpp:1098
 msgid "Error processing node: "
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:543
+#: ../src/backend/filters/externalProgram.cpp:545
+#: ../src/backend/filters/externalProgram.cpp:559
 msgid "Command"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:546
+#: ../src/backend/filters/externalProgram.cpp:548
 msgid ""
 "Full command to send to operating system. See manual for escape sequence "
 "meanings"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:550
+#: ../src/backend/filters/externalProgram.cpp:552
 msgid "Work Dir"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:553
+#: ../src/backend/filters/externalProgram.cpp:555
 msgid "Directory to run the command in"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:563
+#: ../src/backend/filters/externalProgram.cpp:562
 msgid "Cleanup input"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:566
+#: ../src/backend/filters/externalProgram.cpp:565
 msgid "Erase input files when command completed"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:575
+#: ../src/backend/filters/externalProgram.cpp:570
 msgid "Cache"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:578
+#: ../src/backend/filters/externalProgram.cpp:573
 msgid ""
 "Assume program does not alter its output, unless inputs from 3Depict are "
 "altered"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:660
-msgid "Error processing command line"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:662
-msgid "Unable to set working directory"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:664
-msgid "Error saving posfile result for external program"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:666
-msgid "Error saving plot result for externalprogram"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:668
-msgid "Error creating temporary directory"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:670
-msgid "Detected unusable number of columns in plot"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:672
-msgid "Unable to parse plot result from external program"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:674
-msgid "Unable to load ions from external program"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:676
-msgid "Unable to perform commandline substitution"
-msgstr ""
-
-#: ../src/backend/filters/externalProgram.cpp:678
-msgid "Error executing external program"
-msgstr ""
-
-#: ../src/backend/filters/ionClip.cpp:59
-#: ../src/backend/filters/compositionProfile.cpp:43
+#: ../src/backend/filters/ionClip.cpp:60
+#: ../src/backend/filters/compositionProfile.cpp:44
 msgid "Sphere"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:60
+#: ../src/backend/filters/ionClip.cpp:61
 msgid "Plane"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:61
-#: ../src/backend/filters/compositionProfile.cpp:42
+#: ../src/backend/filters/ionClip.cpp:62
+#: ../src/backend/filters/compositionProfile.cpp:43
 msgid "Cylinder"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:62
+#: ../src/backend/filters/ionClip.cpp:63
 msgid "Aligned box"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:495
+#: ../src/backend/filters/ionClip.cpp:488
+#: ../src/backend/filters/compositionProfile.cpp:943
 msgid "Primitive"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:498
+#: ../src/backend/filters/ionClip.cpp:491
 msgid "Shape of clipping object"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:504
-#: ../src/backend/filters/compositionProfile.cpp:1000
+#: ../src/backend/filters/ionClip.cpp:497
+#: ../src/backend/filters/compositionProfile.cpp:949
 msgid "Show Primitive"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:507
+#: ../src/backend/filters/ionClip.cpp:500
 msgid "Display the 3D interaction object"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:512
+#: ../src/backend/filters/ionClip.cpp:505
 msgid "Invert Clip"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:515
+#: ../src/backend/filters/ionClip.cpp:508
 msgid ""
 "Switch between retaining points inside (false) and outside (true) of "
 "primitive"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:529
-#: ../src/backend/filters/compositionProfile.cpp:1059
+#: ../src/backend/filters/ionClip.cpp:522
+#: ../src/backend/filters/compositionProfile.cpp:1005
 msgid "Position for centre of sphere"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:534
-#: ../src/backend/filters/ionClip.cpp:597
-#: ../src/backend/filters/compositionProfile.cpp:1042
-#: ../src/backend/filters/compositionProfile.cpp:1064
-#: ../src/backend/filters/spatialAnalysis.cpp:93
-#: ../src/backend/filters/spatialAnalysis.cpp:616
+#: ../src/backend/filters/ionClip.cpp:527
+#: ../src/backend/filters/ionClip.cpp:587
+#: ../src/backend/filters/compositionProfile.cpp:988
+#: ../src/backend/filters/compositionProfile.cpp:1010
+#: ../src/backend/filters/spatialAnalysis.cpp:111
+#: ../src/backend/filters/spatialAnalysis.cpp:791
 msgid "Radius"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:537
-#: ../src/backend/filters/compositionProfile.cpp:1067
+#: ../src/backend/filters/ionClip.cpp:530
+#: ../src/backend/filters/compositionProfile.cpp:1013
 msgid "Radius of sphere"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:551
+#: ../src/backend/filters/ionClip.cpp:544
 msgid "Position that plane passes through"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:556
+#: ../src/backend/filters/ionClip.cpp:549
 msgid "Plane Normal"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:559
+#: ../src/backend/filters/ionClip.cpp:552
 msgid "Perpendicular direction for plane"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:573
+#: ../src/backend/filters/ionClip.cpp:566
 msgid "Centre of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:578
-#: ../src/backend/filters/compositionProfile.cpp:1023
-#: ../src/backend/filters/spatialAnalysis.cpp:607
-#: ../src/backend/filters/transform.cpp:1325
+#: ../src/backend/filters/ionClip.cpp:571
+#: ../src/backend/filters/compositionProfile.cpp:972
+#: ../src/backend/filters/spatialAnalysis.cpp:782
+#: ../src/backend/filters/transform.cpp:1277
 msgid "Axis"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:581
+#: ../src/backend/filters/ionClip.cpp:574
 msgid "Positive vector for cylinder"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:589
-#: ../src/backend/filters/compositionProfile.cpp:1034
+#: ../src/backend/filters/ionClip.cpp:579
+#: ../src/backend/filters/compositionProfile.cpp:980
 msgid "Lock Axis Mag."
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:592
+#: ../src/backend/filters/ionClip.cpp:582
 msgid "Prevent changing length of cylinder during 3D interaction"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:600
-#: ../src/backend/filters/compositionProfile.cpp:1045
-#: ../src/backend/filters/spatialAnalysis.cpp:619
+#: ../src/backend/filters/ionClip.cpp:590
+#: ../src/backend/filters/compositionProfile.cpp:991
+#: ../src/backend/filters/spatialAnalysis.cpp:794
 msgid "Radius of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:613
+#: ../src/backend/filters/ionClip.cpp:603
 msgid "Centre of axis aligned box"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:618
+#: ../src/backend/filters/ionClip.cpp:608
 msgid "Corner offset"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:621
+#: ../src/backend/filters/ionClip.cpp:611
 msgid "Vector to corner of box"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:77
-#: ../src/backend/filters/clusterAnalysis.cpp:1017
+#: ../src/backend/filters/clusterAnalysis.cpp:80
+#: ../src/backend/filters/clusterAnalysis.cpp:1045
 msgid "Size Distribution"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:78
+#: ../src/backend/filters/clusterAnalysis.cpp:81
 msgid "Chemistry Distribution"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:491
+#: ../src/backend/filters/clusterAnalysis.cpp:499
 msgid "No range data. Can't cluster."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:502
+#: ../src/backend/filters/clusterAnalysis.cpp:510
 msgid ""
 "No ranges selected for cluster \"core\". Cannot continue with clustering."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:511
+#: ../src/backend/filters/clusterAnalysis.cpp:519
 msgid ""
 "No ranges selected for cluster \"bulk\". Cannot continue with clustering."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:684
-msgid "Morphology Plot"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:685
-msgid "\\lambda_1:\\lambda_2 ratio"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:686
-msgid "\\lambda_2:\\lambda_3 ratio"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:723
-msgid "No clusters had sufficient dimensionality to compute singular values"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:780
+#: ../src/backend/filters/clusterAnalysis.cpp:789
 msgid "Found :"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:782
+#: ../src/backend/filters/clusterAnalysis.cpp:791
 msgid " clusters"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:850
+#: ../src/backend/filters/clusterAnalysis.cpp:873
 msgid "Compositions (fractional, core+bulk)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:852
+#: ../src/backend/filters/clusterAnalysis.cpp:875
 msgid "Compositions (fractional, core only)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:870
+#: ../src/backend/filters/clusterAnalysis.cpp:893
 msgid "Frequencies (core+bulk)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:898
+#: ../src/backend/filters/clusterAnalysis.cpp:924
 msgid "Core Link + Erode"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:902
-#: ../src/backend/filters/spatialAnalysis.cpp:373
-#: ../src/backend/filters/ionInfo.cpp:440
+#: ../src/backend/filters/clusterAnalysis.cpp:928
+#: ../src/backend/filters/clusterAnalysis.cpp:936
+#: ../src/backend/filters/spatialAnalysis.cpp:541
+#: ../src/backend/filters/spatialAnalysis.cpp:549
+#: ../src/backend/filters/transform.cpp:1140
+#: ../src/backend/filters/ionInfo.cpp:441
 msgid "Algorithm"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:906
+#: ../src/backend/filters/clusterAnalysis.cpp:932
 msgid "Cluster algorithm mode"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:915
+#: ../src/backend/filters/clusterAnalysis.cpp:943
 msgid "Core Classify"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:918
+#: ../src/backend/filters/clusterAnalysis.cpp:946
 msgid ""
 "Enable core-classifcation pre-step in clustering (Stephenson et al, 2007)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:924
+#: ../src/backend/filters/clusterAnalysis.cpp:952
 msgid "Core Classify Dist"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:927
+#: ../src/backend/filters/clusterAnalysis.cpp:955
 msgid "Restrict only atoms by distance to be cluster sources"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:932
+#: ../src/backend/filters/clusterAnalysis.cpp:960
 msgid "Classify Knn Max"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:935
+#: ../src/backend/filters/clusterAnalysis.cpp:963
 msgid ""
 "Require that the kth NN (this number) is within the classify distance, to be "
 "a cluster source"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:941
+#: ../src/backend/filters/clusterAnalysis.cpp:969
 msgid "Core Link Dist"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:944
+#: ../src/backend/filters/clusterAnalysis.cpp:972
 msgid "Distance between clusters to allow linking"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:949
+#: ../src/backend/filters/clusterAnalysis.cpp:977
 msgid "Bulk Link"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:952
-#: ../src/backend/filters/clusterAnalysis.cpp:970
+#: ../src/backend/filters/clusterAnalysis.cpp:980
+#: ../src/backend/filters/clusterAnalysis.cpp:998
 msgid "Enable  linking of non-cluster species - eg for composition analysis "
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:959
+#: ../src/backend/filters/clusterAnalysis.cpp:987
 msgid "Bulk Link (Envelope) Dist"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:962
+#: ../src/backend/filters/clusterAnalysis.cpp:990
 msgid ""
 "Distance from core points that form cluster that is used to grab surrounding "
 "bulk points"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:967
+#: ../src/backend/filters/clusterAnalysis.cpp:995
 msgid "Erosion"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:976
+#: ../src/backend/filters/clusterAnalysis.cpp:1004
 msgid "Erode Dist"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:979
+#: ../src/backend/filters/clusterAnalysis.cpp:1007
 msgid ""
 "Distance from unclustered material in which bulk points are eroded from "
 "cluster"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:985
+#: ../src/backend/filters/clusterAnalysis.cpp:1013
 msgid "Clustering Params"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:990
+#: ../src/backend/filters/clusterAnalysis.cpp:1018
 msgid "Size Cropping"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:993
+#: ../src/backend/filters/clusterAnalysis.cpp:1021
 msgid "Remove clusters based upon size distribution"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1000
+#: ../src/backend/filters/clusterAnalysis.cpp:1028
 msgid "Min Size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1003
+#: ../src/backend/filters/clusterAnalysis.cpp:1031
 msgid "Remove clusters below this size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1008
+#: ../src/backend/filters/clusterAnalysis.cpp:1036
 msgid "Max Size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1011
+#: ../src/backend/filters/clusterAnalysis.cpp:1039
 msgid "Remove clusters above this size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1020
+#: ../src/backend/filters/clusterAnalysis.cpp:1048
 msgid "Show number of clusters as a function of cluster size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1026
+#: ../src/backend/filters/clusterAnalysis.cpp:1054
 msgid "Log Scale"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1029
+#: ../src/backend/filters/clusterAnalysis.cpp:1057
 msgid "Use logarithmic scale for size distribution"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1045
+#: ../src/backend/filters/clusterAnalysis.cpp:1075
+msgid "Cluster Id"
+msgstr ""
+
+#: ../src/backend/filters/clusterAnalysis.cpp:1078
+msgid "Assign cluster output a unique per-cluster value (id)."
+msgstr ""
+
+#: ../src/backend/filters/clusterAnalysis.cpp:1085
 msgid "Chemistry Dist."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1048
+#: ../src/backend/filters/clusterAnalysis.cpp:1088
 msgid "Create a plot showing chemistry for each cluster size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1055
-#: ../src/backend/filters/compositionProfile.cpp:1107
-#: ../src/backend/filters/spatialAnalysis.cpp:674
+#: ../src/backend/filters/clusterAnalysis.cpp:1095
+#: ../src/backend/filters/compositionProfile.cpp:1053
+#: ../src/backend/filters/spatialAnalysis.cpp:849
 #: ../src/backend/filters/ionInfo.cpp:412
 msgid "Normalise"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1058
+#: ../src/backend/filters/clusterAnalysis.cpp:1098
 msgid "Convert cluster counts to composition"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1064
+#: ../src/backend/filters/clusterAnalysis.cpp:1104
 msgid "Postprocess"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1083
+#: ../src/backend/filters/clusterAnalysis.cpp:1123
 msgid "If selected, use as \"core\" ion type (can make clusters)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1088
+#: ../src/backend/filters/clusterAnalysis.cpp:1128
 msgid "Core Ranges"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1102
+#: ../src/backend/filters/clusterAnalysis.cpp:1142
 msgid ""
 "If selected, use as \"bulk\" ion type (can be included in existing clusters)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1107
+#: ../src/backend/filters/clusterAnalysis.cpp:1147
 msgid "Bulk Ranges"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1123
+#: ../src/backend/filters/clusterAnalysis.cpp:1163
 msgid "Max. Sep + Erode"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1803
-msgid "Clustering aborted"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:1805
-msgid "No core ions for cluster"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:1807
-msgid "No bulk ions for cluster"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:1885
+#: ../src/backend/filters/clusterAnalysis.cpp:1891
 msgid " --------------------------- Parameter selection notice ------------- "
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1886
+#: ../src/backend/filters/clusterAnalysis.cpp:1892
 msgid "You have specified a bulk distance larger than half your link distance."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1887
+#: ../src/backend/filters/clusterAnalysis.cpp:1893
 msgid ""
 "You can do this; thats OK, but the output is no longer independent of the "
 "computational process;"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1888
+#: ../src/backend/filters/clusterAnalysis.cpp:1894
 msgid ""
 "This will be a problem in the case where two or more clusters can equally "
 "lay claim to a \"bulk\" ion. "
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1889
+#: ../src/backend/filters/clusterAnalysis.cpp:1895
 msgid ""
 " If your inter-cluster distance is sufficiently large (larger than your bulk "
 "linking distance), then you can get away with this."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1890
+#: ../src/backend/filters/clusterAnalysis.cpp:1896
 msgid ""
 " In theory it is possible to \"join\" the clusters, but this has not been "
 "implemented for speed reasons."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1891
+#: ../src/backend/filters/clusterAnalysis.cpp:1897
 msgid ""
 "If you want this, please contact the author, or just use the source to add "
 "this in yourself."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1892
+#: ../src/backend/filters/clusterAnalysis.cpp:1898
 msgid "---------------------------------------------------------------------- "
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1902
-#: ../src/backend/filters/spatialAnalysis.cpp:1757
-#: ../src/backend/filters/spatialAnalysis.cpp:2084
-#: ../src/backend/filters/spatialAnalysis.cpp:2382
-#: ../src/backend/filters/spatialAnalysis.cpp:3078
-#: ../src/backend/filters/transform.cpp:1033
+#: ../src/backend/filters/clusterAnalysis.cpp:1908
+#: ../src/backend/filters/spatialAnalysis.cpp:1971
+#: ../src/backend/filters/spatialAnalysis.cpp:2314
+#: ../src/backend/filters/spatialAnalysis.cpp:2605
+#: ../src/backend/filters/spatialAnalysis.cpp:3293
+#: ../src/backend/filters/transform.cpp:991
 msgid "Collate"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1921
+#: ../src/backend/filters/clusterAnalysis.cpp:1927
 msgid "Build Core"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1939
+#: ../src/backend/filters/clusterAnalysis.cpp:1945
 msgid "Classify Core"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2032
+#: ../src/backend/filters/clusterAnalysis.cpp:2038
 msgid "Build Bulk"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2052
+#: ../src/backend/filters/clusterAnalysis.cpp:2058
 msgid "Core"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2197
+#: ../src/backend/filters/clusterAnalysis.cpp:2203
 msgid "Bulk"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2327
+#: ../src/backend/filters/clusterAnalysis.cpp:2333
 msgid "Erode"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2401
+#: ../src/backend/filters/clusterAnalysis.cpp:2407
 msgid "Re-Collate"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2669
-#: ../src/backend/filters/clusterAnalysis.cpp:2873
+#: ../src/backend/filters/clusterAnalysis.cpp:2675
+#: ../src/backend/filters/clusterAnalysis.cpp:2879
 msgid "Cluster Size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2670
-#: ../src/backend/filters/clusterAnalysis.cpp:2877
+#: ../src/backend/filters/clusterAnalysis.cpp:2676
+#: ../src/backend/filters/clusterAnalysis.cpp:2883
 msgid "Frequency"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2875
+#: ../src/backend/filters/clusterAnalysis.cpp:2881
 msgid "Composition"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:109
+#: ../src/backend/filters/voxelise.cpp:110
 msgid "None (Raw count)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:110
+#: ../src/backend/filters/voxelise.cpp:111
 msgid "Volume (Density)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:111
+#: ../src/backend/filters/voxelise.cpp:112
 msgid "All Ions (conc)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:112
+#: ../src/backend/filters/voxelise.cpp:113
 msgid "Ratio (Num/Denom)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:116
+#: ../src/backend/filters/voxelise.cpp:117
 msgid "Point Cloud"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:117
+#: ../src/backend/filters/voxelise.cpp:118
 msgid "Isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:118
+#: ../src/backend/filters/voxelise.cpp:119
 msgid "Axial slice"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:123
+#: ../src/backend/filters/voxelise.cpp:124
 msgid "Gaussian (2𝜎)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:127
+#: ../src/backend/filters/voxelise.cpp:128
 msgid "Zero"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:128
+#: ../src/backend/filters/voxelise.cpp:129
 msgid "Bounce"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:133
+#: ../src/backend/filters/voxelise.cpp:134
 msgid "Linear"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:604
+#: ../src/backend/filters/voxelise.cpp:601
 msgid "Voxel Limits (min,max): ("
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:754
+#: ../src/backend/filters/voxelise.cpp:751
 msgid "Fixed width"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:758
+#: ../src/backend/filters/voxelise.cpp:755
 msgid "If true, use fixed size voxels, otherwise use fixed count"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:764
+#: ../src/backend/filters/voxelise.cpp:761
 msgid "Bin width x"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:768
+#: ../src/backend/filters/voxelise.cpp:765
 msgid "Voxel size in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:772
+#: ../src/backend/filters/voxelise.cpp:769
 msgid "Bin width y"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:775
+#: ../src/backend/filters/voxelise.cpp:772
 msgid "Voxel size in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:781
+#: ../src/backend/filters/voxelise.cpp:778
 msgid "Bin width z"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:784
+#: ../src/backend/filters/voxelise.cpp:781
 msgid "Voxel size in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:791
+#: ../src/backend/filters/voxelise.cpp:788
 msgid "Num bins x"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:795
+#: ../src/backend/filters/voxelise.cpp:792
 msgid "Number of voxels to use in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:800
+#: ../src/backend/filters/voxelise.cpp:797
 msgid "Num bins y"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:803
+#: ../src/backend/filters/voxelise.cpp:800
 msgid "Number of voxels to use in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:809
+#: ../src/backend/filters/voxelise.cpp:806
 msgid "Num bins z"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:811
+#: ../src/backend/filters/voxelise.cpp:808
 msgid "Number of voxels to use in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:832
+#: ../src/backend/filters/voxelise.cpp:838
 msgid "Normalise by"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:835
+#: ../src/backend/filters/voxelise.cpp:841
 msgid "Method to use to normalise scalar value in each voxel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:838
+#: ../src/backend/filters/voxelise.cpp:844
 msgid "Computation"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:845
+#: ../src/backend/filters/voxelise.cpp:851
 msgid "Numerator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:848
+#: ../src/backend/filters/voxelise.cpp:854
 msgid "Parmeter \"a\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:868
+#: ../src/backend/filters/voxelise.cpp:871
 msgid "Enable this ion for numerator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:879
+#: ../src/backend/filters/voxelise.cpp:883
 msgid "Denominator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:882
+#: ../src/backend/filters/voxelise.cpp:886
 msgid "Parameter \"b\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:898
+#: ../src/backend/filters/voxelise.cpp:899
 msgid "Enable this ion for denominator contribution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:919
-#: ../src/backend/filters/voxelise.cpp:954
+#: ../src/backend/filters/voxelise.cpp:920
+#: ../src/backend/filters/voxelise.cpp:955
 msgid "Filtering"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:923
+#: ../src/backend/filters/voxelise.cpp:924
 msgid "Smoothing method to use on voxels"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:926
+#: ../src/backend/filters/voxelise.cpp:927
 msgid "Processing"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:932
+#: ../src/backend/filters/voxelise.cpp:933
 msgid "Kernel Bins"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:936
+#: ../src/backend/filters/voxelise.cpp:937
 msgid "Number of bins in convolution kernel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:947
+#: ../src/backend/filters/voxelise.cpp:948
 msgid "Exterior values"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:950
+#: ../src/backend/filters/voxelise.cpp:951
 msgid "Method to use to treat boundaries of voxel data for convolution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:970
+#: ../src/backend/filters/voxelise.cpp:971
 msgid "Representation"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:973
+#: ../src/backend/filters/voxelise.cpp:974
 msgid "3D display method"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:984
+#: ../src/backend/filters/voxelise.cpp:985
 msgid "Spot size"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:987
+#: ../src/backend/filters/voxelise.cpp:988
 msgid "Size of the spots to use for display"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:992
-#: ../src/backend/filters/voxelise.cpp:1030
+#: ../src/backend/filters/voxelise.cpp:993
+#: ../src/backend/filters/voxelise.cpp:1028
 msgid "Transparency"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:995
+#: ../src/backend/filters/voxelise.cpp:996
 msgid "How \"see through\" each point is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1004
+#: ../src/backend/filters/voxelise.cpp:1005
 msgid "Surf. param."
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1007
+#: ../src/backend/filters/voxelise.cpp:1008
 msgid "Isovalue"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1010
+#: ../src/backend/filters/voxelise.cpp:1011
 msgid "Scalar value to show as isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1025
+#: ../src/backend/filters/voxelise.cpp:1016
+#: ../src/backend/filters/voxelise.cpp:1081
+#: ../src/backend/filters/spatialAnalysis.cpp:2019
+#: ../src/backend/filters/spatialAnalysis.cpp:2073
+msgid "Surface"
+msgstr ""
+
+#: ../src/backend/filters/voxelise.cpp:1023
 msgid "Colour of isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1033
+#: ../src/backend/filters/voxelise.cpp:1031
 msgid "How \"see through\" each facet is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1045
+#: ../src/backend/filters/voxelise.cpp:1042
 msgid "Slice param."
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1053
+#: ../src/backend/filters/voxelise.cpp:1050
 msgid "Slice Axis"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1056
+#: ../src/backend/filters/voxelise.cpp:1053
 msgid "Normal for the planar slice"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1063
+#: ../src/backend/filters/voxelise.cpp:1060
 msgid "Slice Coord"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1066
+#: ../src/backend/filters/voxelise.cpp:1063
 msgid "Fractional coordinate that slice plane passes through"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1071
+#: ../src/backend/filters/voxelise.cpp:1068
 msgid "Interp. Mode"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1079
+#: ../src/backend/filters/voxelise.cpp:1076
 msgid "Interpolation mode for direction normal to slice"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1094
+#: ../src/backend/filters/voxelise.cpp:1092
 msgid "Colour mode"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1097
-#: ../src/backend/filters/ionColour.cpp:262
+#: ../src/backend/filters/voxelise.cpp:1095
+#: ../src/backend/filters/ionColour.cpp:265
 msgid "Colour scheme used to assign points colours by value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1106
-#: ../src/backend/filters/ionColour.cpp:274
+#: ../src/backend/filters/voxelise.cpp:1100
+#: ../src/backend/filters/ionColour.cpp:277
 msgid "Show Bar"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1116
+#: ../src/backend/filters/voxelise.cpp:1107
 msgid "Auto Bounds"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1117
+#: ../src/backend/filters/voxelise.cpp:1108
 msgid "Auto-compute min/max values in map"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1127
-#: ../src/backend/filters/ionColour.cpp:289
+#: ../src/backend/filters/voxelise.cpp:1118
+#: ../src/backend/filters/ionColour.cpp:298
 msgid "Map start"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1128
-#: ../src/backend/filters/ionColour.cpp:290
+#: ../src/backend/filters/voxelise.cpp:1119
+#: ../src/backend/filters/ionColour.cpp:299
 msgid "Assign points with this value to the first colour in map"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1135
-#: ../src/backend/filters/ionColour.cpp:297
+#: ../src/backend/filters/voxelise.cpp:1126
+#: ../src/backend/filters/ionColour.cpp:306
 msgid "Map end"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1136
-#: ../src/backend/filters/ionColour.cpp:298
+#: ../src/backend/filters/voxelise.cpp:1127
+#: ../src/backend/filters/ionColour.cpp:307
 msgid "Assign points with this value to the last colour in map"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1707
-msgid "Voxelisation aborted"
-msgstr ""
-
-#: ../src/backend/filters/voxelise.cpp:1709
-msgid "Out of memory"
-msgstr ""
-
-#: ../src/backend/filters/voxelise.cpp:1711
-msgid "Unable to perform filter convolution"
-msgstr ""
-
-#: ../src/backend/filters/voxelise.cpp:1713
-msgid "Voxelisation bounds are invalid"
-msgstr ""
-
-#: ../src/backend/filters/ionColour.cpp:258
+#: ../src/backend/filters/ionColour.cpp:261
 msgid "Colour Map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:266
+#: ../src/backend/filters/ionColour.cpp:269
 msgid "Reverse map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:267
+#: ../src/backend/filters/ionColour.cpp:270
 msgid "Reverse the colour scale"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:281
+#: ../src/backend/filters/ionColour.cpp:283
+msgid "Opacity"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:290
 msgid "Num Colours"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:283
+#: ../src/backend/filters/ionColour.cpp:292
 msgid "Number of unique colours to use in colour map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:416
-#: ../src/backend/filters/transform.cpp:1579
-#: ../src/backend/filters/ionInfo.cpp:541
+#: ../src/backend/filters/ionColour.cpp:413
 msgid "Aborted"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:536
+#: ../src/backend/filters/compositionProfile.cpp:568
 msgid "Distance"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:544
+#: ../src/backend/filters/compositionProfile.cpp:576
 msgid "Fraction"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:546
+#: ../src/backend/filters/compositionProfile.cpp:578
 msgid "Density (\\frac{\\#}{len^3})"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:573
+#: ../src/backend/filters/compositionProfile.cpp:605
 msgid "Freq. Profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:641
-msgid "Too many bins in comp. profile."
+#: ../src/backend/filters/compositionProfile.cpp:657
+msgid "No data remained in profile - cannot display result"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:643
-msgid "Not enough memory for comp. profile."
-msgstr ""
-
-#: ../src/backend/filters/compositionProfile.cpp:645
-msgid "Aborted composition prof."
-msgstr ""
-
-#: ../src/backend/filters/compositionProfile.cpp:989
+#: ../src/backend/filters/compositionProfile.cpp:937
 msgid "Primitive type"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:993
+#: ../src/backend/filters/compositionProfile.cpp:941
 msgid "Basic shape to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1004
+#: ../src/backend/filters/compositionProfile.cpp:953
 msgid "Display the 3D composition profile interaction object"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1018
-#: ../src/backend/filters/spatialAnalysis.cpp:602
+#: ../src/backend/filters/compositionProfile.cpp:967
+#: ../src/backend/filters/spatialAnalysis.cpp:777
 msgid "Position for centre of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1026
+#: ../src/backend/filters/compositionProfile.cpp:975
 msgid "Vector between ends of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1037
+#: ../src/backend/filters/compositionProfile.cpp:983
 msgid "Prevent length of cylinder changing during interaction"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1077
+#: ../src/backend/filters/compositionProfile.cpp:1023
 msgid "Fixed Bin Num"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1080
+#: ../src/backend/filters/compositionProfile.cpp:1026
 msgid ""
 "If true, use a fixed number of bins for profile, otherwise use fixed step "
 "size"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1086
-#: ../src/backend/filters/spatialAnalysis.cpp:433
-#: ../src/backend/filters/spatialAnalysis.cpp:575
+#: ../src/backend/filters/compositionProfile.cpp:1032
+#: ../src/backend/filters/spatialAnalysis.cpp:612
+#: ../src/backend/filters/spatialAnalysis.cpp:754
 msgid "Num Bins"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1091
+#: ../src/backend/filters/compositionProfile.cpp:1037
 msgid "Number of bins to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1096
-#: ../src/backend/filters/spectrumPlot.cpp:396
+#: ../src/backend/filters/compositionProfile.cpp:1042
+#: ../src/backend/filters/spectrumPlot.cpp:386
 msgid "Bin width"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1102
+#: ../src/backend/filters/compositionProfile.cpp:1048
 msgid "Size of each bin in profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1111
+#: ../src/backend/filters/compositionProfile.cpp:1057
 msgid "Convert bin counts into relative frequencies in each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1115
+#: ../src/backend/filters/compositionProfile.cpp:1061
 msgid "Min. events"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1119
+#: ../src/backend/filters/compositionProfile.cpp:1065
 msgid "Drop data that does not have this many events"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1143
-#: ../src/backend/filters/spectrumPlot.cpp:459
+#: ../src/backend/filters/compositionProfile.cpp:1068
+msgid "Settings"
+msgstr ""
+
+#: ../src/backend/filters/compositionProfile.cpp:1090
+#: ../src/backend/filters/spectrumPlot.cpp:445
 msgid "Plot Type"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1146
+#: ../src/backend/filters/compositionProfile.cpp:1093
 msgid "Visual style for plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1159
+#: ../src/backend/filters/compositionProfile.cpp:1103
 msgid "Colour of plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1175
+#: ../src/backend/filters/compositionProfile.cpp:1119
 msgid "Err. Estimator"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1178
+#: ../src/backend/filters/compositionProfile.cpp:1122
 msgid "Method of estimating error associated with each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1185
+#: ../src/backend/filters/compositionProfile.cpp:1129
 msgid "Avg. Window"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1188
+#: ../src/backend/filters/compositionProfile.cpp:1132
 msgid "Number of bins to include in moving average filter"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1192
+#: ../src/backend/filters/compositionProfile.cpp:1136
 msgid "Error analysis"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:84
+#: ../src/backend/filters/spatialAnalysis.cpp:101
 msgid "Local Density"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:85
+#: ../src/backend/filters/spatialAnalysis.cpp:102
 msgid "Density Filtering"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:86
+#: ../src/backend/filters/spatialAnalysis.cpp:103
 msgid "Radial Distribution"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:87
+#: ../src/backend/filters/spatialAnalysis.cpp:104
 msgid "Axial Distribution"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:88
+#: ../src/backend/filters/spatialAnalysis.cpp:105
 msgid "Binomial Distribution"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:92
+#: ../src/backend/filters/spatialAnalysis.cpp:106
+msgid "Point Em/Replacement"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:110
 msgid "Neighbour Count"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:376
+#: ../src/backend/filters/spatialAnalysis.cpp:544
 msgid "Spatial analysis algorithm to use"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:398
+#: ../src/backend/filters/spatialAnalysis.cpp:567
 msgid "Stop Mode"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:401
+#: ../src/backend/filters/spatialAnalysis.cpp:570
 msgid "Method to use to terminate algorithm when examining each point"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:408
+#: ../src/backend/filters/spatialAnalysis.cpp:577
 msgid "NN Max"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:411
+#: ../src/backend/filters/spatialAnalysis.cpp:580
 msgid "Maximum number of neighbours to examine"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:417
+#: ../src/backend/filters/spatialAnalysis.cpp:586
+msgid "Normalise bins"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:589
+msgid ""
+"Normalise counts by binwidth. Needed when comparing NN histograms against "
+"one another"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:596
 msgid "Dist Max"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:420
+#: ../src/backend/filters/spatialAnalysis.cpp:599
 msgid "Maximum distance from each point for search"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:436
-#: ../src/backend/filters/spatialAnalysis.cpp:578
+#: ../src/backend/filters/spatialAnalysis.cpp:615
+#: ../src/backend/filters/spatialAnalysis.cpp:757
 msgid "Number of bins for output 1D RDF plot"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:442
+#: ../src/backend/filters/spatialAnalysis.cpp:621
 msgid "Surface Remove"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:445
+#: ../src/backend/filters/spatialAnalysis.cpp:624
 msgid ""
 "Exclude surface as part of source to minimise bias in RDF (at cost of "
 "increased noise)"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:452
+#: ../src/backend/filters/spatialAnalysis.cpp:631
 msgid "Remove Dist"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:455
+#: ../src/backend/filters/spatialAnalysis.cpp:634
 msgid "Minimum distance to remove from surface"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:466
-#: ../src/backend/filters/spatialAnalysis.cpp:587
+#: ../src/backend/filters/spatialAnalysis.cpp:642
+#: ../src/backend/filters/spatialAnalysis.cpp:762
 msgid "Plot colour "
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:469
-#: ../src/backend/filters/spatialAnalysis.cpp:590
+#: ../src/backend/filters/spatialAnalysis.cpp:645
+#: ../src/backend/filters/spatialAnalysis.cpp:765
 msgid "Colour of output plot"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:488
+#: ../src/backend/filters/spatialAnalysis.cpp:649
+#: ../src/backend/filters/spatialAnalysis.cpp:743
+#: ../src/backend/filters/spatialAnalysis.cpp:748
+#: ../src/backend/filters/spatialAnalysis.cpp:797
+#: ../src/backend/filters/spatialAnalysis.cpp:836
+msgid "Alg. Params."
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:665
 msgid "Source"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:491
+#: ../src/backend/filters/spatialAnalysis.cpp:668
 msgid "Ions to use for initiating RDF search"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:504
+#: ../src/backend/filters/spatialAnalysis.cpp:681
 msgid "Enable/disable ion as source"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:521
+#: ../src/backend/filters/spatialAnalysis.cpp:687
+msgid "Source Ion"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:700
 msgid "Enable/disable all ions as target"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:533
+#: ../src/backend/filters/spatialAnalysis.cpp:712
 msgid "Enable/disable this ion as target"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:541
-#: ../src/backend/filters/spatialAnalysis.cpp:564
-#: ../src/backend/filters/spatialAnalysis.cpp:569
-#: ../src/backend/filters/spatialAnalysis.cpp:622
-#: ../src/backend/filters/spatialAnalysis.cpp:661
-msgid "Alg. Params."
+#: ../src/backend/filters/spatialAnalysis.cpp:717
+msgid "Target Ion"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:548
+#: ../src/backend/filters/spatialAnalysis.cpp:727
 msgid "Cutoff"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:551
+#: ../src/backend/filters/spatialAnalysis.cpp:730
 msgid "Remove points with local density above/below this value"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:557
+#: ../src/backend/filters/spatialAnalysis.cpp:736
 msgid "Retain Upper"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:560
+#: ../src/backend/filters/spatialAnalysis.cpp:739
 msgid "Retain either points with density above (enabled) or below cutoff"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:610
+#: ../src/backend/filters/spatialAnalysis.cpp:785
 msgid "Vector between centre and end of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:629
-#: ../src/backend/filters/spatialAnalysis.cpp:3217
-#: ../src/backend/filters/spatialAnalysis.cpp:3286
+#: ../src/backend/filters/spatialAnalysis.cpp:804
+#: ../src/backend/filters/spatialAnalysis.cpp:3432
+#: ../src/backend/filters/spatialAnalysis.cpp:3491
 msgid "Block size"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:632
+#: ../src/backend/filters/spatialAnalysis.cpp:807
 msgid "Number of ions to use per block"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:639
+#: ../src/backend/filters/spatialAnalysis.cpp:814
 msgid "Max Block Aspect"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:642
+#: ../src/backend/filters/spatialAnalysis.cpp:817
 msgid ""
 "Maximum allowable block aspect ratio. Blocks above this aspect are "
 "discarded. Setting too high decreases correlation strength. Too low causes "
 "loss of statistical power."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:653
+#: ../src/backend/filters/spatialAnalysis.cpp:828
 msgid "Extrusion Direction"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:656
+#: ../src/backend/filters/spatialAnalysis.cpp:831
 msgid "Direction in which blocks are extended during construction."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:665
+#: ../src/backend/filters/spatialAnalysis.cpp:840
 msgid "Plot Counts"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:668
+#: ../src/backend/filters/spatialAnalysis.cpp:843
 msgid "Show the counts in the binomial histogram"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:677
+#: ../src/backend/filters/spatialAnalysis.cpp:852
 msgid ""
 "Normalise the counts in the binomial histogram to a probability density "
 "function"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:691
+#: ../src/backend/filters/spatialAnalysis.cpp:866
 msgid "Display Grid"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:700
+#: ../src/backend/filters/spatialAnalysis.cpp:875
 msgid "View Options"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1227
-msgid "Spatial analysis aborted by user"
+#: ../src/backend/filters/spatialAnalysis.cpp:881
+msgid "Data File"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1229
-msgid "Insufficient data to complete analysis."
+#: ../src/backend/filters/spatialAnalysis.cpp:885
+msgid "Pos file of points to subtract/replace/etc"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1231
-msgid "Insufficient bins in histogram for analysis."
+#: ../src/backend/filters/spatialAnalysis.cpp:890
+msgid "Match Tol."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1233
-msgid "Insufficient memory for binomial. Reduce input size?"
+#: ../src/backend/filters/spatialAnalysis.cpp:893
+msgid "Tolerance to allow for matching"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1235
-msgid "Binomial requires a parent range file"
+#: ../src/backend/filters/spatialAnalysis.cpp:909
+msgid "Replacment condition"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1791
-#: ../src/backend/filters/spatialAnalysis.cpp:1843
-#: ../src/backend/filters/spatialAnalysis.cpp:2090
-#: ../src/backend/filters/spatialAnalysis.cpp:2388
-#: ../src/backend/filters/spatialAnalysis.cpp:2920
-msgid "Build"
+#: ../src/backend/filters/spatialAnalysis.cpp:915
+msgid "Replace value"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1803
-#: ../src/backend/filters/spatialAnalysis.cpp:1855
-msgid "Surface"
+#: ../src/backend/filters/spatialAnalysis.cpp:918
+msgid "Use value data from file when replacing ions"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:923
+msgid "Replacement"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:2005
+#: ../src/backend/filters/spatialAnalysis.cpp:2059
+#: ../src/backend/filters/spatialAnalysis.cpp:2320
+#: ../src/backend/filters/spatialAnalysis.cpp:2611
+#: ../src/backend/filters/spatialAnalysis.cpp:3136
+msgid "Build"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1895
-#: ../src/backend/filters/spatialAnalysis.cpp:2117
-#: ../src/backend/filters/spatialAnalysis.cpp:2415
+#: ../src/backend/filters/spatialAnalysis.cpp:2113
+#: ../src/backend/filters/spatialAnalysis.cpp:2347
+#: ../src/backend/filters/spatialAnalysis.cpp:2638
 msgid "Analyse"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1952
-#: ../src/backend/filters/spatialAnalysis.cpp:2021
+#: ../src/backend/filters/spatialAnalysis.cpp:2195
+#: ../src/backend/filters/spatialAnalysis.cpp:2258
 msgid "Radial Distance"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1956
+#: ../src/backend/filters/spatialAnalysis.cpp:2197
+msgid "Count/Distance"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:2202
 msgid "NN Freq."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2012
+#: ../src/backend/filters/spatialAnalysis.cpp:2249
 msgid "Warning, "
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2013
+#: ../src/backend/filters/spatialAnalysis.cpp:2250
 msgid ""
 " points were unable to find neighbour points that exceeded the search "
 "radius, and thus terminated prematurely"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2023
+#: ../src/backend/filters/spatialAnalysis.cpp:2260
 msgid " RDF"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2313
-#: ../src/backend/filters/spatialAnalysis.cpp:2621
+#: ../src/backend/filters/spatialAnalysis.cpp:2543
+#: ../src/backend/filters/spatialAnalysis.cpp:2844
 msgid "Number Density (\\#/Vol^3)"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2342
-#: ../src/backend/filters/spatialAnalysis.cpp:2648
+#: ../src/backend/filters/spatialAnalysis.cpp:2565
+#: ../src/backend/filters/spatialAnalysis.cpp:2864
 msgid "Warning,"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2343
-#: ../src/backend/filters/spatialAnalysis.cpp:2649
+#: ../src/backend/filters/spatialAnalysis.cpp:2566
+#: ../src/backend/filters/spatialAnalysis.cpp:2865
 msgid " points were un-analysable. These have been dropped"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2365
-#: ../src/backend/filters/spatialAnalysis.cpp:2671
+#: ../src/backend/filters/spatialAnalysis.cpp:2588
+#: ../src/backend/filters/spatialAnalysis.cpp:2887
 msgid "And so on..."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2754
+#: ../src/backend/filters/spatialAnalysis.cpp:2970
 msgid "Extract"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2829
+#: ../src/backend/filters/spatialAnalysis.cpp:3045
 msgid "Reduce"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2937
+#: ../src/backend/filters/spatialAnalysis.cpp:3155
 msgid "Compute"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2965
+#: ../src/backend/filters/spatialAnalysis.cpp:3200
 msgid "Insufficient points to complete analysis"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3001
+#: ../src/backend/filters/spatialAnalysis.cpp:3223
 msgid "Axial Distance"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3003
+#: ../src/backend/filters/spatialAnalysis.cpp:3225
 msgid " 1D Dist. Func."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3087
+#: ../src/backend/filters/spatialAnalysis.cpp:3302
 msgid "Binomial"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3219
-#: ../src/backend/filters/spatialAnalysis.cpp:3288
+#: ../src/backend/filters/spatialAnalysis.cpp:3434
+#: ../src/backend/filters/spatialAnalysis.cpp:3493
 msgid "Rel. Frequency"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:77
+#: ../src/backend/filters/transform.cpp:78
 msgid "Translate"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:78
+#: ../src/backend/filters/transform.cpp:79
 msgid "Scale (isotropic)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:79
+#: ../src/backend/filters/transform.cpp:80
 msgid "Scale (anisotropic)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:80
+#: ../src/backend/filters/transform.cpp:81
 msgid "Rotate"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:81
+#: ../src/backend/filters/transform.cpp:82
 msgid "Value Shuffle"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:82
+#: ../src/backend/filters/transform.cpp:83
 msgid "Spatial Noise"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:83
+#: ../src/backend/filters/transform.cpp:84
 msgid "Translate Value"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:87
+#: ../src/backend/filters/transform.cpp:88
 msgid "Specify"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:88
+#: ../src/backend/filters/transform.cpp:89
 msgid "Boundbox Centre"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:89
+#: ../src/backend/filters/transform.cpp:90
 msgid "Mass Centre"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1052
+#: ../src/backend/filters/transform.cpp:1010
 msgid "Mass-to-Charge (amu/e)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1106
+#: ../src/backend/filters/transform.cpp:1064
 msgid "Shuffle"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1130
+#: ../src/backend/filters/transform.cpp:1088
 msgid "Splice"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1185
+#: ../src/backend/filters/transform.cpp:1136
 msgid "Algorithm to use to transform point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1201
+#: ../src/backend/filters/transform.cpp:1153
 msgid "Origin mode"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1204
+#: ../src/backend/filters/transform.cpp:1156
 msgid "Select how transform origin is computed"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1209
+#: ../src/backend/filters/transform.cpp:1161
 msgid "Show marker"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1213
+#: ../src/backend/filters/transform.cpp:1165
 msgid "Display an interactive object to set transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1215
+#: ../src/backend/filters/transform.cpp:1167
 msgid "Display a small marker to denote transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1231
+#: ../src/backend/filters/transform.cpp:1183
 msgid "Translation"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1234
+#: ../src/backend/filters/transform.cpp:1186
 msgid "Translation vector for transform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1246
+#: ../src/backend/filters/transform.cpp:1198
 msgid "Offset"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1250
+#: ../src/backend/filters/transform.cpp:1202
 msgid "Scalar to use to offset each point's associated value"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1267
-#: ../src/backend/filters/transform.cpp:1294
+#: ../src/backend/filters/transform.cpp:1219
+#: ../src/backend/filters/transform.cpp:1246
 msgid "Origin of scale trasnform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1274
-#: ../src/backend/filters/transform.cpp:1301
+#: ../src/backend/filters/transform.cpp:1226
+#: ../src/backend/filters/transform.cpp:1253
 msgid "Scale Fact."
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1277
-#: ../src/backend/filters/transform.cpp:1304
+#: ../src/backend/filters/transform.cpp:1229
+#: ../src/backend/filters/transform.cpp:1256
 msgid "Enlargement factor for scaling around origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1320
+#: ../src/backend/filters/transform.cpp:1272
 msgid "Origin of rotation"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1328
+#: ../src/backend/filters/transform.cpp:1280
 msgid "Axis around which to revolve"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1333
+#: ../src/backend/filters/transform.cpp:1285
 msgid "Angle (deg)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1336
+#: ../src/backend/filters/transform.cpp:1288
 msgid "Angle to perform rotation (ACW, as viewed from axis towards origin)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1353
+#: ../src/backend/filters/transform.cpp:1305
 msgid "Noise Type"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1356
+#: ../src/backend/filters/transform.cpp:1308
 msgid "Method to use to degrade point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1363
+#: ../src/backend/filters/transform.cpp:1315
 msgid "Noise level"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1365
+#: ../src/backend/filters/transform.cpp:1317
 msgid "Standard dev."
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1373
+#: ../src/backend/filters/transform.cpp:1325
 msgid "Amplitude of noise"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1385
+#: ../src/backend/filters/transform.cpp:1337
 msgid "Transform Params"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1582
-msgid "Unable to allocate memory"
-msgstr ""
-
-#: ../src/backend/filters/transform.cpp:1761
+#: ../src/backend/filters/transform.cpp:1675
 msgid "White"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1763
+#: ../src/backend/filters/transform.cpp:1677
 msgid "Gaussian"
 msgstr ""
 
@@ -3772,102 +3694,106 @@ msgstr ""
 msgid "Dimension"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:524
+#: ../src/backend/filters/boundingBox.cpp:525
 msgid "If true, show box, otherwise hide box"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:537
+#: ../src/backend/filters/boundingBox.cpp:538
 msgid "Style"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:540
+#: ../src/backend/filters/boundingBox.cpp:541
 msgid "Box display mode"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:551
+#: ../src/backend/filters/boundingBox.cpp:544
+msgid "Display mode"
+msgstr ""
+
+#: ../src/backend/filters/boundingBox.cpp:553
 msgid "Fixed Tick Num"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:555
+#: ../src/backend/filters/boundingBox.cpp:557
 msgid ""
 "If true, evenly use specified number of ticks. Otherwise, use distance to "
 "determine tick count"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:563
+#: ../src/backend/filters/boundingBox.cpp:565
 msgid "Num X"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:566
+#: ../src/backend/filters/boundingBox.cpp:568
 msgid "Tick count in X direction"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:571
+#: ../src/backend/filters/boundingBox.cpp:573
 msgid "Num Y"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:574
+#: ../src/backend/filters/boundingBox.cpp:576
 msgid "Tick count in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:579
+#: ../src/backend/filters/boundingBox.cpp:581
 msgid "Num Z"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:582
+#: ../src/backend/filters/boundingBox.cpp:584
 msgid "Tick count in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:588
+#: ../src/backend/filters/boundingBox.cpp:590
 msgid "Spacing X"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:592
+#: ../src/backend/filters/boundingBox.cpp:594
 msgid "Distance between ticks on X axis"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:596
+#: ../src/backend/filters/boundingBox.cpp:598
 msgid "Spacing Y"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:600
+#: ../src/backend/filters/boundingBox.cpp:602
 msgid "Distance between ticks on Y axis"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:604
+#: ../src/backend/filters/boundingBox.cpp:606
 msgid "Spacing Z"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:608
+#: ../src/backend/filters/boundingBox.cpp:610
 msgid "Distance between ticks on Z axis"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:611
+#: ../src/backend/filters/boundingBox.cpp:613
 msgid "Tick marks"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:621
+#: ../src/backend/filters/boundingBox.cpp:620
 msgid "Box Colour"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:625
+#: ../src/backend/filters/boundingBox.cpp:624
 msgid "Colour of the bounding box"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:630
+#: ../src/backend/filters/boundingBox.cpp:629
 msgid "Line thickness"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:634
+#: ../src/backend/filters/boundingBox.cpp:633
 msgid "Thickness of the lines used to draw the box"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:642
-#: ../src/backend/filters/annotation.cpp:845
+#: ../src/backend/filters/boundingBox.cpp:641
+#: ../src/backend/filters/annotation.cpp:843
 msgid "Font Size"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:645
+#: ../src/backend/filters/boundingBox.cpp:644
 msgid "Relative size for text"
 msgstr ""
 
@@ -3891,248 +3817,250 @@ msgstr ""
 msgid "Ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:526
+#: ../src/backend/filters/annotation.cpp:519
 msgid "Enable"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:529
+#: ../src/backend/filters/annotation.cpp:522
 msgid "Enable/disable annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:550
+#: ../src/backend/filters/annotation.cpp:543
 msgid "Type or style of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:565
-#: ../src/backend/filters/annotation.cpp:667
+#: ../src/backend/filters/annotation.cpp:559
+#: ../src/backend/filters/annotation.cpp:663
 msgid "Text of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:573
+#: ../src/backend/filters/annotation.cpp:567
 msgid "Position of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:577
-#: ../src/backend/filters/annotation.cpp:681
-#: ../src/backend/filters/annotation.cpp:739
-#: ../src/backend/filters/annotation.cpp:828
+#: ../src/backend/filters/annotation.cpp:571
+#: ../src/backend/filters/annotation.cpp:678
+#: ../src/backend/filters/annotation.cpp:737
+#: ../src/backend/filters/annotation.cpp:826
 msgid "Up dir"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:581
-#: ../src/backend/filters/annotation.cpp:832
+#: ../src/backend/filters/annotation.cpp:575
+#: ../src/backend/filters/annotation.cpp:830
 msgid "Vector for up direction of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:585
-#: ../src/backend/filters/annotation.cpp:688
-#: ../src/backend/filters/annotation.cpp:731
-#: ../src/backend/filters/annotation.cpp:836
+#: ../src/backend/filters/annotation.cpp:579
+#: ../src/backend/filters/annotation.cpp:685
+#: ../src/backend/filters/annotation.cpp:729
+#: ../src/backend/filters/annotation.cpp:834
 msgid "Across dir"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:589
-#: ../src/backend/filters/annotation.cpp:840
+#: ../src/backend/filters/annotation.cpp:583
+#: ../src/backend/filters/annotation.cpp:838
 msgid "Reading direction for annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:594
-#: ../src/backend/filters/annotation.cpp:673
-#: ../src/backend/filters/annotation.cpp:766
+#: ../src/backend/filters/annotation.cpp:588
+#: ../src/backend/filters/annotation.cpp:670
+#: ../src/backend/filters/annotation.cpp:764
 msgid "Text size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:598
-#: ../src/backend/filters/annotation.cpp:677
-#: ../src/backend/filters/annotation.cpp:848
+#: ../src/backend/filters/annotation.cpp:592
+#: ../src/backend/filters/annotation.cpp:674
+#: ../src/backend/filters/annotation.cpp:846
 msgid "Relative size of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:610
-#: ../src/backend/filters/annotation.cpp:649
+#: ../src/backend/filters/annotation.cpp:604
+#: ../src/backend/filters/annotation.cpp:645
 msgid "3D position for tail of arrow"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:618
-#: ../src/backend/filters/annotation.cpp:658
+#: ../src/backend/filters/annotation.cpp:612
+#: ../src/backend/filters/annotation.cpp:654
 msgid "3D Position to which arrow points"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:624
-#: ../src/backend/filters/annotation.cpp:695
+#: ../src/backend/filters/annotation.cpp:615
+#: ../src/backend/filters/annotation.cpp:725
+msgid "Positioning"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:620
+#: ../src/backend/filters/annotation.cpp:692
 msgid "Tip radius"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:628
+#: ../src/backend/filters/annotation.cpp:624
 msgid "Size of the arrow head"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:632
+#: ../src/backend/filters/annotation.cpp:628
 msgid "Line size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:636
+#: ../src/backend/filters/annotation.cpp:632
 msgid "Thickness of line used to draw arrow stem"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:705
+#: ../src/backend/filters/annotation.cpp:666
+msgid "Options"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:702
 msgid "Position A"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:709
+#: ../src/backend/filters/annotation.cpp:706
 msgid "Location of first non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:713
+#: ../src/backend/filters/annotation.cpp:710
 msgid "Origin "
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:717
+#: ../src/backend/filters/annotation.cpp:714
 msgid "Location of central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:721
+#: ../src/backend/filters/annotation.cpp:718
 msgid "Position B"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:725
+#: ../src/backend/filters/annotation.cpp:722
 msgid "Location of second non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:735
+#: ../src/backend/filters/annotation.cpp:733
 msgid "Reading direction for angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:740
+#: ../src/backend/filters/annotation.cpp:738
 msgid "Vector for up direction of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:748
+#: ../src/backend/filters/annotation.cpp:746
 msgid "Reflexive"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:751
+#: ../src/backend/filters/annotation.cpp:749
 msgid "Measure interor (enabled) or exterior angle (disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:756
+#: ../src/backend/filters/annotation.cpp:754
 msgid "Show Angle"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:760
+#: ../src/backend/filters/annotation.cpp:758
 msgid "Display angle text (when enabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:770
+#: ../src/backend/filters/annotation.cpp:768
 msgid "Size of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:788
+#: ../src/backend/filters/annotation.cpp:786
 msgid "Digit format"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:792
+#: ../src/backend/filters/annotation.cpp:790
 msgid ""
 "Format of angle text; # for numeral position, '.' for separator, eg ##.## "
 "gives 12.34"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:798
-#: ../src/backend/filters/annotation.cpp:886
+#: ../src/backend/filters/annotation.cpp:796
+#: ../src/backend/filters/annotation.cpp:881
 msgid "Sphere size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:802
-#: ../src/backend/filters/annotation.cpp:890
+#: ../src/backend/filters/annotation.cpp:800
+#: ../src/backend/filters/annotation.cpp:885
 msgid "Marker sphere size for manipulating tool"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:816
+#: ../src/backend/filters/annotation.cpp:814
 msgid "Ruler beginning 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:824
+#: ../src/backend/filters/annotation.cpp:822
 msgid "Ruler finish 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:857
+#: ../src/backend/filters/annotation.cpp:852
 msgid "Fixed ticks"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:860
+#: ../src/backend/filters/annotation.cpp:855
 msgid ""
 "Use fixed (enabled) number of text markers, or one every fixed distance "
 "(disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:867
+#: ../src/backend/filters/annotation.cpp:862
 msgid "Num Ticks"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:870
+#: ../src/backend/filters/annotation.cpp:865
 msgid "Number of tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:877
+#: ../src/backend/filters/annotation.cpp:872
 msgid "Tick Spacing"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:880
+#: ../src/backend/filters/annotation.cpp:875
 msgid "Distance between tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:906
+#: ../src/backend/filters/annotation.cpp:899
 msgid "Colour for ruler and ticks"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:460
+#: ../src/backend/filters/ionDownsample.cpp:445
 msgid "By Count"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:463
+#: ../src/backend/filters/ionDownsample.cpp:448
 msgid "Sample up to a fixed number of ions"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:469
+#: ../src/backend/filters/ionDownsample.cpp:454
 msgid "Per Species"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:473
+#: ../src/backend/filters/ionDownsample.cpp:458
 msgid "Use species specific (from ranging) sampling values"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:478
-msgid "Sampling rates"
+#: ../src/backend/filters/ionDownsample.cpp:487
+msgid "Sampling value for species"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:501
-msgid "Sampling value for species"
+#: ../src/backend/filters/ionDownsample.cpp:495
+#: ../src/backend/filters/ionDownsample.cpp:519
+msgid "Sampling rates"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:513
+#: ../src/backend/filters/ionDownsample.cpp:503
 msgid "Output Count"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:516
+#: ../src/backend/filters/ionDownsample.cpp:506
 msgid "Sample up to this value of points"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:521
+#: ../src/backend/filters/ionDownsample.cpp:511
 msgid "Out Fraction"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:525
+#: ../src/backend/filters/ionDownsample.cpp:515
 msgid "Sample this fraction of points"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:669
-msgid "Downsample Aborted"
-msgstr ""
-
-#: ../src/backend/filters/ionDownsample.cpp:671
-msgid "Insuffient memory for downsample"
-msgstr ""
-
 #: ../src/backend/filters/ionInfo.cpp:30
 msgid "Rectilinear"
 msgstr ""
@@ -4213,24 +4141,24 @@ msgstr ""
 msgid "Normalise count data"
 msgstr ""
 
-#: ../src/backend/filters/ionInfo.cpp:425
+#: ../src/backend/filters/ionInfo.cpp:421
+msgid "Ion data"
+msgstr ""
+
+#: ../src/backend/filters/ionInfo.cpp:426
 msgid "Volume"
 msgstr ""
 
-#: ../src/backend/filters/ionInfo.cpp:428
+#: ../src/backend/filters/ionInfo.cpp:429
 msgid "Compute volume for point data"
 msgstr ""
 
-#: ../src/backend/filters/ionInfo.cpp:443
+#: ../src/backend/filters/ionInfo.cpp:444
 msgid "Select volume counting technique"
 msgstr ""
 
-#: ../src/backend/filters/ionInfo.cpp:539
-msgid "Insufficient memory for operation"
-msgstr ""
-
-#: ../src/backend/filters/ionInfo.cpp:543
-msgid "Bug? Problem with qhull library, cannot run convex hull."
+#: ../src/backend/filters/ionInfo.cpp:457
+msgid "Volume data"
 msgstr ""
 
 #: ../src/backend/filters/dataLoad.cpp:56
@@ -4257,336 +4185,340 @@ msgstr ""
 msgid "ATO Data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:242
+#: ../src/backend/filters/dataLoad.cpp:238
 msgid " does not exist"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:280
-#: ../src/backend/filters/dataLoad.cpp:293
-#: ../src/backend/filters/dataLoad.cpp:336
-#: ../src/backend/filters/dataLoad.cpp:347
-#: ../src/backend/filters/dataLoad.cpp:408
+#: ../src/backend/filters/dataLoad.cpp:276
+#: ../src/backend/filters/dataLoad.cpp:289
+#: ../src/backend/filters/dataLoad.cpp:332
+#: ../src/backend/filters/dataLoad.cpp:343
+#: ../src/backend/filters/dataLoad.cpp:404
 msgid "Error loading file: "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:310
+#: ../src/backend/filters/dataLoad.cpp:306
 msgid "Sampling is active, loaded "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:311
+#: ../src/backend/filters/dataLoad.cpp:307
 msgid " available."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:319
+#: ../src/backend/filters/dataLoad.cpp:315
 msgid "Loaded entire dataset, "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:319
-#: ../src/backend/filters/dataLoad.cpp:418
+#: ../src/backend/filters/dataLoad.cpp:315
+#: ../src/backend/filters/dataLoad.cpp:414
 msgid " points."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:362
+#: ../src/backend/filters/dataLoad.cpp:358
 msgid ""
 "Data file contained incorrect number of columns -- should be 3 or 4, was "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:417
+#: ../src/backend/filters/dataLoad.cpp:413
 msgid "Loaded dataset, "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:449
+#: ../src/backend/filters/dataLoad.cpp:445
 msgid ""
 "Warning:One or more bounds of the loaded data approaches the limits of "
 "numerical stability for the internal data type(magnitude too large). "
 "Consider rescaling data before loading"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:481
-#: ../src/backend/filters/rangeFile.cpp:567
+#: ../src/backend/filters/dataLoad.cpp:469
+#: ../src/backend/filters/dataLoad.cpp:490
+#: ../src/backend/filters/rangeFile.cpp:569
+#: ../src/backend/filters/rangeFile.cpp:589
 msgid "File"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:482
+#: ../src/backend/filters/dataLoad.cpp:470
 msgid "File from which to load data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:493
+#: ../src/backend/filters/dataLoad.cpp:473
+msgid ""
+"Readable files (*.xml, *.pos, *.txt,*.csv, *.ato)|*.xml;*.pos;*.txt;*.csv;*."
+"ato|All Files|*"
+msgstr ""
+
+#: ../src/backend/filters/dataLoad.cpp:483
 msgid "File type"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:495
+#: ../src/backend/filters/dataLoad.cpp:485
 msgid "Type of file to be loaded"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:509
+#: ../src/backend/filters/dataLoad.cpp:500
 msgid "Entries per point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:510
+#: ../src/backend/filters/dataLoad.cpp:501
 msgid "Number of decimal values in file per 3D point (normally 4)"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:529
+#: ../src/backend/filters/dataLoad.cpp:520
 msgid "File \"Endianness\""
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:530
+#: ../src/backend/filters/dataLoad.cpp:521
 msgid "On-disk data storage format. If file won't load, just try each"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:555
+#: ../src/backend/filters/dataLoad.cpp:546
 msgid "Relative offset of each entry in file for point's X position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:563
+#: ../src/backend/filters/dataLoad.cpp:554
 msgid "Relative offset of each entry in file for point's Y position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:571
+#: ../src/backend/filters/dataLoad.cpp:562
 msgid "Relative offset of each entry in file for point's Z position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:579
+#: ../src/backend/filters/dataLoad.cpp:570
 msgid ""
 "Relative offset of each entry in file to use for scalar value of 3D point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:582
+#: ../src/backend/filters/dataLoad.cpp:573
 msgid "Value Label"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:586
+#: ../src/backend/filters/dataLoad.cpp:577
 msgid "Name for the scalar value associated with each point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:589
+#: ../src/backend/filters/dataLoad.cpp:580
 msgid "Format params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:595
+#: ../src/backend/filters/dataLoad.cpp:586
 msgid "Enabled"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:599
+#: ../src/backend/filters/dataLoad.cpp:590
 msgid "Load this file?"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:610
+#: ../src/backend/filters/dataLoad.cpp:601
 msgid "Sample data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:613
+#: ../src/backend/filters/dataLoad.cpp:604
 msgid ""
 "Perform random selection on file contents, instead of loading entire file"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:620
+#: ../src/backend/filters/dataLoad.cpp:611
 msgid "Load Limit (MB)"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:623
+#: ../src/backend/filters/dataLoad.cpp:614
 msgid "Limit for size of data to load"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:630
+#: ../src/backend/filters/dataLoad.cpp:621
 msgid "Monitor"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:634
+#: ../src/backend/filters/dataLoad.cpp:625
 msgid ""
 "Watch file timestamp to track changes to file contents from other programs"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:636
+#: ../src/backend/filters/dataLoad.cpp:629
 msgid "Load params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:646
+#: ../src/backend/filters/dataLoad.cpp:636
 msgid "Default colour "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:649
+#: ../src/backend/filters/dataLoad.cpp:639
 msgid "Default colour for points, if not overridden by other filters"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:654
+#: ../src/backend/filters/dataLoad.cpp:644
 msgid "Draw Size"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:657
+#: ../src/backend/filters/dataLoad.cpp:647
 msgid "Default size for points, if not overridden by other filters"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:125
+#: ../src/backend/filters/spectrumPlot.cpp:122
 msgid "Extrema"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:174
+#: ../src/backend/filters/spectrumPlot.cpp:171
 msgid "count"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:259
+#: ../src/backend/filters/spectrumPlot.cpp:256
 msgid "Mixed data"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:400
+#: ../src/backend/filters/spectrumPlot.cpp:390
 msgid "Step size for spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:409
+#: ../src/backend/filters/spectrumPlot.cpp:395
 msgid "Auto Min/max"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:413
+#: ../src/backend/filters/spectrumPlot.cpp:399
 msgid "Automatically compute spectrum upper and lower bound"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:418
+#: ../src/backend/filters/spectrumPlot.cpp:404
 msgid "Min"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:421
+#: ../src/backend/filters/spectrumPlot.cpp:407
 msgid "Starting position for spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:426
+#: ../src/backend/filters/spectrumPlot.cpp:412
 msgid "Max"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:429
+#: ../src/backend/filters/spectrumPlot.cpp:415
 msgid "Ending position for spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:437
+#: ../src/backend/filters/spectrumPlot.cpp:423
 msgid "Logarithmic"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:440
+#: ../src/backend/filters/spectrumPlot.cpp:426
 msgid "Convert the plot to logarithmic mode"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:462
+#: ../src/backend/filters/spectrumPlot.cpp:448
 msgid "Visual style of plot"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:475
+#: ../src/backend/filters/spectrumPlot.cpp:455
 msgid "Colour of plotted spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:709
-msgid "Insufficient memory for spectrum filter."
-msgstr ""
-
-#: ../src/backend/filters/spectrumPlot.cpp:711
-msgid "Bad bincount value in spectrum filter."
-msgstr ""
-
-#: ../src/backend/filters/rangeFile.cpp:149
+#: ../src/backend/filters/rangeFile.cpp:151
 msgid "Pre-Allocate"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:280 ../src/backend/filter.cpp:46
+#: ../src/backend/filters/rangeFile.cpp:282 ../src/backend/filter.cpp:48
 msgid "Range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:569
+#: ../src/backend/filters/rangeFile.cpp:572
 msgid "File to use for range data"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:581
+#: ../src/backend/filters/rangeFile.cpp:582
 msgid "Drop unranged"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:583
+#: ../src/backend/filters/rangeFile.cpp:584
 msgid "Remove unranged points when generating output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:603
+#: ../src/backend/filters/rangeFile.cpp:594
+msgid "Legend"
+msgstr ""
+
+#: ../src/backend/filters/rangeFile.cpp:596
+msgid "Display colour legend for enabled ions"
+msgstr ""
+
+#: ../src/backend/filters/rangeFile.cpp:600
+msgid "View"
+msgstr ""
+
+#: ../src/backend/filters/rangeFile.cpp:616
 msgid "All Ions"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:604
+#: ../src/backend/filters/rangeFile.cpp:617
 msgid "Enable/disable all ions at once"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:612
+#: ../src/backend/filters/rangeFile.cpp:625
 msgid "Species"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:619
+#: ../src/backend/filters/rangeFile.cpp:632
 msgid "IonID "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:620
+#: ../src/backend/filters/rangeFile.cpp:633
 msgid "Enable/disable specified ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:633
+#: ../src/backend/filters/rangeFile.cpp:643
 msgid "Active Ion "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:635
+#: ../src/backend/filters/rangeFile.cpp:645
 msgid "If true, ion is used in output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:649
+#: ../src/backend/filters/rangeFile.cpp:655
 msgid "Colour "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:652
+#: ../src/backend/filters/rangeFile.cpp:659
 msgid "Colour used to represent ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:676
+#: ../src/backend/filters/rangeFile.cpp:682
 msgid "All Ranges"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:677
+#: ../src/backend/filters/rangeFile.cpp:683
 msgid "Enable/disable all ranges"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:695
+#: ../src/backend/filters/rangeFile.cpp:698
 msgid "Active Rng "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:698
+#: ../src/backend/filters/rangeFile.cpp:701
 msgid ""
 "Enable/disable specified range (ion must also be enabled to activiate range)"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:702
+#: ../src/backend/filters/rangeFile.cpp:705
 msgid "Ion "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:705
+#: ../src/backend/filters/rangeFile.cpp:708
 msgid "Name of ion associate to this range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:714
+#: ../src/backend/filters/rangeFile.cpp:717
 msgid "Start rng "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:717
+#: ../src/backend/filters/rangeFile.cpp:720
 msgid "Start value for range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:722
+#: ../src/backend/filters/rangeFile.cpp:725
 msgid "End rng "
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:725
+#: ../src/backend/filters/rangeFile.cpp:728
 msgid "Stopping value for range`"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:1029
-msgid "Ranging aborted by user"
-msgstr ""
-
-#: ../src/backend/filters/rangeFile.cpp:1031
-msgid "Insufficient memory for range"
-msgstr ""
-
 #: ../src/backend/state.cpp:137
 msgid ""
 "This file is a \"state\" file for the 3Depict program, and stores "
@@ -4598,136 +4530,130 @@ msgstr ""
 msgid "Failed to allocate parser"
 msgstr ""
 
-#: ../src/backend/state.cpp:326
+#: ../src/backend/state.cpp:325
 msgid ""
 "Unable to retrieve root node in input state file... Is this really a non-"
 "empty XML file?"
 msgstr ""
 
-#: ../src/backend/state.cpp:333
+#: ../src/backend/state.cpp:332
 msgid "Base state node missing. Is this really a state XML file??"
 msgstr ""
 
-#: ../src/backend/state.cpp:362
+#: ../src/backend/state.cpp:361
 msgid "State was created by a newer version of this program.. "
 msgstr ""
 
-#: ../src/backend/state.cpp:363
+#: ../src/backend/state.cpp:362
 msgid "file reading will continue, but may fail."
 msgstr ""
 
-#: ../src/backend/state.cpp:368
+#: ../src/backend/state.cpp:367
 msgid ""
 "Warning, unparseable version number in state file. File reading will "
 "continue, but may fail"
 msgstr ""
 
-#: ../src/backend/state.cpp:375
+#: ../src/backend/state.cpp:374
 msgid "Unable to find the \"writer\" node"
 msgstr ""
 
-#: ../src/backend/state.cpp:385
+#: ../src/backend/state.cpp:384
 msgid "Unable to find the \"backcolour\" node."
 msgstr ""
 
-#: ../src/backend/state.cpp:392
+#: ../src/backend/state.cpp:391
 msgid "\"backcolour\" node missing \"r\" value."
 msgstr ""
 
-#: ../src/backend/state.cpp:397
+#: ../src/backend/state.cpp:396
 msgid "Unable to interpret \"backColour\" node's \"r\" value."
 msgstr ""
 
-#: ../src/backend/state.cpp:405
+#: ../src/backend/state.cpp:404
 msgid "\"backcolour\" node missing \"g\" value."
 msgstr ""
 
-#: ../src/backend/state.cpp:411
+#: ../src/backend/state.cpp:410
 msgid "Unable to interpret \"backColour\" node's \"g\" value."
 msgstr ""
 
-#: ../src/backend/state.cpp:419
+#: ../src/backend/state.cpp:418
 msgid "\"backcolour\" node missing \"b\" value."
 msgstr ""
 
-#: ../src/backend/state.cpp:425
+#: ../src/backend/state.cpp:424
 msgid "Unable to interpret \"backColour\" node's \"b\" value."
 msgstr ""
 
-#: ../src/backend/state.cpp:432
+#: ../src/backend/state.cpp:431
 msgid "\"backcolour\"s rgb values must be in range [0,1]"
 msgstr ""
 
-#: ../src/backend/state.cpp:460
+#: ../src/backend/state.cpp:459
 msgid "Unable to find or interpret \"showaxis\" node"
 msgstr ""
 
-#: ../src/backend/state.cpp:504
+#: ../src/backend/state.cpp:503
 msgid "Unable to locate \"filtertree\" node."
 msgstr ""
 
-#: ../src/backend/state.cpp:520
+#: ../src/backend/state.cpp:519
 msgid "Cameras section missing \"active\" node."
 msgstr ""
 
-#: ../src/backend/state.cpp:528
+#: ../src/backend/state.cpp:527
 msgid "Unable to find property \"value\"  for \"cameras->active\" node."
 msgstr ""
 
-#: ../src/backend/state.cpp:534
+#: ../src/backend/state.cpp:533
 msgid "Unable to interpret property \"value\"  for \"cameras->active\" node."
 msgstr ""
 
-#: ../src/backend/state.cpp:553
+#: ../src/backend/state.cpp:552
 msgid "Failed to interpret camera state for camera : "
 msgstr ""
 
-#: ../src/backend/state.cpp:561
+#: ../src/backend/state.cpp:560
 msgid "Unable to interpret the camera type for camera : "
 msgstr ""
 
-#: ../src/backend/state.cpp:597
+#: ../src/backend/state.cpp:596
 msgid "Unable to locate stash name for stash "
 msgstr ""
 
-#: ../src/backend/state.cpp:604
+#: ../src/backend/state.cpp:603
 msgid "Empty stash name for stash "
 msgstr ""
 
-#: ../src/backend/state.cpp:613
+#: ../src/backend/state.cpp:612
 msgid "No filter tree for stash:"
 msgstr ""
 
-#: ../src/backend/state.cpp:619
+#: ../src/backend/state.cpp:618
 msgid "For stash "
 msgstr ""
 
-#: ../src/backend/state.cpp:651
+#: ../src/backend/state.cpp:650
 msgid "Unrecognised effect :"
 msgstr ""
 
-#: ../src/backend/state.cpp:661
+#: ../src/backend/state.cpp:660
 msgid "Duplicate effect found"
 msgstr ""
 
-#: ../src/backend/state.cpp:661
+#: ../src/backend/state.cpp:660
 msgid " cannot use."
 msgstr ""
 
-#: ../src/backend/state.cpp:671
+#: ../src/backend/state.cpp:670
 msgid "Error reading effect : "
 msgstr ""
 
-#: ../src/backend/state.cpp:789
+#: ../src/backend/state.cpp:866
 msgid "-merge"
 msgstr ""
 
-#: ../src/backend/state.cpp:794
-msgid ""
-" Unable to merge stashes correctly. This is improbable, so please report "
-"this."
-msgstr ""
-
 #: ../src/backend/filtertreeAnalyse.cpp:199
 msgid ""
 "Parent filter has no output, but filter requires input -- there is no point "
@@ -4780,174 +4706,211 @@ msgstr ""
 msgid "Filter missing needed parent"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:554
+#: ../src/backend/filtertreeAnalyse.cpp:555
 msgid "Composition results possibly altered"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:555
+#: ../src/backend/filtertreeAnalyse.cpp:556
 msgid ""
 "Filters and settings selected that could bias reported composition. Check to "
 "see if species biasing may occcur in the filter tree - this warning is "
 "provisional only."
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:40
+#: ../src/backend/APT/APTFileIO.cpp:43 ../src/backend/APT/APTFileIO.cpp:78
+#: ../src/backend/APT/APTFileIO.cpp:102
+msgid "Error opening file"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:44
+msgid "Only found header, no data"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:45
+msgid "Unable to reopen file after first scan"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:46
+msgid "Error whilst reading file contents"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:47 ../src/backend/APT/APTFileIO.cpp:48
+msgid "Unexpected file format"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:49
+msgid "Insufficient memory to continue"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:53
 msgid "Memory allocation failure on POS load"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:41
+#: ../src/backend/APT/APTFileIO.cpp:54
 msgid "Error opening pos file"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:42
+#: ../src/backend/APT/APTFileIO.cpp:55
 msgid "Pos file empty"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:43
+#: ../src/backend/APT/APTFileIO.cpp:56
 msgid "Pos file size appears to have non-integer number of entries"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:44
+#: ../src/backend/APT/APTFileIO.cpp:57
 msgid "Error reading from pos file (after open)"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:45
+#: ../src/backend/APT/APTFileIO.cpp:58
 msgid "Error - Found NaN in pos file"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:46
+#: ../src/backend/APT/APTFileIO.cpp:59
+msgid "Error - Found Inf in pos file"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:60
 msgid "Pos load aborted by interrupt."
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:66
+#: ../src/backend/APT/APTFileIO.cpp:79
 msgid "No numerical data found"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:67
+#: ../src/backend/APT/APTFileIO.cpp:80
 msgid "Error re-opening file, after first scan"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:68
+#: ../src/backend/APT/APTFileIO.cpp:81
 msgid "Unable to read file contents after open"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:70
+#: ../src/backend/APT/APTFileIO.cpp:82
+msgid "Error interpreting field in file"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:83
 msgid "Incorrect number of fields in file"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:71 ../src/backend/APT/APTFileIO.cpp:93
+#: ../src/backend/APT/APTFileIO.cpp:84 ../src/backend/APT/APTFileIO.cpp:106
 msgid "Unable to allocate memory to store data"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:90
+#: ../src/backend/APT/APTFileIO.cpp:103
 msgid "File is empty"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:91
+#: ../src/backend/APT/APTFileIO.cpp:104
 msgid "Filesize does not match expected format"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:92
+#: ../src/backend/APT/APTFileIO.cpp:105
 msgid "File version number not <4, as expected"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:94
+#: ../src/backend/APT/APTFileIO.cpp:107
 msgid "Unable to detect endian-ness in file"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:47
+#: ../src/backend/APT/APTRanges.cpp:48
 msgid "Error opening file, check name and permissions."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:48
+#: ../src/backend/APT/APTRanges.cpp:49
 msgid ""
 "Error interpreting range file header, expecting ion count and range count, "
 "respectively."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:49
+#: ../src/backend/APT/APTRanges.cpp:50
 msgid ""
 "Range file appears to be empty, check file is a proper range file and is not "
 "empty."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:50
+#: ../src/backend/APT/APTRanges.cpp:51
 msgid "Error reading the long name for ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:51
+#: ../src/backend/APT/APTRanges.cpp:52
 msgid "Error reading the short name for ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:52
+#: ../src/backend/APT/APTRanges.cpp:53
 msgid ""
 "Error reading colour data in the file, expecting 3 decimal values, space "
 "separated."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:53
+#: ../src/backend/APT/APTRanges.cpp:54
 msgid ""
 "Tried skipping to table separator line (line with dashes), but did not find "
 "it."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:54
+#: ../src/backend/APT/APTRanges.cpp:55
 msgid ""
 "Number of ions in the table header did not match the number specified at the "
 "start of the file"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:55
+#: ../src/backend/APT/APTRanges.cpp:56
 msgid ""
 "Unexpected failure whilst trying to skip over range lead-in data (bit before "
 "range start value)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:56
+#: ../src/backend/APT/APTRanges.cpp:57
 msgid ""
 "Range table had an incorrect number of entries, should be 2 or 3 + number of "
 "ranges"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:57
+#: ../src/backend/APT/APTRanges.cpp:58
 msgid "Unable to read range start and end values"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:58
+#: ../src/backend/APT/APTRanges.cpp:59
 msgid "Unable to read range table entry"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:59
+#: ../src/backend/APT/APTRanges.cpp:60
 msgid ""
 "Error reading file, unexpected format, are you sure it is a proper range "
 "file?"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:60
+#: ../src/backend/APT/APTRanges.cpp:61
 msgid ""
 "Too many ranges appeared to have range entries with no usable data (eg, all "
 "blank)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:61
+#: ../src/backend/APT/APTRanges.cpp:62
 msgid ""
 "Range file appears to contain malformed data, check things like start and "
 "ends of m/c are not equal or flipped."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:62
+#: ../src/backend/APT/APTRanges.cpp:63
 msgid "Range file appears to be inconsistent (eg, overlapping ranges)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:63
+#: ../src/backend/APT/APTRanges.cpp:64
 msgid "No ion name mapping found  for multiple ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:64
+#: ../src/backend/APT/APTRanges.cpp:65
 msgid "Polyatomic extension range matches multiple masses in first section"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:1387
+#: ../src/backend/APT/APTRanges.cpp:66
+msgid "Range file is exceedingly large. Refusing to open"
+msgstr ""
+
+#: ../src/backend/APT/APTRanges.cpp:1403
 msgid ""
 "Range headings do not match order of the ions listed in the name "
 "specifications. The name specification ordering will be used when reading "
@@ -4956,15 +4919,19 @@ msgid ""
 "Check range-species associations actually match what you expect."
 msgstr ""
 
-#: ../src/backend/filter.cpp:45
-msgid "Draw"
+#: ../src/backend/filter.cpp:46
+msgid "2D Plot"
 msgstr ""
 
 #: ../src/backend/filter.cpp:47
+msgid "Draw"
+msgstr ""
+
+#: ../src/backend/filter.cpp:49
 msgid "Voxel"
 msgstr ""
 
-#: ../src/wx/wxcomponents.h:98
+#: ../src/wx/wxcomponents.h:82
 msgid "treeCtrl"
 msgstr ""
 
@@ -4972,7 +4939,7 @@ msgstr ""
 msgid "Ion. Transform"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.h:61
+#: ../src/backend/filters/ionColour.h:63
 msgid "Spectral Colour"
 msgstr ""
 
@@ -4988,7 +4955,7 @@ msgstr ""
 msgid "Ion info"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.h:136
+#: ../src/backend/filters/dataLoad.h:135
 msgid "Pos Data"
 msgstr ""
 
@@ -4996,7 +4963,7 @@ msgstr ""
 msgid "Ext. Program"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.h:89
+#: ../src/backend/filters/rangeFile.h:93
 msgid "Ranging"
 msgstr ""
 
diff --git a/translations/3Depict_de_DE.mo b/translations/3Depict_de_DE.mo
index cf1c383..36291f1 100644
Binary files a/translations/3Depict_de_DE.mo and b/translations/3Depict_de_DE.mo differ
diff --git a/translations/3Depict_de_DE.po b/translations/3Depict_de_DE.po
index 888bc71..8cee9e4 100644
--- a/translations/3Depict_de_DE.po
+++ b/translations/3Depict_de_DE.po
@@ -10,7 +10,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: 3Depict\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-04-12 18:12+0200\n"
+"POT-Creation-Date: 2014-08-23 15:32+0100\n"
 "PO-Revision-Date: 2012-07-09 08:21+0000\n"
 "Last-Translator: epix1234 <erich_s at gmx.de>\n"
 "Language-Team: German (Germany) (http://www.transifex.com/projects/p/3depict/"
@@ -21,25 +21,25 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1)\n"
 
-#: ../src/gl/cameras.cpp:598 ../src/gl/cameras.cpp:600
+#: ../src/gl/cameras.cpp:596
 msgid "Lock"
 msgstr "Sperren"
 
-#: ../src/gl/cameras.cpp:607 ../src/backend/filters/ionClip.cpp:526
-#: ../src/backend/filters/ionClip.cpp:548
-#: ../src/backend/filters/ionClip.cpp:570
-#: ../src/backend/filters/ionClip.cpp:610
-#: ../src/backend/filters/compositionProfile.cpp:1015
-#: ../src/backend/filters/compositionProfile.cpp:1056
-#: ../src/backend/filters/spatialAnalysis.cpp:599
-#: ../src/backend/filters/transform.cpp:1264
-#: ../src/backend/filters/transform.cpp:1291
-#: ../src/backend/filters/transform.cpp:1317
-#: ../src/backend/filters/annotation.cpp:569
+#: ../src/gl/cameras.cpp:603 ../src/backend/filters/ionClip.cpp:519
+#: ../src/backend/filters/ionClip.cpp:541
+#: ../src/backend/filters/ionClip.cpp:563
+#: ../src/backend/filters/ionClip.cpp:600
+#: ../src/backend/filters/compositionProfile.cpp:964
+#: ../src/backend/filters/compositionProfile.cpp:1002
+#: ../src/backend/filters/spatialAnalysis.cpp:774
+#: ../src/backend/filters/transform.cpp:1216
+#: ../src/backend/filters/transform.cpp:1243
+#: ../src/backend/filters/transform.cpp:1269
+#: ../src/backend/filters/annotation.cpp:563
 msgid "Origin"
 msgstr "Ursprung"
 
-#: ../src/gl/cameras.cpp:612 ../src/backend/filters/spatialAnalysis.cpp:518
+#: ../src/gl/cameras.cpp:611 ../src/backend/filters/spatialAnalysis.cpp:697
 msgid "Target"
 msgstr "Ziel"
 
@@ -47,12 +47,12 @@ msgstr "Ziel"
 msgid "Up Dir."
 msgstr "Up Dir."
 
-#: ../src/gl/cameras.cpp:625 ../src/gl/cameras.cpp:729
+#: ../src/gl/cameras.cpp:625 ../src/gl/cameras.cpp:728
 msgid "Perspective"
 msgstr "Perspektivisch"
 
-#: ../src/gl/cameras.cpp:627 ../src/gl/cameras.cpp:731
-#: ../src/gui/mainFrame.cpp:5396
+#: ../src/gl/cameras.cpp:627 ../src/gl/cameras.cpp:730
+#: ../src/gui/mainFrame.cpp:5134
 msgid "Orthogonal"
 msgstr "Orthogonal"
 
@@ -60,169 +60,137 @@ msgstr "Orthogonal"
 msgid "Projection"
 msgstr "Projektion"
 
-#: ../src/gl/cameras.cpp:639
+#: ../src/gl/cameras.cpp:640
 msgid "Field of View (deg)"
 msgstr "Bildausschnitt"
 
-#: ../src/gl/cameras.cpp:645
+#: ../src/gl/cameras.cpp:646
 msgid "View size"
 msgstr "Anzeigegröße"
 
-#: ../src/wx/wxcomponents.cpp:441 ../src/gui/dialogs/ExportRngDialog.cpp:88
-#: ../src/gui/dialogs/prefDialog.cpp:110
-msgid "Param"
-msgstr "Param."
-
-#: ../src/wx/wxcomponents.cpp:442 ../src/gui/dialogs/ExportRngDialog.cpp:89
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:109
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:356
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1186
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1211
-#: ../src/gui/dialogs/prefDialog.cpp:111 ../src/gui/mainFrame.cpp:5849
-#: ../src/gui/mainFrame.cpp:5854 ../src/backend/filters/dataLoad.cpp:575
-msgid "Value"
-msgstr "Wert"
-
-#: ../src/wx/wxcomponents.cpp:655
+#: ../src/wx/wxcomponents.cpp:187
 msgid "Save Data..."
 msgstr "Datei speichern..."
 
-#: ../src/wx/wxcomponents.cpp:656
+#: ../src/wx/wxcomponents.cpp:188
 msgid "Text File (*.txt)|*.txt|All Files (*)|*"
 msgstr "Text Datei (*.txt)|*.txt|Alle Dateien (*)|*"
 
-#: ../src/wx/wxcomponents.cpp:668
+#: ../src/wx/wxcomponents.cpp:200
 msgid "Error saving file. Check output dir is writable."
 msgstr ""
 "Fehler beim Schreiben der Datei. Stellen Sie sicher, dass das "
 "Zielverzeichnis nicht schreibgeschüzt ist."
 
-#: ../src/wx/wxcomponents.cpp:668 ../src/gui/dialogs/ExportRngDialog.cpp:170
-#: ../src/gui/mainFrame.cpp:1422 ../src/gui/mainFrame.cpp:1548
-#: ../src/gui/mainFrame.cpp:1583 ../src/gui/mainFrame.cpp:1659
-#: ../src/gui/mainFrame.cpp:2213 ../src/gui/mainFrame.cpp:2279
-#: ../src/gui/mainFrame.cpp:2371 ../src/gui/mainFrame.cpp:2486
+#: ../src/wx/wxcomponents.cpp:200 ../src/gui/dialogs/ExportRngDialog.cpp:170
+#: ../src/gui/mainFrame.cpp:1446 ../src/gui/mainFrame.cpp:1572
+#: ../src/gui/mainFrame.cpp:1621 ../src/gui/mainFrame.cpp:1697
+#: ../src/gui/mainFrame.cpp:2253 ../src/gui/mainFrame.cpp:2319
+#: ../src/gui/mainFrame.cpp:2411 ../src/gui/mainFrame.cpp:2526
 msgid "Save error"
 msgstr "Fehler speichern"
 
-#: ../src/common/basics.cpp:62 ../src/backend/APT/APTFileIO.cpp:65
-#: ../src/backend/APT/APTFileIO.cpp:89
-msgid "Error opening file"
-msgstr "Fehler beim Öffnen der Datei"
-
-#: ../src/common/basics.cpp:63
-msgid "Error whilst reading file contents"
-msgstr "Fehler beim Lesen des Dateiinhaltes"
-
-#: ../src/common/basics.cpp:64 ../src/backend/APT/APTFileIO.cpp:69
-msgid "Error interpreting field in file"
-msgstr "Fehler beim Interpretieren eine Feldes in der Datei"
-
-#: ../src/common/basics.cpp:65
-msgid "Inconsistent number of columns found"
-msgstr "Inkonsistente Anzahl an Spalten gefunden"
-
-#: ../src/common/basics.cpp:197
+#: ../src/common/basics.cpp:183
 msgid "in the future?"
 msgstr "in Zukunft?"
 
-#: ../src/common/basics.cpp:248
+#: ../src/common/basics.cpp:234
 msgid "a decade ago"
 msgstr "vor zehn Jahren"
 
-#: ../src/common/basics.cpp:249
+#: ../src/common/basics.cpp:235
 msgid "a year ago"
 msgstr "vor einem Jahr"
 
-#: ../src/common/basics.cpp:250
+#: ../src/common/basics.cpp:236
 msgid "a month ago"
 msgstr "vor einem Monat"
 
-#: ../src/common/basics.cpp:251
+#: ../src/common/basics.cpp:237
 msgid "a week ago"
 msgstr "vor einer Woche"
 
-#: ../src/common/basics.cpp:252
+#: ../src/common/basics.cpp:238
 msgid "a day ago"
 msgstr "gestern"
 
-#: ../src/common/basics.cpp:253
+#: ../src/common/basics.cpp:239
 msgid "an hour ago"
 msgstr "vor einer Stunde"
 
-#: ../src/common/basics.cpp:254
+#: ../src/common/basics.cpp:240
 msgid "45 minutes ago"
 msgstr "vor 45 Minuten"
 
-#: ../src/common/basics.cpp:255
+#: ../src/common/basics.cpp:241
 msgid "30 minutes ago"
 msgstr "vor 30 Minuten"
 
-#: ../src/common/basics.cpp:256
+#: ../src/common/basics.cpp:242
 msgid "20 minutes ago"
 msgstr "vor 20 Minuten"
 
-#: ../src/common/basics.cpp:257
+#: ../src/common/basics.cpp:243
 msgid "15 minutes ago"
 msgstr "vor 15 Minuten"
 
-#: ../src/common/basics.cpp:258
+#: ../src/common/basics.cpp:244
 msgid "10 minutes ago"
 msgstr "vor 10 Minuten"
 
-#: ../src/common/basics.cpp:259
+#: ../src/common/basics.cpp:245
 msgid "5 minutes ago"
 msgstr "vor 5 Minuten"
 
-#: ../src/common/basics.cpp:260
+#: ../src/common/basics.cpp:246
 msgid "a minute ago"
 msgstr "vor einer Minute"
 
-#: ../src/common/basics.cpp:261
+#: ../src/common/basics.cpp:247
 msgid "30 seconds ago"
 msgstr "vor 30 Sekunden"
 
-#: ../src/common/basics.cpp:262
+#: ../src/common/basics.cpp:248
 msgid "10 seconds ago"
 msgstr "vor 10 Sekunden"
 
-#: ../src/common/basics.cpp:263
+#: ../src/common/basics.cpp:249
 msgid "a second ago"
 msgstr "vor einer Sekunde"
 
-#: ../src/common/basics.cpp:268
+#: ../src/common/basics.cpp:254
 msgid "a few decades ago"
 msgstr "vor einigen Dekaden"
 
-#: ../src/common/basics.cpp:269
+#: ../src/common/basics.cpp:255
 msgid "a few years ago"
 msgstr "vor einigen Jahren"
 
-#: ../src/common/basics.cpp:270
+#: ../src/common/basics.cpp:256
 msgid "a few months ago"
 msgstr "vor einigen Monaten"
 
-#: ../src/common/basics.cpp:271
+#: ../src/common/basics.cpp:257
 msgid "a few weeks ago"
 msgstr "vor einigen Wochen"
 
-#: ../src/common/basics.cpp:272
+#: ../src/common/basics.cpp:258
 msgid "a few days ago"
 msgstr "vor einigen Tagen"
 
-#: ../src/common/basics.cpp:273
+#: ../src/common/basics.cpp:259
 msgid "a few hours ago"
 msgstr "vor einigen Stunden"
 
-#: ../src/common/basics.cpp:280
+#: ../src/common/basics.cpp:266
 msgid "a few minutes ago"
 msgstr "vor einigen Minuten"
 
-#: ../src/common/basics.cpp:283
+#: ../src/common/basics.cpp:269
 msgid "a few seconds ago"
 msgstr "vor einigen Sekunden"
 
-#: ../src/common/basics.cpp:310
+#: ../src/common/basics.cpp:296
 msgid "moments ago"
 msgstr "kürzlich"
 
@@ -258,42 +226,45 @@ msgstr "Blau"
 msgid "Pseudo-Random"
 msgstr "Pseudo-Random"
 
-#: ../src/gui/glPane.cpp:670
+#: ../src/common/constants.cpp:22
+msgid ""
+"Range Files (*.rng; *.env; *.rrng)|*.rng;*.env;*.rrng;*.RRNG;*.RNG;*.ENV|RNG "
+"File (*.rng)|*.rng;*.RNG|Environment File (*.env)|*.env;*.ENV|RRNG Files (*."
+"rrng)|*.rrng;*.RRNG|All Files (*)|*"
+msgstr ""
+
+#: ../src/gui/glPane.cpp:637
 msgid "Use shift/ctrl-space or double tap to alter reset axis"
 msgstr ""
 "Verwenden Sie Shift / ⌘-Leertaste oder doppeltippen, um Achsen "
 "zurückzusetzen oder zu verändern"
 
-#: ../src/gui/glPane.cpp:934
+#: ../src/gui/glPane.cpp:910
 msgid "Image progress"
 msgstr "Bild Fortschritt"
 
-#: ../src/gui/glPane.cpp:935
+#: ../src/gui/glPane.cpp:911
 msgid "Rendering tiles..."
 msgstr "Rendering tiles..."
 
-#: ../src/gui/glPane.cpp:969
-msgid "Tile "
-msgstr "Tile "
-
-#: ../src/gui/glPane.cpp:969 ../src/gui/glPane.cpp:1080
-#: ../src/gui/mainFrame.cpp:4279 ../src/gui/mainFrame.cpp:4283
-#: ../src/gui/mainFrame.cpp:4296 ../src/backend/filters/dataLoad.cpp:311
-msgid " of "
-msgstr " von "
-
-#: ../src/gui/glPane.cpp:1041
+#: ../src/gui/glPane.cpp:1097
 msgid "Animation progress"
 msgstr "Animation-Fortschritt"
 
-#: ../src/gui/glPane.cpp:1042
+#: ../src/gui/glPane.cpp:1098
 msgid "Rendering sequence..."
 msgstr "Renderreihenfolge..."
 
-#: ../src/gui/glPane.cpp:1080
+#: ../src/gui/glPane.cpp:1136
 msgid "Saving Image "
 msgstr "Speichere Bild "
 
+#: ../src/gui/glPane.cpp:1136 ../src/gui/mainFrame.cpp:4309
+#: ../src/gui/mainFrame.cpp:4313 ../src/gui/mainFrame.cpp:4326
+#: ../src/backend/filters/dataLoad.cpp:307
+msgid " of "
+msgstr " von "
+
 #: ../src/gui/dialogs/ExportRngDialog.cpp:40
 msgid "Range Sources"
 msgstr "Range Sources"
@@ -307,15 +278,29 @@ msgid "Source Filter"
 msgstr "Source Filter"
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:54
+#: ../src/backend/filters/rangeFile.cpp:665
 msgid "Ions"
 msgstr "Ionen"
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:55
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1606
-#: ../src/backend/filters/rangeFile.cpp:729
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1586
+#: ../src/backend/filters/voxelise.cpp:876
+#: ../src/backend/filters/rangeFile.cpp:732
 msgid "Ranges"
 msgstr "Ranges"
 
+#: ../src/gui/dialogs/ExportRngDialog.cpp:88
+msgid "Param"
+msgstr "Param."
+
+#: ../src/gui/dialogs/ExportRngDialog.cpp:89
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:105
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:352
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1173
+#: ../src/backend/filters/dataLoad.cpp:566
+msgid "Value"
+msgstr "Wert"
+
 #: ../src/gui/dialogs/ExportRngDialog.cpp:90
 msgid "Value2"
 msgstr "Wert2"
@@ -329,7 +314,7 @@ msgid "Num Ranges"
 msgstr "Num Ranges"
 
 #: ../src/gui/dialogs/ExportRngDialog.cpp:116
-#: ../src/gui/dialogs/rangeEditDialog.cpp:710 ../src/backend/filter.cpp:43
+#: ../src/gui/dialogs/rangeEditDialog.cpp:695 ../src/backend/filter.cpp:44
 msgid "Ion"
 msgstr "Ion"
 
@@ -341,7 +326,7 @@ msgstr "Range Anfang"
 msgid "Range end"
 msgstr "Range Ende"
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2315
+#: ../src/gui/dialogs/ExportRngDialog.cpp:151 ../src/gui/mainFrame.cpp:2355
 msgid "Save pos..."
 msgstr "pos speichern..."
 
@@ -349,10 +334,10 @@ msgstr "pos speichern..."
 msgid "ORNL format RNG (*.rng)|*.rng|All Files (*)|*"
 msgstr "ORNL Format RNG (*.rng)|*.rng|Alle Dateien (*)|*"
 
-#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1422
-#: ../src/gui/mainFrame.cpp:1584 ../src/gui/mainFrame.cpp:1659
-#: ../src/gui/mainFrame.cpp:2214 ../src/gui/mainFrame.cpp:2372
-#: ../src/gui/mainFrame.cpp:2487
+#: ../src/gui/dialogs/ExportRngDialog.cpp:167 ../src/gui/mainFrame.cpp:1446
+#: ../src/gui/mainFrame.cpp:1622 ../src/gui/mainFrame.cpp:1697
+#: ../src/gui/mainFrame.cpp:2254 ../src/gui/mainFrame.cpp:2412
+#: ../src/gui/mainFrame.cpp:2527
 msgid "Unable to save. Check output destination can be written to."
 msgstr ""
 "Speichern nicht möglich. Bitte überprüfen Sie ob der Ausgabepfad "
@@ -378,86 +363,84 @@ msgstr ""
 msgid "e.g. H2O"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:575
-#: ../src/gui/dialogs/rangeEditDialog.cpp:709 ../src/gui/mainFrame.cpp:6061
-#: ../src/backend/filter.cpp:44
+#: ../src/gui/dialogs/rangeEditDialog.cpp:560
+#: ../src/gui/dialogs/rangeEditDialog.cpp:694 ../src/gui/mainFrame.cpp:5800
+#: ../src/backend/filter.cpp:45
 msgid "Plot"
 msgstr "Plot"
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:576
+#: ../src/gui/dialogs/rangeEditDialog.cpp:561
 msgid "Short Name"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:577
+#: ../src/gui/dialogs/rangeEditDialog.cpp:562
 msgid "Long Name"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:578
-#: ../src/backend/filters/voxelise.cpp:1022
-#: ../src/backend/filters/compositionProfile.cpp:1156
-#: ../src/backend/filters/annotation.cpp:903
-#: ../src/backend/filters/spectrumPlot.cpp:472
+#: ../src/gui/dialogs/rangeEditDialog.cpp:563
+#: ../src/backend/filters/voxelise.cpp:1020
+#: ../src/backend/filters/compositionProfile.cpp:1100
+#: ../src/backend/filters/annotation.cpp:896
+#: ../src/backend/filters/spectrumPlot.cpp:452
 msgid "Colour"
 msgstr "Farbe"
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:711
-#: ../src/backend/filters/annotation.cpp:606
-#: ../src/backend/filters/annotation.cpp:645
-#: ../src/backend/filters/annotation.cpp:812
+#: ../src/gui/dialogs/rangeEditDialog.cpp:696
+#: ../src/backend/filters/annotation.cpp:600
+#: ../src/backend/filters/annotation.cpp:641
+#: ../src/backend/filters/annotation.cpp:810
 msgid "Start"
 msgstr "Anfang"
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:712
-#: ../src/backend/filters/annotation.cpp:614
-#: ../src/backend/filters/annotation.cpp:654
-#: ../src/backend/filters/annotation.cpp:820
+#: ../src/gui/dialogs/rangeEditDialog.cpp:697
+#: ../src/backend/filters/annotation.cpp:608
+#: ../src/backend/filters/annotation.cpp:650
+#: ../src/backend/filters/annotation.cpp:818
 msgid "End"
 msgstr "Ende"
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1275
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1278
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1259
 msgid "Range or ion?"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1276
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1279
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1260
 msgid "Select type to add"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1561
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1541
 msgid "Range Editor"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1565
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1545
 msgid "Enable or disable all overlays"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1566
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1546
 msgid "Entered overlays, use delete to remove"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1567
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1547
 msgid "Available plots for ranging"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1568
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1548
 msgid "Enter species to display as overlay, e.g. SiO2"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1569
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1549
 msgid "Editable ranges"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1570
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1550
 msgid "Editable ions"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1605
-#: ../src/gui/dialogs/animateFilterDialog.cpp:172
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1585
+#: ../src/gui/dialogs/animateFilterDialog.cpp:173
 msgid "Plots"
 msgstr ""
 
-#: ../src/gui/dialogs/rangeEditDialog.cpp:1607
+#: ../src/gui/dialogs/rangeEditDialog.cpp:1587
 msgid "Overlay"
 msgstr ""
 
@@ -473,8 +456,8 @@ msgstr ""
 msgid "Multiple autosave states were found; would you like to restore one?"
 msgstr ""
 
-#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:388
-#: ../src/backend/filter.cpp:391
+#: ../src/gui/dialogs/filterErrorDialog.cpp:37 ../src/backend/filter.cpp:435
+#: ../src/backend/filter.cpp:438
 msgid "Error"
 msgstr ""
 
@@ -487,46 +470,46 @@ msgstr ""
 msgid "Filter Errors"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:45
+#: ../src/gui/dialogs/StashDialog.cpp:46
 msgid "Stashes"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:48
+#: ../src/gui/dialogs/StashDialog.cpp:49
 msgid "Stashed Tree"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:50
+#: ../src/gui/dialogs/StashDialog.cpp:51
 msgid "Properties"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:86
+#: ../src/gui/dialogs/StashDialog.cpp:57
+msgid "Stash Name"
+msgstr "Stash Name"
+
+#: ../src/gui/dialogs/StashDialog.cpp:58
+msgid "Filter Count"
+msgstr "Filter Count"
+
+#: ../src/gui/dialogs/StashDialog.cpp:91
 msgid "Stashed Trees"
 msgstr "Stashed Trees"
 
-#: ../src/gui/dialogs/StashDialog.cpp:89
+#: ../src/gui/dialogs/StashDialog.cpp:94
 msgid "Erase stashed item"
 msgstr ""
 
-#: ../src/gui/dialogs/StashDialog.cpp:90
+#: ../src/gui/dialogs/StashDialog.cpp:95
 msgid "Filter view for current stash"
 msgstr "Filteransicht für den aktuellen Stash"
 
-#: ../src/gui/dialogs/StashDialog.cpp:91
+#: ../src/gui/dialogs/StashDialog.cpp:96
 msgid "Settings for selected filter in current stash"
 msgstr "Einstellungen für den ausgewählten Stash"
 
-#: ../src/gui/dialogs/StashDialog.cpp:92
+#: ../src/gui/dialogs/StashDialog.cpp:97
 msgid "Available stashes"
 msgstr "Verfügbare Stash"
 
-#: ../src/gui/dialogs/StashDialog.cpp:153
-msgid "Stash Name"
-msgstr "Stash Name"
-
-#: ../src/gui/dialogs/StashDialog.cpp:154
-msgid "Filter Count"
-msgstr "Filter Count"
-
 #: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:45
 msgid "Start Frame: "
 msgstr ""
@@ -539,57 +522,57 @@ msgstr ""
 msgid "From Table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:108
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:354
-#: ../src/gui/dialogs/animateFilterDialog.cpp:191
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:104
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:350
+#: ../src/gui/dialogs/animateFilterDialog.cpp:192
 msgid "Frame"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:244
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:240
 msgid "Select text file..."
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:245
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:241
 msgid "Text files (*.txt)|*.txt;|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:346
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:342
 msgid "String Keyframes"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:348
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:344
 msgid "Frame at which to start string sequence"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:349
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:345
 msgid "Frame offset for data start"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:350
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:346
 msgid "File to use as string data source, one value per row"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:351
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:347
 msgid "Select file to use as data source"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:352
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:348
 msgid "Use table below for data source"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:358
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:354
 msgid "Add new data rows to table, hold shift/cmd to insert multiple rows"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:359
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:355
 msgid "Remove selected strings from table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:360
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:356
 msgid "Abort value selection and return to previous window"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:361
+#: ../src/gui/dialogs/animateSubDialogs/stringKeyFrameDialog.cpp:357
 msgid "Accept data values"
 msgstr ""
 
@@ -610,12 +593,12 @@ msgid "Ramp"
 msgstr ""
 
 #: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:64
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1192
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1154
 msgid "Start Frame"
 msgstr ""
 
 #: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:66
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1193
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1155
 msgid "End Frame"
 msgstr ""
 
@@ -635,219 +618,221 @@ msgstr ""
 msgid "endColour"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:237
+#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:235
 msgid "Key Frame : Colour"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:239
+#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:237
 msgid "Colour at the start of the transtition"
 msgstr ""
 
-#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:240
+#: ../src/gui/dialogs/animateSubDialogs/colourKeyFrameDialog.cpp:238
 msgid "Colour at end of transition"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:91
+#: ../src/gui/dialogs/animateFilterDialog.cpp:92
 msgid "Oak-Ridge RNG"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:92
+#: ../src/gui/dialogs/animateFilterDialog.cpp:93
 msgid "Cameca/Ametek RRNG"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:93
+#: ../src/gui/dialogs/animateFilterDialog.cpp:94
 msgid "Cameca/Ametek ENV"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:151
+#: ../src/gui/dialogs/animateFilterDialog.cpp:152
 msgid "Key frames"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:152
+#: ../src/gui/dialogs/animateFilterDialog.cpp:153
 msgid "Output Data"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:153
+#: ../src/gui/dialogs/animateFilterDialog.cpp:154
 msgid "Filters and properties"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:159
+#: ../src/gui/dialogs/animateFilterDialog.cpp:160
 msgid "Dir : "
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:162
+#: ../src/gui/dialogs/animateFilterDialog.cpp:163
 msgid "Output only when refresh required"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:164
+#: ../src/gui/dialogs/animateFilterDialog.cpp:165
 msgid "Data Types:"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:165
+#: ../src/gui/dialogs/animateFilterDialog.cpp:166
 msgid "3D Images"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:166
+#: ../src/gui/dialogs/animateFilterDialog.cpp:167
 msgid "File Suffix: "
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:168
+#: ../src/gui/dialogs/animateFilterDialog.cpp:169
 msgid "Size : "
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:170
+#: ../src/gui/dialogs/animateFilterDialog.cpp:171
 msgid "..."
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:171
+#: ../src/gui/dialogs/animateFilterDialog.cpp:172
 msgid "Point data"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:173
+#: ../src/gui/dialogs/animateFilterDialog.cpp:174
 msgid "Voxel data"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:174
+#: ../src/gui/dialogs/animateFilterDialog.cpp:175
 msgid "Range files"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:175
+#: ../src/gui/dialogs/animateFilterDialog.cpp:176
 msgid "Format"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:672
+#: ../src/gui/dialogs/animateFilterDialog.cpp:677
 msgid "transition frame"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:672
-#: ../src/gui/mainFrame.cpp:1636
+#: ../src/gui/dialogs/animateFilterDialog.cpp:677
+#: ../src/gui/mainFrame.cpp:1674
 msgid "Frame count"
 msgstr "Bildanzahl"
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:744
+#: ../src/gui/dialogs/animateFilterDialog.cpp:749
 msgid "Key frame : Colour"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:797
+#: ../src/gui/dialogs/animateFilterDialog.cpp:802
 msgid "File existed, but was unable to read or interpret file contents."
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:798
+#: ../src/gui/dialogs/animateFilterDialog.cpp:803
 msgid "String load failed"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:819
+#: ../src/gui/dialogs/animateFilterDialog.cpp:824
 msgid "Keyframe : decimal"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:828
+#: ../src/gui/dialogs/animateFilterDialog.cpp:833
 msgid "Keyframe : integer"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:837
+#: ../src/gui/dialogs/animateFilterDialog.cpp:842
 msgid "Keyframe : 3D Point"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:962
+#: ../src/gui/dialogs/animateFilterDialog.cpp:967
 msgid "Select or create new folder"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1182
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1147
 msgid "Export Animation"
 msgstr "Animation exportieren"
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1183
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1148
 msgid "Select filter"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1185
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1190
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1210
-#: ../src/gui/mainFrame.cpp:5848 ../src/gui/mainFrame.cpp:5853
-msgid "Property"
-msgstr "Eigenschaft"
-
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1187
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1149
 msgid "Select property"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1189
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1209
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1151
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1171
 msgid "Filter"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1191
-#: ../src/backend/filters/transform.cpp:1182
-#: ../src/backend/filters/annotation.cpp:547
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1152
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1172
+msgid "Property"
+msgstr "Eigenschaft"
+
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1153
+#: ../src/backend/filters/voxelise.cpp:903
+#: ../src/backend/filters/spatialAnalysis.cpp:906
+#: ../src/backend/filters/transform.cpp:1133
+#: ../src/backend/filters/annotation.cpp:540
+#: ../src/backend/filters/annotation.cpp:546
+#: ../src/backend/filters/ionDownsample.cpp:463
 msgid "Mode"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1194
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1156
 msgid "Keyframe table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1195
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1157
 msgid "Remove the selected keyframe from the table"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1196
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1158
 msgid "Enter where the animation frames will be exported to"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1197
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1159
 msgid "Browse to directory where the animation frames will be exported to"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1199
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1161
 msgid ""
 "Title for files, result will be saved as #-name.png, where # is image number."
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1200
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1162
 msgid "Target resolution (image size)"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1202
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1164
 msgid "Select frame for property display"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1203
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1165
 msgid "Enter frame number to change frame (eg 1/20)"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1204
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1166
 msgid "Save point data (POS files) in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1205
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1167
 msgid "Save plots (as text files) in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1206
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1168
 msgid "Save voxel data (raw files) in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1207
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1169
 msgid "Save range files  in output folder?"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1212
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1174
 msgid "Animation parameters for current frame"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1213
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1175
 msgid "Abort animation"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1214
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1176
 msgid "Run Animation"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1285
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1247
 msgid "Filter view"
 msgstr ""
 
-#: ../src/gui/dialogs/animateFilterDialog.cpp:1286
+#: ../src/gui/dialogs/animateFilterDialog.cpp:1248
 msgid "Frame view"
 msgstr ""
 
@@ -860,11 +845,11 @@ msgid "Height :"
 msgstr ""
 
 #: ../src/gui/dialogs/resolutionDialog.cpp:50
-#: ../src/gui/dialogs/prefDialog.cpp:83
+#: ../src/gui/dialogs/prefDialog.cpp:85
 msgid "Reset"
 msgstr "Zurücksetzen"
 
-#: ../src/gui/dialogs/resolutionDialog.cpp:350
+#: ../src/gui/dialogs/resolutionDialog.cpp:336
 msgid "Resolution Selection"
 msgstr ""
 
@@ -873,7 +858,7 @@ msgid "Export:"
 msgstr "Exportieren:"
 
 #: ../src/gui/dialogs/ExportPos.cpp:76
-#: ../src/backend/filters/boundingBox.cpp:520
+#: ../src/backend/filters/boundingBox.cpp:521
 msgid "Visible"
 msgstr "Sichtbar"
 
@@ -894,143 +879,129 @@ msgid "Index"
 msgstr "Index"
 
 #: ../src/gui/dialogs/ExportPos.cpp:111 ../src/gui/dialogs/ExportPos.cpp:114
-#: ../src/backend/filters/compositionProfile.cpp:549
-#: ../src/backend/filters/spatialAnalysis.cpp:1953
-#: ../src/backend/filters/spatialAnalysis.cpp:2022
-#: ../src/backend/filters/spatialAnalysis.cpp:3002
-#: ../src/backend/filters/spatialAnalysis.cpp:3221
-#: ../src/backend/filters/spatialAnalysis.cpp:3290
-#: ../src/backend/filters/spectrumPlot.cpp:240
+#: ../src/backend/filters/compositionProfile.cpp:581
+#: ../src/backend/filters/spatialAnalysis.cpp:2199
+#: ../src/backend/filters/spatialAnalysis.cpp:2259
+#: ../src/backend/filters/spatialAnalysis.cpp:3224
+#: ../src/backend/filters/spatialAnalysis.cpp:3436
+#: ../src/backend/filters/spatialAnalysis.cpp:3495
+#: ../src/backend/filters/spectrumPlot.cpp:237
 msgid "Count"
 msgstr "Anzahl"
 
-#: ../src/gui/dialogs/ExportPos.cpp:450
+#: ../src/gui/dialogs/ExportPos.cpp:457
 msgid "Export Pos Data"
 msgstr "POS Daten exportieren"
 
-#: ../src/gui/dialogs/ExportPos.cpp:453
+#: ../src/gui/dialogs/ExportPos.cpp:460
 msgid "Tree of filters, select leaves to show ion data."
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:455
+#: ../src/gui/dialogs/ExportPos.cpp:462
 msgid "Add all data from all filters"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:456
+#: ../src/gui/dialogs/ExportPos.cpp:463
 msgid "Add all data from currently selected filter"
 msgstr ""
 
-#: ../src/gui/dialogs/ExportPos.cpp:457
+#: ../src/gui/dialogs/ExportPos.cpp:464
 msgid "Add selected data from currently selected filter"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:72
+#: ../src/gui/dialogs/prefDialog.cpp:73
 msgid "Panel Display"
 msgstr "Panel Display"
 
-#: ../src/gui/dialogs/prefDialog.cpp:74
+#: ../src/gui/dialogs/prefDialog.cpp:75
 msgid "Online Updates"
 msgstr "Online Updates"
 
-#: ../src/gui/dialogs/prefDialog.cpp:76 ../src/gui/dialogs/prefDialog.cpp:654
+#: ../src/gui/dialogs/prefDialog.cpp:77 ../src/gui/dialogs/prefDialog.cpp:560
 msgid "Startup"
 msgstr "Startup"
 
-#: ../src/gui/dialogs/prefDialog.cpp:77
+#: ../src/gui/dialogs/prefDialog.cpp:78
 msgid "Camera Speed"
 msgstr "Kamerageschwindigkeit"
 
-#: ../src/gui/dialogs/prefDialog.cpp:78
-msgid "Filter Defaults"
-msgstr "Filtervoreinstellungen"
-
 #: ../src/gui/dialogs/prefDialog.cpp:79
 msgid "Available Filters"
 msgstr "Verfügbare Filter"
 
-#: ../src/gui/dialogs/prefDialog.cpp:82
+#: ../src/gui/dialogs/prefDialog.cpp:84
 msgid "Reset All"
 msgstr "Alle zurücksetzen"
 
-#: ../src/gui/dialogs/prefDialog.cpp:85
+#: ../src/gui/dialogs/prefDialog.cpp:87
 msgid "Show all panels"
 msgstr "Zeige alle Fenster"
 
-#: ../src/gui/dialogs/prefDialog.cpp:86
+#: ../src/gui/dialogs/prefDialog.cpp:88
 msgid "Remember last"
 msgstr "Zuletzt verwendet"
 
-#: ../src/gui/dialogs/prefDialog.cpp:87
+#: ../src/gui/dialogs/prefDialog.cpp:89
 msgid "Show Selected"
 msgstr "Zeige Auswahl"
 
-#: ../src/gui/dialogs/prefDialog.cpp:90
+#: ../src/gui/dialogs/prefDialog.cpp:92
 msgid "Control Pane"
 msgstr "Kontrollfenster"
 
-#: ../src/gui/dialogs/prefDialog.cpp:91
+#: ../src/gui/dialogs/prefDialog.cpp:93
 msgid "Raw Data Panel"
 msgstr "Rohdatenfenster"
 
-#: ../src/gui/dialogs/prefDialog.cpp:92 ../src/gui/mainFrame.cpp:652
+#: ../src/gui/dialogs/prefDialog.cpp:94 ../src/gui/mainFrame.cpp:663
 msgid "Plot List"
 msgstr "Plotliste"
 
-#: ../src/gui/dialogs/prefDialog.cpp:94
+#: ../src/gui/dialogs/prefDialog.cpp:96
 msgid "Periodically notify about available updates"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:96
+#: ../src/gui/dialogs/prefDialog.cpp:98
 msgid "Prefer orthographic at startup"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:97
+#: ../src/gui/dialogs/prefDialog.cpp:99
 msgid "Move Rate"
 msgstr "Bewegungsgeschwindigkeit"
 
-#: ../src/gui/dialogs/prefDialog.cpp:98 ../src/gui/dialogs/prefDialog.cpp:102
+#: ../src/gui/dialogs/prefDialog.cpp:100 ../src/gui/dialogs/prefDialog.cpp:104
 msgid "(slow)"
 msgstr "(langsam)"
 
-#: ../src/gui/dialogs/prefDialog.cpp:100 ../src/gui/dialogs/prefDialog.cpp:104
+#: ../src/gui/dialogs/prefDialog.cpp:102 ../src/gui/dialogs/prefDialog.cpp:106
 msgid "(fast)"
 msgstr "(schnell)"
 
-#: ../src/gui/dialogs/prefDialog.cpp:101
+#: ../src/gui/dialogs/prefDialog.cpp:103
 msgid "Zoom Rate"
 msgstr "Zoomgeschwindigkeit"
 
-#: ../src/gui/dialogs/prefDialog.cpp:456
-msgid "Notice"
-msgstr "Notiz"
-
-#: ../src/gui/dialogs/prefDialog.cpp:459
-msgid "For security reasons, defaults are not modifiable for this filter"
-msgstr ""
-"Aus Sicherheitsgründen können die Voreinstellungen für diesen Filter nicht "
-"geändert werden."
-
-#: ../src/gui/dialogs/prefDialog.cpp:496
+#: ../src/gui/dialogs/prefDialog.cpp:416
 msgid "Show all panels when starting program"
 msgstr "Zeige alle Fenster beim Programmstart"
 
-#: ../src/gui/dialogs/prefDialog.cpp:499
+#: ../src/gui/dialogs/prefDialog.cpp:419
 msgid "Show panels visible at last shutdown when starting program"
 msgstr "Beim Programmstart zuletzt eingeschaltete Fenster anzeigen."
 
-#: ../src/gui/dialogs/prefDialog.cpp:506
+#: ../src/gui/dialogs/prefDialog.cpp:426
 msgid "Show selected panels when starting program"
 msgstr "Zeige ausgewählte Fenster beim Programmstart"
 
-#: ../src/gui/dialogs/prefDialog.cpp:555
+#: ../src/gui/dialogs/prefDialog.cpp:475
 msgid "Preferences"
 msgstr "Voreinstellungen"
 
-#: ../src/gui/dialogs/prefDialog.cpp:557
+#: ../src/gui/dialogs/prefDialog.cpp:477
 msgid "Set the method of panel layout when starting the program"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:560
+#: ../src/gui/dialogs/prefDialog.cpp:480
 msgid ""
 "Lets the program check the internet to see if updates to the program version "
 "are available, then notifies you about updates now and again."
@@ -1038,107 +1009,112 @@ msgstr ""
 "Lässt das Programm via Internet überprüfen ob Updates für diese "
 "Programmversion verfügbar sind. Danach informiert es über die neuen Updates."
 
-#: ../src/gui/dialogs/prefDialog.cpp:562
+#: ../src/gui/dialogs/prefDialog.cpp:482
 msgid ""
 "By default, use an orthographic camera at startup. State files will override "
 "this preference."
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:563
+#: ../src/gui/dialogs/prefDialog.cpp:483
 msgid "Camera translation, orbit and swivel rates. "
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:564
+#: ../src/gui/dialogs/prefDialog.cpp:484
 msgid "Camera zooming rate."
 msgstr "Zoomgeschwindigkeit der Kamera"
 
-#: ../src/gui/dialogs/prefDialog.cpp:566
+#: ../src/gui/dialogs/prefDialog.cpp:486
 msgid "Reset the filter initial values back to program defaults"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:567
+#: ../src/gui/dialogs/prefDialog.cpp:487
 msgid "Reset all filter initial values back to program defaults"
 msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:653
-msgid "Pref"
-msgstr "Pref"
+#: ../src/gui/dialogs/prefDialog.cpp:559
+msgid "Filt. Default"
+msgstr ""
 
-#: ../src/gui/dialogs/prefDialog.cpp:655
+#: ../src/gui/dialogs/prefDialog.cpp:561
 msgid "Camera"
 msgstr "Kamera"
 
-#: ../src/gui/mainFrame.cpp:91
+#: ../src/gui/mainFrame.cpp:105
 msgid "New camera name..."
 msgstr "Neuer Kameraname..."
 
-#: ../src/gui/mainFrame.cpp:92
-msgid "New stash name...."
-msgstr "Neuer Stashname..."
+#: ../src/gui/mainFrame.cpp:106
+msgid "New stash name..."
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:111
+msgid "New Filter..."
+msgstr ""
 
-#: ../src/gui/mainFrame.cpp:108 ../src/backend/filters/annotation.cpp:561
-#: ../src/backend/filters/annotation.cpp:663
+#: ../src/gui/mainFrame.cpp:128 ../src/backend/filters/annotation.cpp:555
+#: ../src/backend/filters/annotation.cpp:659
 #: ../src/backend/filters/annotation.h:96
 msgid "Annotation"
 msgstr "Kommentar"
 
-#: ../src/gui/mainFrame.cpp:109
+#: ../src/gui/mainFrame.cpp:129
 msgid "Bounding Box"
 msgstr "Begrenzungs-Box"
 
-#: ../src/gui/mainFrame.cpp:110 ../src/backend/filters/ionClip.h:66
+#: ../src/gui/mainFrame.cpp:130 ../src/backend/filters/ionClip.cpp:619
+#: ../src/backend/filters/ionClip.h:66
 msgid "Clipping"
 msgstr "Zuschneiden"
 
-#: ../src/gui/mainFrame.cpp:111 ../src/backend/filters/clusterAnalysis.h:140
+#: ../src/gui/mainFrame.cpp:131 ../src/backend/filters/clusterAnalysis.h:143
 msgid "Cluster Analysis"
 msgstr "Clusteranalyse"
 
-#: ../src/gui/mainFrame.cpp:112
+#: ../src/gui/mainFrame.cpp:132
 msgid "Compos. Profiles"
 msgstr "Konz.Profil"
 
-#: ../src/gui/mainFrame.cpp:113
+#: ../src/gui/mainFrame.cpp:133
 msgid "Downsampling"
 msgstr "Datenreduktion"
 
-#: ../src/gui/mainFrame.cpp:114
+#: ../src/gui/mainFrame.cpp:134
 msgid "Extern. Prog."
 msgstr "Ext. Progr."
 
-#: ../src/gui/mainFrame.cpp:115
+#: ../src/gui/mainFrame.cpp:135
 msgid "Ion Colour"
 msgstr "Ionenfarbe"
 
-#: ../src/gui/mainFrame.cpp:116
+#: ../src/gui/mainFrame.cpp:136
 msgid "Ion Info"
 msgstr "Ion Info"
 
-#: ../src/gui/mainFrame.cpp:117
+#: ../src/gui/mainFrame.cpp:137
 msgid "Ion Transform"
 msgstr "Ionentransform."
 
-#: ../src/gui/mainFrame.cpp:118 ../src/backend/filters/spectrumPlot.h:53
+#: ../src/gui/mainFrame.cpp:138 ../src/backend/filters/spectrumPlot.h:53
 msgid "Spectrum"
 msgstr "Spektrum"
 
-#: ../src/gui/mainFrame.cpp:119
+#: ../src/gui/mainFrame.cpp:139
 msgid "Range File"
 msgstr "Rangedatei"
 
-#: ../src/gui/mainFrame.cpp:120 ../src/backend/filters/spatialAnalysis.h:172
+#: ../src/gui/mainFrame.cpp:140 ../src/backend/filters/spatialAnalysis.h:193
 msgid "Spat. Analysis"
 msgstr "Räumliche Analyse"
 
-#: ../src/gui/mainFrame.cpp:121 ../src/backend/filters/voxelise.h:121
+#: ../src/gui/mainFrame.cpp:141 ../src/backend/filters/voxelise.h:121
 msgid "Voxelisation"
 msgstr "Voxelisation"
 
-#: ../src/gui/mainFrame.cpp:421
+#: ../src/gui/mainFrame.cpp:429
 msgid "OpenGL Failed"
 msgstr "OpenGL fehlgeschlagen"
 
-#: ../src/gui/mainFrame.cpp:422 ../src/gui/mainFrame.cpp:424
+#: ../src/gui/mainFrame.cpp:430 ../src/gui/mainFrame.cpp:432
 msgid ""
 "Unable to initialise the openGL (3D) panel. Program cannot start. Please "
 "check your video drivers."
@@ -1146,445 +1122,447 @@ msgstr ""
 "Kann das OpenGL (3D)-Panel nicht initialisieren. Das Programm kann nicht "
 "gestartet werden. Bitte überprüfen Sie Ihren Video-Treiber."
 
-#: ../src/gui/mainFrame.cpp:444
+#: ../src/gui/mainFrame.cpp:452
 msgid "&Open...\tCtrl+O"
 msgstr "&Öffnen...\tCtrl+O"
 
-#: ../src/gui/mainFrame.cpp:444
+#: ../src/gui/mainFrame.cpp:452
 msgid "Open state file"
 msgstr "Statusdatei öffnen"
 
-#: ../src/gui/mainFrame.cpp:445
+#: ../src/gui/mainFrame.cpp:453
 msgid "&Merge...\tCtrl+Shift+O"
 msgstr "&Zusammenführen...\tCtrl+Shift+O"
 
-#: ../src/gui/mainFrame.cpp:445
+#: ../src/gui/mainFrame.cpp:453
 msgid "Merge other file"
 msgstr "Merge other file"
 
-#: ../src/gui/mainFrame.cpp:449
+#: ../src/gui/mainFrame.cpp:457
 msgid "&Recent"
 msgstr "&Letzte"
 
-#: ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:458
 msgid "&Save\tCtrl+S"
 msgstr "&Speichern\tCtrl+S"
 
-#: ../src/gui/mainFrame.cpp:450
+#: ../src/gui/mainFrame.cpp:458
 msgid "Save state to file"
 msgstr "Status in Datei speichern"
 
-#: ../src/gui/mainFrame.cpp:452
+#: ../src/gui/mainFrame.cpp:460
 msgid "Save &As...\tCtrl+Shift+S"
 msgstr "Speichern &als...\tCtrl+Shift+S"
 
-#: ../src/gui/mainFrame.cpp:452
+#: ../src/gui/mainFrame.cpp:460
 msgid "Save current state to new file"
 msgstr "Aktuellen Status als neue Datei speichern"
 
-#: ../src/gui/mainFrame.cpp:455
+#: ../src/gui/mainFrame.cpp:463
 msgid "&Plot...\tCtrl+P"
 msgstr "&Plot...\tCtrl+P"
 
-#: ../src/gui/mainFrame.cpp:455
+#: ../src/gui/mainFrame.cpp:463
 msgid "Export Current Plot"
 msgstr "Aktuellen Plot exportieren"
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:464
 msgid "&Image...\tCtrl+I"
 msgstr "&Bild...\tCtrl+I"
 
-#: ../src/gui/mainFrame.cpp:456
+#: ../src/gui/mainFrame.cpp:464
 msgid "Export Current 3D View"
 msgstr "Aktuelle 3D Ansicht exportieren"
 
-#: ../src/gui/mainFrame.cpp:457
+#: ../src/gui/mainFrame.cpp:465
 msgid "Ion&s...\tCtrl+N"
 msgstr "Ion&en...\tCtrl+N"
 
-#: ../src/gui/mainFrame.cpp:457
+#: ../src/gui/mainFrame.cpp:465
 msgid "Export Ion Data"
 msgstr "Ionendaten exportieren"
 
-#: ../src/gui/mainFrame.cpp:458
+#: ../src/gui/mainFrame.cpp:466
 msgid "Ran&ges...\tCtrl+G"
 msgstr "Ran&ges...\tCtrl+G"
 
-#: ../src/gui/mainFrame.cpp:458
+#: ../src/gui/mainFrame.cpp:466
 msgid "Export Range Data"
 msgstr "Rangedaten exportieren"
 
-#: ../src/gui/mainFrame.cpp:459
+#: ../src/gui/mainFrame.cpp:467
 msgid "&Animate Filters...\tCtrl+A"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:459
+#: ../src/gui/mainFrame.cpp:467
 msgid "Export Animated Filter"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:460
+#: ../src/gui/mainFrame.cpp:468
 msgid "Ani&mate Camera...\tCtrl+M"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:460
+#: ../src/gui/mainFrame.cpp:468
 msgid "Export Animated Camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:461
+#: ../src/gui/mainFrame.cpp:469
 msgid "Pac&kage...\tCtrl+K"
 msgstr "Pa&ket...\tCtrl+K"
 
-#: ../src/gui/mainFrame.cpp:461
+#: ../src/gui/mainFrame.cpp:469
 msgid "Export analysis package"
 msgstr "Analysepaket exportieren"
 
-#: ../src/gui/mainFrame.cpp:463
+#: ../src/gui/mainFrame.cpp:471
 msgid "&Export"
 msgstr "&Exportieren"
 
-#: ../src/gui/mainFrame.cpp:466
+#: ../src/gui/mainFrame.cpp:474
 msgid "&Quit\tCtrl+Q"
 msgstr "&Beenden\tCtrl+Q"
 
-#: ../src/gui/mainFrame.cpp:466 ../src/gui/mainFrame.cpp:468
+#: ../src/gui/mainFrame.cpp:474 ../src/gui/mainFrame.cpp:476
 msgid "Exit Program"
 msgstr "Programm beenden"
 
-#: ../src/gui/mainFrame.cpp:468
+#: ../src/gui/mainFrame.cpp:476
 msgid "E&xit"
 msgstr "E&xit"
 
-#: ../src/gui/mainFrame.cpp:470
+#: ../src/gui/mainFrame.cpp:478
 msgid "&File"
 msgstr "&Datei"
 
-#: ../src/gui/mainFrame.cpp:474
+#: ../src/gui/mainFrame.cpp:482
 msgid "&Background Colour...\tCtrl+B"
 msgstr "&Hintergrundfarbe...\tCtrl+B"
 
-#: ../src/gui/mainFrame.cpp:474
+#: ../src/gui/mainFrame.cpp:482
 msgid "Change background colour"
 msgstr "Hintergrundfarbe ändern"
 
-#: ../src/gui/mainFrame.cpp:478
+#: ../src/gui/mainFrame.cpp:486
 msgid "&Control Pane\tF2"
 msgstr "&Kontrollfenster\tF2"
 
-#: ../src/gui/mainFrame.cpp:478 ../src/gui/mainFrame.cpp:481
+#: ../src/gui/mainFrame.cpp:486 ../src/gui/mainFrame.cpp:489
 msgid "Toggle left control pane"
 msgstr "Linkes Kontrollfenster ein/aus schalten"
 
-#: ../src/gui/mainFrame.cpp:481
+#: ../src/gui/mainFrame.cpp:489
 msgid "&Control Pane\tAlt+C"
 msgstr "&Kontrollfenster\tAlt+C"
 
-#: ../src/gui/mainFrame.cpp:487
+#: ../src/gui/mainFrame.cpp:495
 msgid "&Raw Data Pane\tF3"
 msgstr "&Rohdatenfenster\tF3"
 
-#: ../src/gui/mainFrame.cpp:487 ../src/gui/mainFrame.cpp:490
+#: ../src/gui/mainFrame.cpp:495 ../src/gui/mainFrame.cpp:498
 msgid "Toggle raw data  pane (bottom)"
 msgstr "Rohdatenfenster (unten)"
 
-#: ../src/gui/mainFrame.cpp:490
+#: ../src/gui/mainFrame.cpp:498
 msgid "&Raw Data Pane\tAlt+R"
 msgstr "&Rohdatenfenster\tAlt+R"
 
-#: ../src/gui/mainFrame.cpp:494
+#: ../src/gui/mainFrame.cpp:502
 msgid "&Plot List\tF4"
 msgstr "&Plot Liste\tF4"
 
-#: ../src/gui/mainFrame.cpp:494 ../src/gui/mainFrame.cpp:496
+#: ../src/gui/mainFrame.cpp:502 ../src/gui/mainFrame.cpp:504
 msgid "Toggle plot list"
 msgstr "Plotliste ein/aus schalten"
 
-#: ../src/gui/mainFrame.cpp:496
+#: ../src/gui/mainFrame.cpp:504
 msgid "&Plot List\tAlt+P"
 msgstr "&Plot Liste\tAlt+P"
 
-#: ../src/gui/mainFrame.cpp:502
+#: ../src/gui/mainFrame.cpp:510
 msgid "&Legend\tCtrl+L"
 msgstr "&Legende\tCtrl+L"
 
-#: ../src/gui/mainFrame.cpp:502
+#: ../src/gui/mainFrame.cpp:510
 msgid "Toggle Legend display"
 msgstr "Legende anzeigen ein/aus"
 
-#: ../src/gui/mainFrame.cpp:504
+#: ../src/gui/mainFrame.cpp:512
 msgid "P&lot..."
 msgstr "P&lot..."
 
-#: ../src/gui/mainFrame.cpp:505
+#: ../src/gui/mainFrame.cpp:513
 msgid "&Axis\tCtrl+Shift+I"
 msgstr "&Achsen\tCtrl+Shift+I"
 
-#: ../src/gui/mainFrame.cpp:505
+#: ../src/gui/mainFrame.cpp:513
 msgid "Toggle World Axis display"
 msgstr "Hauptachsen ein/aus schalten"
 
-#: ../src/gui/mainFrame.cpp:510
+#: ../src/gui/mainFrame.cpp:518
 msgid "&Fullscreen mode\tF11"
 msgstr "&Vollbildmodus\tF11"
 
-#: ../src/gui/mainFrame.cpp:510 ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:518 ../src/gui/mainFrame.cpp:520
 msgid "Next fullscreen mode: with toolbars"
 msgstr "Nächster Vollbildmodus: ohne Werkzeugleisten"
 
-#: ../src/gui/mainFrame.cpp:512
+#: ../src/gui/mainFrame.cpp:520
 msgid "&Fullscreen mode\tCtrl+Shift+F"
 msgstr "&Vollbildmodus\tCtrl+Shift+F"
 
-#: ../src/gui/mainFrame.cpp:517
+#: ../src/gui/mainFrame.cpp:525
 msgid "&Undo\tCtrl+Z"
 msgstr "&Zurück\tCtrl+Z"
 
-#: ../src/gui/mainFrame.cpp:519
+#: ../src/gui/mainFrame.cpp:527
 msgid "&Redo\tCtrl+Y"
 msgstr "&Wiederholen\tCtrl+Y"
 
-#: ../src/gui/mainFrame.cpp:522
+#: ../src/gui/mainFrame.cpp:530
 msgid "&Range"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:525
+#: ../src/gui/mainFrame.cpp:533
 msgid "&Preferences"
 msgstr "&Voreinstellungen"
 
-#: ../src/gui/mainFrame.cpp:527
+#: ../src/gui/mainFrame.cpp:535
 msgid "&Edit"
 msgstr "&Bearbeiten"
 
-#: ../src/gui/mainFrame.cpp:530
+#: ../src/gui/mainFrame.cpp:538
 msgid "&View"
 msgstr "&Ansicht"
 
-#: ../src/gui/mainFrame.cpp:532
+#: ../src/gui/mainFrame.cpp:540
 msgid "&Help...\tCtrl+H"
 msgstr "&Hilfe...\tCtrl+H"
 
-#: ../src/gui/mainFrame.cpp:532
+#: ../src/gui/mainFrame.cpp:540
 msgid "Show help files and documentation"
 msgstr "Hilfedateien und Dokumentation anzeigen"
 
-#: ../src/gui/mainFrame.cpp:533
+#: ../src/gui/mainFrame.cpp:541
 msgid "&Contact..."
 msgstr "&Kontakt..."
 
-#: ../src/gui/mainFrame.cpp:533
+#: ../src/gui/mainFrame.cpp:541
 msgid "Open contact page"
 msgstr "Kontaktseite öffnen"
 
-#: ../src/gui/mainFrame.cpp:535
+#: ../src/gui/mainFrame.cpp:543
 msgid "&About..."
 msgstr "Über 3Depict..."
 
-#: ../src/gui/mainFrame.cpp:535
+#: ../src/gui/mainFrame.cpp:543
 msgid "Information about this program"
 msgstr "Informationen zu diesem Programm"
 
-#: ../src/gui/mainFrame.cpp:536
+#: ../src/gui/mainFrame.cpp:544
 msgid "&Help"
 msgstr "&Hilfe"
 
-#: ../src/gui/mainFrame.cpp:538
+#: ../src/gui/mainFrame.cpp:546
 msgid "Stashed Filters"
 msgstr "Zwischengelagerte Filter"
 
-#: ../src/gui/mainFrame.cpp:543
+#: ../src/gui/mainFrame.cpp:551
 msgid "New Filters"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:571
+#: ../src/gui/mainFrame.cpp:580
 msgid "Last Outputs"
 msgstr "Letzte Ausgabe"
 
-#: ../src/gui/mainFrame.cpp:573
+#: ../src/gui/mainFrame.cpp:582
 msgid "Auto Refresh"
 msgstr ""
 "Autom.\n"
 "aktualisieren"
 
-#: ../src/gui/mainFrame.cpp:579
+#: ../src/gui/mainFrame.cpp:588
 msgid "Filter settings"
 msgstr "Filtereinstellungen"
 
-#: ../src/gui/mainFrame.cpp:581
+#: ../src/gui/mainFrame.cpp:591
 msgid "Camera Name"
 msgstr "Kameraname"
 
-#: ../src/gui/mainFrame.cpp:587
+#: ../src/gui/mainFrame.cpp:598
 msgid "3D Post-processing"
 msgstr "3D Nachbearbeitung"
 
-#: ../src/gui/mainFrame.cpp:589
+#: ../src/gui/mainFrame.cpp:600
 msgid "Enable Cropping"
 msgstr "Zuschneiden aktivieren"
 
-#: ../src/gui/mainFrame.cpp:591 ../src/gui/mainFrame.cpp:602
+#: ../src/gui/mainFrame.cpp:602 ../src/gui/mainFrame.cpp:613
 msgid "x-y"
 msgstr "x-y"
 
-#: ../src/gui/mainFrame.cpp:592 ../src/gui/mainFrame.cpp:603
+#: ../src/gui/mainFrame.cpp:603 ../src/gui/mainFrame.cpp:614
 msgid "x-z"
 msgstr "x-z"
 
-#: ../src/gui/mainFrame.cpp:593 ../src/gui/mainFrame.cpp:604
+#: ../src/gui/mainFrame.cpp:604 ../src/gui/mainFrame.cpp:615
 msgid "y-x"
 msgstr "y-x"
 
-#: ../src/gui/mainFrame.cpp:594 ../src/gui/mainFrame.cpp:605
+#: ../src/gui/mainFrame.cpp:605 ../src/gui/mainFrame.cpp:616
 msgid "y-z"
 msgstr "y-z"
 
-#: ../src/gui/mainFrame.cpp:595 ../src/gui/mainFrame.cpp:606
+#: ../src/gui/mainFrame.cpp:606 ../src/gui/mainFrame.cpp:617
 msgid "z-x"
 msgstr "z-x"
 
-#: ../src/gui/mainFrame.cpp:596 ../src/gui/mainFrame.cpp:607
+#: ../src/gui/mainFrame.cpp:607 ../src/gui/mainFrame.cpp:618
 msgid "z-y"
 msgstr "z-y"
 
-#: ../src/gui/mainFrame.cpp:611
+#: ../src/gui/mainFrame.cpp:622
 msgid "Use camera coordinates"
 msgstr "Verwende Kamerakoordinaten"
 
-#: ../src/gui/mainFrame.cpp:612
+#: ../src/gui/mainFrame.cpp:623
 msgid "dX"
 msgstr "dX"
 
-#: ../src/gui/mainFrame.cpp:614
+#: ../src/gui/mainFrame.cpp:625
 msgid "dY"
 msgstr "dY"
 
-#: ../src/gui/mainFrame.cpp:616
+#: ../src/gui/mainFrame.cpp:627
 msgid "dZ"
 msgstr "dZ"
 
-#: ../src/gui/mainFrame.cpp:618
+#: ../src/gui/mainFrame.cpp:629
 msgid "Enable Anaglyphic Stereo"
 msgstr "Anaglyphic Stereo aktivieren"
 
-#: ../src/gui/mainFrame.cpp:619
+#: ../src/gui/mainFrame.cpp:630
 msgid "Flip Channels"
 msgstr "Kanäle tauschen"
 
-#: ../src/gui/mainFrame.cpp:620
+#: ../src/gui/mainFrame.cpp:631
 msgid "Anaglyph Mode"
 msgstr "Anaglyphmodus"
 
-#: ../src/gui/mainFrame.cpp:622
+#: ../src/gui/mainFrame.cpp:633
 msgid "Red-Blue"
 msgstr "Rot-Blau"
 
-#: ../src/gui/mainFrame.cpp:623
+#: ../src/gui/mainFrame.cpp:634
 msgid "Red-Green"
 msgstr "Rot-Grün"
 
-#: ../src/gui/mainFrame.cpp:624
+#: ../src/gui/mainFrame.cpp:635
 msgid "Red-Cyan"
 msgstr "Rot-Zyan"
 
-#: ../src/gui/mainFrame.cpp:625
+#: ../src/gui/mainFrame.cpp:636
 msgid "Green-Magenta"
 msgstr "Grün-Magenta"
 
-#: ../src/gui/mainFrame.cpp:629
+#: ../src/gui/mainFrame.cpp:640
 msgid "Baseline Separation"
 msgstr "Basislinienabstand"
 
-#: ../src/gui/mainFrame.cpp:631 ../src/backend/filters/voxelise.cpp:981
-#: ../src/backend/filters/voxelise.cpp:1037
-#: ../src/backend/filters/compositionProfile.cpp:1165
+#: ../src/gui/mainFrame.cpp:642 ../src/backend/filters/voxelise.cpp:982
+#: ../src/backend/filters/voxelise.cpp:1142
+#: ../src/backend/filters/compositionProfile.cpp:1109
 #: ../src/backend/filters/boundingBox.cpp:648
-#: ../src/backend/filters/dataLoad.cpp:660
+#: ../src/backend/filters/annotation.cpp:901
+#: ../src/backend/filters/dataLoad.cpp:651
+#: ../src/backend/filters/spectrumPlot.cpp:459
 msgid "Appearance"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:632
+#: ../src/gui/mainFrame.cpp:643
 msgid "Smooth && translucent objects"
 msgstr "Glatte && durchsichtige Objekte"
 
-#: ../src/gui/mainFrame.cpp:634
+#: ../src/gui/mainFrame.cpp:645
 msgid "3D lighting"
 msgstr "3D Beleuchtung"
 
-#: ../src/gui/mainFrame.cpp:637
+#: ../src/gui/mainFrame.cpp:648
 msgid "Performance"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:638
+#: ../src/gui/mainFrame.cpp:649
 msgid "Fast and weak randomisation."
 msgstr "Schnelle aber schwache Randomisierung"
 
-#: ../src/gui/mainFrame.cpp:640
+#: ../src/gui/mainFrame.cpp:651
 msgid "Limit Output Pts"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:646
+#: ../src/gui/mainFrame.cpp:657
 msgid "Filter caching"
 msgstr "Filter zwischenspeichern"
 
-#: ../src/gui/mainFrame.cpp:648
+#: ../src/gui/mainFrame.cpp:659
 msgid "Max. Ram usage (%)"
 msgstr "Max. RAM-Nutzung (%)"
 
-#: ../src/gui/mainFrame.cpp:705
+#: ../src/gui/mainFrame.cpp:718
 msgid "Type"
 msgstr "Type"
 
-#: ../src/gui/mainFrame.cpp:706
+#: ../src/gui/mainFrame.cpp:719
 msgid "Num"
 msgstr "Num"
 
-#: ../src/gui/mainFrame.cpp:721
+#: ../src/gui/mainFrame.cpp:734
 msgid "Warning: Your configuration file appears to be invalid:\n"
 msgstr "Warnung: Ihre Konfigurationsdatei scheint ungültig zu sein.\n"
 
-#: ../src/gui/mainFrame.cpp:722
+#: ../src/gui/mainFrame.cpp:735
 msgid "\tConfig Load: "
 msgstr "\tConfig Load: "
 
-#: ../src/gui/mainFrame.cpp:974
+#: ../src/gui/mainFrame.cpp:984
 msgid "Current state has not been saved, would you like to save it now?"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:975
+#: ../src/gui/mainFrame.cpp:985
 msgid "State changed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:995
+#: ../src/gui/mainFrame.cpp:1005
 msgid "Readable files (*.xml, *.pos, *.txt,*.csv, *.ato)"
 msgstr "Lesbare Dateien (*.xml, *.pos, *.txt,*.csv,*.ato)"
 
-#: ../src/gui/mainFrame.cpp:997
+#: ../src/gui/mainFrame.cpp:1007
 msgid "XML State File (*.xml)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:998
+#: ../src/gui/mainFrame.cpp:1008
 msgid "POS File (*.pos)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:999
+#: ../src/gui/mainFrame.cpp:1009
 msgid "LAWATAP ATO File (*.ato)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1000
+#: ../src/gui/mainFrame.cpp:1010
 msgid "Text File (*.txt, *.csv)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1001
+#: ../src/gui/mainFrame.cpp:1011
 msgid "All Files (*)"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1014 ../src/gui/mainFrame.cpp:1068
+#: ../src/gui/mainFrame.cpp:1024 ../src/gui/mainFrame.cpp:1080
 msgid "Select Data or State File..."
 msgstr "Daten oder Statusdatei auswählen..."
 
-#: ../src/gui/mainFrame.cpp:1056 ../src/gui/mainFrame.cpp:1387
+#: ../src/gui/mainFrame.cpp:1068 ../src/gui/mainFrame.cpp:1407
 msgid "Loaded file."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1069
+#: ../src/gui/mainFrame.cpp:1081
 msgid ""
 "3Depict file (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS File (*.pos)|*.pos|"
 "XML State File (*.xml)|*.xml|All Files (*)|*"
@@ -1592,23 +1570,23 @@ msgstr ""
 "3Depictdateien (*.xml, *.pos,*.txt)|*.xml;*.pos;*.txt|POS Datei (*.pos)|*."
 "pos|XML Status Datei (*.xml)|*.xml|All Files (*)|*"
 
-#: ../src/gui/mainFrame.cpp:1080
+#: ../src/gui/mainFrame.cpp:1092
 msgid "Merged file."
 msgstr "Datei zusammengeführt."
 
-#: ../src/gui/mainFrame.cpp:1182
+#: ../src/gui/mainFrame.cpp:1199
 msgid "Tip: You can use ⌘ (command) to merge"
 msgstr "Tip: Sie können ⌘ (command) zum Zusammenführen verwenden"
 
-#: ../src/gui/mainFrame.cpp:1184
+#: ../src/gui/mainFrame.cpp:1201
 msgid "Tip: You can use ctrl to merge"
 msgstr "Tip: Sie können strg zum Zusammen führen verwenden"
 
-#: ../src/gui/mainFrame.cpp:1221
+#: ../src/gui/mainFrame.cpp:1241
 msgid "Load error"
 msgstr "Fehler beim Laden"
 
-#: ../src/gui/mainFrame.cpp:1222
+#: ../src/gui/mainFrame.cpp:1242
 msgid ""
 "Error loading state file.\n"
 "See console for more info."
@@ -1616,7 +1594,7 @@ msgstr ""
 "Fehler beim Laden der Statusdatei.\n"
 "Konsole für mehr Informationen."
 
-#: ../src/gui/mainFrame.cpp:1230
+#: ../src/gui/mainFrame.cpp:1250
 msgid ""
 "This state file contains filters that can be unsafe to run\n"
 "Do you wish to remove these before continuing?."
@@ -1624,24 +1602,24 @@ msgstr ""
 "Diese Statusdatei enthält Filter deren Anwendung möglicherweise unsicher "
 "ist. Wollen Sie diese entfernen."
 
-#: ../src/gui/mainFrame.cpp:1231
+#: ../src/gui/mainFrame.cpp:1251
 msgid "Security warning"
 msgstr "Sicherheitswarnung"
 
-#: ../src/gui/mainFrame.cpp:1444 ../src/gui/mainFrame.cpp:1540
-#: ../src/gui/mainFrame.cpp:1957
+#: ../src/gui/mainFrame.cpp:1468 ../src/gui/mainFrame.cpp:1564
+#: ../src/gui/mainFrame.cpp:1997
 msgid "Unable to save"
 msgstr "Speichern nicht möglich"
 
-#: ../src/gui/mainFrame.cpp:1445
+#: ../src/gui/mainFrame.cpp:1469
 msgid "No plot available. Please create a plot before exporting."
 msgstr "Kein Plot vefügbar. Plot muss vor dem Exportieren erzeugt werden."
 
-#: ../src/gui/mainFrame.cpp:1449
+#: ../src/gui/mainFrame.cpp:1473
 msgid "Save plot..."
 msgstr "Plot speichern..."
 
-#: ../src/gui/mainFrame.cpp:1450
+#: ../src/gui/mainFrame.cpp:1474
 msgid ""
 "By Extension (svg,png)|*.svg;*.png|Scalable Vector Graphics File (*.svg)|*."
 "svg|PNG File (*.png)|*.png|All Files (*)|*"
@@ -1649,44 +1627,53 @@ msgstr ""
 "Dateierweiterung (svg,png)|*.svg;*.png|Skalierbare Vektorgrafik (*.svg)|*."
 "svg|PNG Datei (*.png)|*.png|Alle Dateien (*)|*"
 
-#: ../src/gui/mainFrame.cpp:1504
+#: ../src/gui/mainFrame.cpp:1528
 msgid "Select type for save"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1505
+#: ../src/gui/mainFrame.cpp:1529
 msgid "Choose file type"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1525 ../src/gui/mainFrame.cpp:1568
-#: ../src/gui/mainFrame.cpp:1604
+#: ../src/gui/mainFrame.cpp:1549 ../src/gui/mainFrame.cpp:1606
+#: ../src/gui/mainFrame.cpp:1642
 msgid "Choose resolution"
 msgstr "Auflösung auswählen"
 
-#: ../src/gui/mainFrame.cpp:1541
+#: ../src/gui/mainFrame.cpp:1565
 msgid "Unknown file extension. Please use \"svg\" or \"png\""
 msgstr "Unbekannte Dateierweiterung. Bitte verwenden Sie \"svg\" oder \"png\""
 
-#: ../src/gui/mainFrame.cpp:1552
+#: ../src/gui/mainFrame.cpp:1576
 msgid "Saved plot: "
 msgstr "Gespeicherter Plot:"
 
-#: ../src/gui/mainFrame.cpp:1559 ../src/gui/mainFrame.cpp:1597
+#: ../src/gui/mainFrame.cpp:1583 ../src/gui/mainFrame.cpp:1635
 msgid "Save Image..."
 msgstr "Speichere Bild..."
 
-#: ../src/gui/mainFrame.cpp:1560 ../src/gui/mainFrame.cpp:1598
+#: ../src/gui/mainFrame.cpp:1584 ../src/gui/mainFrame.cpp:1636
 msgid "PNG File (*.png)|*.png|All Files (*)|*"
 msgstr "PNG Datei (*.png)|*.png|Alle Dateien (*)|*"
 
-#: ../src/gui/mainFrame.cpp:1588 ../src/gui/mainFrame.cpp:1664
+#: ../src/gui/mainFrame.cpp:1598
+msgid "File already exists. Overwrite?"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:1599 ../src/gui/mainFrame.cpp:2385
+#: ../src/gui/mainFrame.cpp:2483 ../src/gui/mainFrame.cpp:2507
+msgid "Overwrite?"
+msgstr "Überschreiben?"
+
+#: ../src/gui/mainFrame.cpp:1626 ../src/gui/mainFrame.cpp:1702
 msgid "Saved 3D View :"
 msgstr "Gespeicherte 3D Ansicht"
 
-#: ../src/gui/mainFrame.cpp:1618
+#: ../src/gui/mainFrame.cpp:1656
 msgid "Program limitation"
 msgstr "Programmeinschränkung"
 
-#: ../src/gui/mainFrame.cpp:1619
+#: ../src/gui/mainFrame.cpp:1657
 msgid ""
 "Limitation on the screenshot dimension; please ensure that both width and "
 "height exceed the initial values,\n"
@@ -1698,104 +1685,104 @@ msgstr ""
 "kleiner als die ursprünglichen Werte sind. Sollte Sie dies stören, melden "
 "Sie bitte einen Bug."
 
-#: ../src/gui/mainFrame.cpp:1636
+#: ../src/gui/mainFrame.cpp:1674
 msgid "Number of frames"
 msgstr "Bilderanzahl"
 
-#: ../src/gui/mainFrame.cpp:1791
+#: ../src/gui/mainFrame.cpp:1829
 msgid "Cannot animate with no filters."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1868
+#: ../src/gui/mainFrame.cpp:1908
 msgid "Animating"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1869
+#: ../src/gui/mainFrame.cpp:1909
 msgid "Performing refresh"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1898
+#: ../src/gui/mainFrame.cpp:1938
 msgid "Filter property change failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1918
+#: ../src/gui/mainFrame.cpp:1958
 msgid "Refresh failed on frame :"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1943
+#: ../src/gui/mainFrame.cpp:1983
 msgid "Scene generation failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1944
+#: ../src/gui/mainFrame.cpp:1984
 msgid "Unable to generate scene for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1958
+#: ../src/gui/mainFrame.cpp:1998
 msgid "Image save failed for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1983
+#: ../src/gui/mainFrame.cpp:2023
 msgid "Ion save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:1984
+#: ../src/gui/mainFrame.cpp:2024
 msgid "Unable to save ions for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2015
+#: ../src/gui/mainFrame.cpp:2055
 msgid "Plot save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2016
+#: ../src/gui/mainFrame.cpp:2056
 msgid "Unable to save plot or frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2057
+#: ../src/gui/mainFrame.cpp:2097
 msgid "Range save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2058
+#: ../src/gui/mainFrame.cpp:2098
 msgid "Unable to save range for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2087
+#: ../src/gui/mainFrame.cpp:2127
 msgid "Voxel save failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2088
+#: ../src/gui/mainFrame.cpp:2128
 msgid "Unable to save voxels for frame "
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2118
+#: ../src/gui/mainFrame.cpp:2158
 msgid "Animate failed"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2143 ../src/gui/mainFrame.cpp:2301
-#: ../src/gui/mainFrame.cpp:2397
+#: ../src/gui/mainFrame.cpp:2183 ../src/gui/mainFrame.cpp:2341
+#: ../src/gui/mainFrame.cpp:2437
 msgid "No filters means no data to export"
 msgstr "Keine Filter bedeutet keine Daten zum Exportieren"
 
-#: ../src/gui/mainFrame.cpp:2157
+#: ../src/gui/mainFrame.cpp:2197
 msgid "Package name"
 msgstr "Paketname"
 
-#: ../src/gui/mainFrame.cpp:2158
+#: ../src/gui/mainFrame.cpp:2198
 msgid "Package directory name"
 msgstr "Paketverzeichnis"
 
-#: ../src/gui/mainFrame.cpp:2160
+#: ../src/gui/mainFrame.cpp:2200
 msgid "AnalysisPackage"
 msgstr "Analysepaket"
 
-#: ../src/gui/mainFrame.cpp:2173
+#: ../src/gui/mainFrame.cpp:2213
 msgid "Package folder already exists, won't overwrite."
 msgstr "Paketverzeichnis existiert bereits. Werde es nicht überschreiben."
 
-#: ../src/gui/mainFrame.cpp:2174
+#: ../src/gui/mainFrame.cpp:2214
 msgid "Not available"
 msgstr "Nicht verfügbar"
 
-#: ../src/gui/mainFrame.cpp:2199
+#: ../src/gui/mainFrame.cpp:2239
 msgid ""
 "Package folder creation failed\n"
 "check writing to this location is possible."
@@ -1803,244 +1790,211 @@ msgstr ""
 "Anlegen des Paketverzeichnisses fehlgeschlagen\n"
 "Überprüfen Sie ob der angegenbene Ort schreibgeschützt ist."
 
-#: ../src/gui/mainFrame.cpp:2200
+#: ../src/gui/mainFrame.cpp:2240
 msgid "Folder creation failed"
 msgstr "Anlegen des Ordners ist fehlgeschlagen"
 
-#: ../src/gui/mainFrame.cpp:2219
+#: ../src/gui/mainFrame.cpp:2259
 msgid "Copying"
 msgstr "kopiere"
 
-#: ../src/gui/mainFrame.cpp:2220
+#: ../src/gui/mainFrame.cpp:2260
 msgid "Copying referenced files"
 msgstr "Copying referenced files"
 
-#: ../src/gui/mainFrame.cpp:2279
+#: ../src/gui/mainFrame.cpp:2319
 msgid "Error copying file"
 msgstr "Fehler beim Kopieren der Datei"
 
-#: ../src/gui/mainFrame.cpp:2288
+#: ../src/gui/mainFrame.cpp:2328
 msgid "Saved package: "
 msgstr "Gespeicherte Pakete: "
 
-#: ../src/gui/mainFrame.cpp:2311
+#: ../src/gui/mainFrame.cpp:2351
 msgid "Export"
 msgstr "Exportieren"
 
-#: ../src/gui/mainFrame.cpp:2316
+#: ../src/gui/mainFrame.cpp:2356
 msgid "POS Data (*.pos)|*.pos|All Files (*)|*"
 msgstr "POS-Daten (*.pos)|*.pos|All Files (*)|*"
 
-#: ../src/gui/mainFrame.cpp:2344 ../src/gui/mainFrame.cpp:2442
+#: ../src/gui/mainFrame.cpp:2384 ../src/gui/mainFrame.cpp:2482
 msgid "File already exists, overwrite?"
 msgstr "Datei existiert bereits. Überschreiben?"
 
-#: ../src/gui/mainFrame.cpp:2345 ../src/gui/mainFrame.cpp:2443
-#: ../src/gui/mainFrame.cpp:2467
-msgid "Overwrite?"
-msgstr "Überschreiben?"
-
-#: ../src/gui/mainFrame.cpp:2376
+#: ../src/gui/mainFrame.cpp:2416
 msgid "Saved ions: "
 msgstr "Gespeicherte Ionen:"
 
-#: ../src/gui/mainFrame.cpp:2401
+#: ../src/gui/mainFrame.cpp:2441
 msgid "Export Ranges"
 msgstr "Range exportieren"
 
-#: ../src/gui/mainFrame.cpp:2424
+#: ../src/gui/mainFrame.cpp:2464
 msgid "Save state..."
 msgstr "Speichere Status..."
 
-#: ../src/gui/mainFrame.cpp:2425
+#: ../src/gui/mainFrame.cpp:2465
 msgid "XML state file (*.xml)|*.xml|All Files (*)|*"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2466
+#: ../src/gui/mainFrame.cpp:2506
 msgid "Files have been referred to using relative paths. Keep relative paths?"
 msgstr ""
 "Auf Dateien wurde mit relativen Pfaden verwiesen. Relative Pfade beibehalten?"
 
-#: ../src/gui/mainFrame.cpp:2499
+#: ../src/gui/mainFrame.cpp:2539
 msgid "Saved state: "
 msgstr "Gespeicherter Status: "
 
-#: ../src/gui/mainFrame.cpp:2576
+#: ../src/gui/mainFrame.cpp:2616
 msgid "Range editor"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:2872
+#: ../src/gui/mainFrame.cpp:2871
 msgid "Manual not found locally. Launching web browser"
 msgstr "Anleitung konnte lokal nicht gefunden werden. Starte Webbrowser"
 
-#: ../src/gui/mainFrame.cpp:2881
+#: ../src/gui/mainFrame.cpp:2880
 msgid "Opening contact page in external web browser"
 msgstr "Öffne Kontaktseite in externem Browser"
 
-#: ../src/gui/mainFrame.cpp:2893
+#: ../src/gui/mainFrame.cpp:2892
 msgid "No filter stashes to edit."
 msgstr "Keine Filterstashes zum Bearbeiten."
 
-#: ../src/gui/mainFrame.cpp:2897
+#: ../src/gui/mainFrame.cpp:2896
 msgid "Filter Stashes"
 msgstr "Filter Stashes"
 
-#: ../src/gui/mainFrame.cpp:2926
+#: ../src/gui/mainFrame.cpp:2925
 msgid "Quick and dirty analysis for point data."
 msgstr "\"Quick and dirty\" Analyse von Punktdaten."
 
-#: ../src/gui/mainFrame.cpp:2936
+#: ../src/gui/mainFrame.cpp:2935
 msgid "Compiled with wx Version: "
 msgstr "Kompiliert mit wx Version: "
 
-#: ../src/gui/mainFrame.cpp:2957
+#: ../src/gui/mainFrame.cpp:2956
 msgid "Press enter to store new stash"
 msgstr "Eingabe drücken um neuen Filterstash zu speichern"
 
-#: ../src/gui/mainFrame.cpp:2963
+#: ../src/gui/mainFrame.cpp:2962
 msgid "Press enter to restore stash"
 msgstr "Eingabe drücken um Stash wiederherzustellen"
 
-#: ../src/gui/mainFrame.cpp:2998
+#: ../src/gui/mainFrame.cpp:2997
 msgid "Unable to create stash, selection invalid"
 msgstr "Stash kann nicht erstellt werden, Auswahl ungültig"
 
-#: ../src/gui/mainFrame.cpp:3006
+#: ../src/gui/mainFrame.cpp:3005
 msgid "Created new filter tree stash"
 msgstr "Neuer Filterstash wurde erzeugt"
 
-#: ../src/gui/mainFrame.cpp:3128
+#: ../src/gui/mainFrame.cpp:3132
 msgid "Filter type not a data source - can't be at tree base"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3302
+#: ../src/gui/mainFrame.cpp:3309
 msgid "Moving - Hold ⌘ (command) to copy"
 msgstr "Verschieben - Halte ⌘ (command) um zu kopieren"
 
-#: ../src/gui/mainFrame.cpp:3304
+#: ../src/gui/mainFrame.cpp:3311
 msgid "Moving - Hold control to copy"
 msgstr "Verschieben - Halte Strg zum kopieren"
 
-#: ../src/gui/mainFrame.cpp:3647
+#: ../src/gui/mainFrame.cpp:3630
 msgid "Press enter to store new camera"
 msgstr "Eingabe drücken um neue Kamera zu speichern"
 
-#: ../src/gui/mainFrame.cpp:3649
+#: ../src/gui/mainFrame.cpp:3632
 msgid "Press enter to restore camera"
 msgstr "Eingabe drücken um Kamera wiederherzustellen"
 
-#: ../src/gui/mainFrame.cpp:3674 ../src/gui/mainFrame.cpp:3715
+#: ../src/gui/mainFrame.cpp:3657 ../src/gui/mainFrame.cpp:3698
 msgid "Restored camera: "
 msgstr "Wiederhergestellte Kamera: "
 
-#: ../src/gui/mainFrame.cpp:3694
+#: ../src/gui/mainFrame.cpp:3677
 msgid "Stored camera: "
 msgstr "Gespeicherte Kamera: "
 
-#: ../src/gui/mainFrame.cpp:3775
+#: ../src/gui/mainFrame.cpp:3759
 msgid "Select an item from the filter tree before choosing a new filter"
 msgstr ""
 "Aktivieren Sie zuerst ein Punkt aus dem Filterverlauf bevor Sie einen neuen "
 "Filter auswählen"
 
-#: ../src/gui/mainFrame.cpp:3777
+#: ../src/gui/mainFrame.cpp:3761
 msgid "Load data source (file->open) before choosing a new filter"
 msgstr "Lade Datenquelle (Datei->öffnen) vor dem Auswählen eines neuen Filters"
 
-#: ../src/gui/mainFrame.cpp:3798
+#: ../src/gui/mainFrame.cpp:3785
 msgid "Select RNG File..."
 msgstr "RNG Datei auswählen..."
 
-#: ../src/gui/mainFrame.cpp:3799
-msgid ""
-"Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
-"Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"
-msgstr ""
-"Rangedatei (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
-"Environment Datei (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|Alle Dateien (*)|*"
-
-#: ../src/gui/mainFrame.cpp:3819
+#: ../src/gui/mainFrame.cpp:3806
 msgid "Failed reading range file."
 msgstr "Fehler beim Lesen der Rangedatei."
 
-#: ../src/gui/mainFrame.cpp:3823
+#: ../src/gui/mainFrame.cpp:3810
 msgid "Error loading file"
 msgstr "Fehler beim Laden der Datei"
 
-#: ../src/gui/mainFrame.cpp:3881 ../src/gui/mainFrame.cpp:3947
-#: ../src/gui/mainFrame.cpp:5508 ../src/gui/mainFrame.cpp:6063
+#: ../src/gui/mainFrame.cpp:3870 ../src/gui/mainFrame.cpp:3937
+#: ../src/gui/mainFrame.cpp:5268 ../src/gui/mainFrame.cpp:5802
 msgid "Cons."
 msgstr "Kons."
 
-#: ../src/gui/mainFrame.cpp:3914
+#: ../src/gui/mainFrame.cpp:3904
 msgid "Refresh Aborted."
 msgstr "Aktualisieren abgebrochen"
 
-#: ../src/gui/mainFrame.cpp:3951
+#: ../src/gui/mainFrame.cpp:3941
 msgid "*Cons."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:3953
+#: ../src/gui/mainFrame.cpp:3943
 msgid "§Cons."
 msgstr "§Kons."
 
-#: ../src/gui/mainFrame.cpp:4076
+#: ../src/gui/mainFrame.cpp:4037
+msgid "msgs"
+msgstr ""
+
+#: ../src/gui/mainFrame.cpp:4077
 msgid "Autosave complete."
 msgstr "Autosave beendet."
 
-#: ../src/gui/mainFrame.cpp:4243
+#: ../src/gui/mainFrame.cpp:4273
 msgid "Aborted."
 msgstr "Abgebrochen"
 
-#: ../src/gui/mainFrame.cpp:4294
+#: ../src/gui/mainFrame.cpp:4324
 msgid "Updated."
 msgstr "Updated."
 
-#: ../src/gui/mainFrame.cpp:4301
+#: ../src/gui/mainFrame.cpp:4331
 msgid "\\% Done (Esc aborts)"
 msgstr "\\% fertig (Esc abbrechen)"
 
-#: ../src/gui/mainFrame.cpp:4303
+#: ../src/gui/mainFrame.cpp:4333
 msgid "\\% Done"
 msgstr "\\% fertig"
 
-#: ../src/gui/mainFrame.cpp:4562 ../src/gui/mainFrame.cpp:4569
-msgid "Next Fullscreen mode: none"
-msgstr "Nächster Vollbildmodus: keiner"
-
-#: ../src/gui/mainFrame.cpp:4565
-msgid "Next Fullscreen mode: complete"
-msgstr "Nächster Vollbildmodus: vollständig"
-
-#: ../src/gui/mainFrame.cpp:4573
-msgid "Next Fullscreen mode: with toolbars"
-msgstr "Nächster Vollbildmodus: mit Werkzeugleisten"
-
-#: ../src/gui/mainFrame.cpp:4589
-msgid "Next Mode: No fullscreen"
-msgstr "Nächster Modus: Kein Vollbild"
-
-#: ../src/gui/mainFrame.cpp:4593
-msgid "Next Mode: fullscreen w/o toolbar"
-msgstr "Nächster Modus: Vollbild ohne Werkzeugleiste"
-
-#: ../src/gui/mainFrame.cpp:4597
-msgid "Next Mode: fullscreen with toolbar"
-msgstr "Nächster Modus: Vollbild mit Werkzeugleiste"
-
-#: ../src/gui/mainFrame.cpp:4638
+#: ../src/gui/mainFrame.cpp:4609
 msgid "Tip: You can shift-click to force full refresh, if required"
 msgstr "Tipp: Verwende shift-click um komplettes Aktualisieren zu erzwingen"
 
-#: ../src/gui/mainFrame.cpp:4910
+#: ../src/gui/mainFrame.cpp:4672
 msgid "No data to save"
 msgstr "Keine Daten zum Sichern"
 
-#: ../src/gui/mainFrame.cpp:5082
+#: ../src/gui/mainFrame.cpp:4842
 msgid "Aborting..."
 msgstr "Abbrechen..."
 
-#: ../src/gui/mainFrame.cpp:5088
+#: ../src/gui/mainFrame.cpp:4848
 msgid ""
 "Waiting for refresh to abort. Exiting could lead to the program "
 "backgrounding. Exit anyway? "
@@ -2048,63 +2002,63 @@ msgstr ""
 "Waiting for refresh to abort. Exiting could lead to the program "
 "backgrounding. Exit anyway? "
 
-#: ../src/gui/mainFrame.cpp:5089 ../src/gui/mainFrame.cpp:5109
+#: ../src/gui/mainFrame.cpp:4849 ../src/gui/mainFrame.cpp:4869
 msgid "Confirmation request"
 msgstr "Bestätigungsabfrage"
 
-#: ../src/gui/mainFrame.cpp:5108
+#: ../src/gui/mainFrame.cpp:4868
 msgid "Are you sure you wish to exit 3Depict?"
 msgstr "Sind Sie sicher, dass Sie 3Depict beenden wollen?"
 
-#: ../src/gui/mainFrame.cpp:5536
+#: ../src/gui/mainFrame.cpp:5296
 msgid "Update Notice: New version "
 msgstr "Updatenotiz: Neue Version "
 
-#: ../src/gui/mainFrame.cpp:5536
+#: ../src/gui/mainFrame.cpp:5296
 msgid " found online."
 msgstr " online gefunden."
 
-#: ../src/gui/mainFrame.cpp:5540
+#: ../src/gui/mainFrame.cpp:5300
 msgid "Online Check: "
 msgstr "Überprüfe online:"
 
-#: ../src/gui/mainFrame.cpp:5540
+#: ../src/gui/mainFrame.cpp:5300
 msgid " is up-to-date."
 msgstr "ist up-to-date."
 
-#: ../src/gui/mainFrame.cpp:5630
+#: ../src/gui/mainFrame.cpp:5395
 msgid "An auto-save state was found, would you like to restore it?."
 msgstr "Ein auto-save Status wurde gefunden. Wollen Sie ihn wiederherstellen?"
 
-#: ../src/gui/mainFrame.cpp:5631
+#: ../src/gui/mainFrame.cpp:5396
 msgid "Autosave"
 msgstr "Automatisch speichern"
 
-#: ../src/gui/mainFrame.cpp:5638
+#: ../src/gui/mainFrame.cpp:5403
 msgid "Unable to load autosave file.."
 msgstr "Kann Autosavedatei nicht laden.."
 
-#: ../src/gui/mainFrame.cpp:5830
+#: ../src/gui/mainFrame.cpp:5600
 msgid "List of available filters"
 msgstr "Liste der verfügbaren Filter"
 
-#: ../src/gui/mainFrame.cpp:5832
+#: ../src/gui/mainFrame.cpp:5602
 msgid "Tree - drag to move items, hold ⌘ for copy. Tap delete to remove items"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5834
+#: ../src/gui/mainFrame.cpp:5604
 msgid ""
 "Tree - drag to move items, hold Ctrl for copy. Tap delete to remove items."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5836
+#: ../src/gui/mainFrame.cpp:5606
 msgid ""
 "Enable/Disable automatic updates of data when filter change takes effect"
 msgstr ""
 "Ein/Ausschalten vom automatischen Aktualisieren der Daten wenn Änderungen am "
 "Filter wirksam werden"
 
-#: ../src/gui/mainFrame.cpp:5839
+#: ../src/gui/mainFrame.cpp:5609
 msgid ""
 "Enable/Disable \"Alpha blending\" (transparency) in rendering system. "
 "Blending is used to smooth objects (avoids artefacts known as \"jaggies\") "
@@ -2116,7 +2070,7 @@ msgstr ""
 "und transparente Oberflächen zu generieren. Ausschalten erlaubt schnelleres "
 "Renden führt jedoch zu blockigerer Darstellung."
 
-#: ../src/gui/mainFrame.cpp:5840
+#: ../src/gui/mainFrame.cpp:5610
 msgid ""
 "Enable/Disable lighting calculations in rendering, for objects that request "
 "this. Lighting provides important depth cues for objects comprised of 3D "
@@ -2127,7 +2081,7 @@ msgstr ""
 "umrandete Objekte. Deaktivieren erlaubt u.U. schnelleres Rendern bei "
 "komplizierten Szenen."
 
-#: ../src/gui/mainFrame.cpp:5841
+#: ../src/gui/mainFrame.cpp:5611
 msgid ""
 "Enable/Disable weak randomisation (Galois linear feedback shift register). "
 "Strong randomisation uses a much slower random selection method, but "
@@ -2139,14 +2093,14 @@ msgstr ""
 "Auswahlmethode bietet dafür aber einen besseren Schutz gegen unbeabsichtigte "
 "Korrelationen und wird für die endgültige Analyse empfohlen."
 
-#: ../src/gui/mainFrame.cpp:5843
+#: ../src/gui/mainFrame.cpp:5613
 msgid ""
 "Limit the number of points that can be displayed in the 3D  scene. Does not "
 "affect filter tree calculations. Disabling this can severely reduce "
 "performance, due to large numbers of points being visible at once."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5844
+#: ../src/gui/mainFrame.cpp:5614
 msgid ""
 "Enable/Disable caching of intermediate results during filter updates. "
 "Disabling caching will use less system RAM, though changes to any filter "
@@ -2158,30 +2112,30 @@ msgstr ""
 "bei Änderungen der Filterparameter der ganze Filterbaum neu berechnet wird. "
 "Dies erhöht den Rechenaufwand deutlich."
 
-#: ../src/gui/mainFrame.cpp:5855
+#: ../src/gui/mainFrame.cpp:5616
 msgid "Camera data information"
 msgstr "Kamerainformation"
 
-#: ../src/gui/mainFrame.cpp:5859
+#: ../src/gui/mainFrame.cpp:5620
 msgid "Enable/disable visual effects on final 3D output"
 msgstr "Ein/Ausschalten von visuellen Effekten in der finalen 3D Ausgabe."
 
-#: ../src/gui/mainFrame.cpp:5861
+#: ../src/gui/mainFrame.cpp:5622
 msgid "Enable cropping post-process effect"
 msgstr "Cropping post-Prozess Effect einschalten"
 
-#: ../src/gui/mainFrame.cpp:5864
+#: ../src/gui/mainFrame.cpp:5625
 msgid ""
 "Colour based 3D effect enable/disable - requires appropriate colour filter "
 "3D glasses."
 msgstr ""
 "Farbbasierte 3D-Effekte ein/ausschalten - erfordert geeignete 3D-Brillen"
 
-#: ../src/gui/mainFrame.cpp:5865
+#: ../src/gui/mainFrame.cpp:5626
 msgid "Glasses colour mode"
 msgstr "Brillenfarbmodus"
 
-#: ../src/gui/mainFrame.cpp:5867
+#: ../src/gui/mainFrame.cpp:5628
 msgid ""
 "Level of separation between left and right images, which sets 3D depth to "
 "visual distortion tradeoff"
@@ -2189,92 +2143,95 @@ msgstr ""
 "Level of separation between left and right images, which sets 3D depth to "
 "visual distortion tradeoff"
 
-#: ../src/gui/mainFrame.cpp:5871
+#: ../src/gui/mainFrame.cpp:5632
 msgid "X"
 msgstr "X"
 
-#: ../src/gui/mainFrame.cpp:5872
+#: ../src/gui/mainFrame.cpp:5633
 msgid "Y"
 msgstr "Y"
 
-#: ../src/gui/mainFrame.cpp:5873
+#: ../src/gui/mainFrame.cpp:5634
 msgid "Save raw data to file"
 msgstr "Speichere Rohdaten in Datei"
 
-#: ../src/gui/mainFrame.cpp:5874
+#: ../src/gui/mainFrame.cpp:5635
 msgid "Copy raw data to clipboard"
 msgstr "Kopiere Rohdaten in die Zwischenablage"
 
-#: ../src/gui/mainFrame.cpp:5875
+#: ../src/gui/mainFrame.cpp:5636
 msgid "Manage \"stashed\" data."
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5876
+#: ../src/gui/mainFrame.cpp:5637
 msgid "Program text output"
 msgstr "Programm Textausgabe"
 
-#: ../src/gui/mainFrame.cpp:5877
+#: ../src/gui/mainFrame.cpp:5638
 msgid "Select active camera, or type to create new named camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5878
+#: ../src/gui/mainFrame.cpp:5639
 msgid "Remove the selected camera"
 msgstr "Ausgewählte Kamera entfernen"
 
-#: ../src/gui/mainFrame.cpp:5879
+#: ../src/gui/mainFrame.cpp:5640
 msgid "Perform cropping from coordinate frame of camera"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5880
+#: ../src/gui/mainFrame.cpp:5641
 msgid ""
 "Set the maximum amount of RAM to use in order to speed repeat computations"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5881
+#: ../src/gui/mainFrame.cpp:5642
 msgid "Collapse the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5882
+#: ../src/gui/mainFrame.cpp:5643
 msgid "Expand the filter tree"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:5883
+#: ../src/gui/mainFrame.cpp:5644
 msgid "Process the filter tree, hold shift to purge cached filter data"
 msgstr ""
 
-#: ../src/gui/mainFrame.cpp:6023
+#: ../src/gui/mainFrame.cpp:5762
 msgid "Crop"
 msgstr "Zuschneiden"
 
-#: ../src/gui/mainFrame.cpp:6024
+#: ../src/gui/mainFrame.cpp:5763
 msgid "Stereo"
 msgstr "Stereo"
 
-#: ../src/gui/mainFrame.cpp:6041
+#: ../src/gui/mainFrame.cpp:5780
+#: ../src/backend/filters/externalProgram.cpp:577
+#: ../src/backend/filters/ionColour.cpp:312
+#: ../src/backend/filters/spectrumPlot.cpp:418
 msgid "Data"
 msgstr "Daten"
 
-#: ../src/gui/mainFrame.cpp:6042
+#: ../src/gui/mainFrame.cpp:5781
 msgid "Cam"
 msgstr "Cam"
 
-#: ../src/gui/mainFrame.cpp:6043
+#: ../src/gui/mainFrame.cpp:5782
 msgid "Post"
 msgstr "Post"
 
-#: ../src/gui/mainFrame.cpp:6044
+#: ../src/gui/mainFrame.cpp:5783
 msgid "Tools"
 msgstr "Werkz."
 
-#: ../src/gui/mainFrame.cpp:6062
+#: ../src/gui/mainFrame.cpp:5801
 msgid "Raw"
 msgstr "Roh"
 
-#: ../src/gui/mathglPane.cpp:230
+#: ../src/gui/mathglPane.cpp:241
 msgid "No plots selected."
 msgstr "Kein Plot ausgewählt."
 
-#: ../src/gui/mathglPane.cpp:1202
+#: ../src/gui/mathglPane.cpp:1165
 msgid ""
 "Unable to allocate requested memory.\n"
 " Try a lower resolution, or save as vector (SVG)."
@@ -2282,37 +2239,23 @@ msgstr ""
 "Kann den notwendigen Speicher nicht zuordnen. Versuche eine geringer "
 "Auflösung oder speichere als Vektografik (svg)."
 
-#: ../src/gui/mathglPane.cpp:1204
+#: ../src/gui/mathglPane.cpp:1167
 msgid "Plotting functions returned an error:\n"
 msgstr "Plot-Funktion meldete einen Fehler:\n"
 
-#: ../src/gui/mathglPane.cpp:1206
+#: ../src/gui/mathglPane.cpp:1169
 msgid "File readback check failed"
 msgstr "File readback check failed"
 
-#: ../src/gui/mathglPane.cpp:1208
+#: ../src/gui/mathglPane.cpp:1171
 msgid "Filesize during readback appears to be zero."
 msgstr "Filesize during readback appears to be zero."
 
-#: ../src/3Depict.cpp:78
-msgid "displays this message"
-msgstr "zeigt diese Nachricht"
-
-#: ../src/3Depict.cpp:80
-msgid "inputfile"
-msgstr "Eingabedatei"
-
-#: ../src/3Depict.cpp:89
-msgid ""
-"Run debug unit tests, returns nonzero on test failure, zero on success.\n"
-"\t\tXML files may be passed to run, instead of default tests"
-msgstr ""
-
-#: ../src/3Depict.cpp:383
+#: ../src/3Depict.cpp:381
 msgid "File : "
 msgstr "Datei : "
 
-#: ../src/3Depict.cpp:383
+#: ../src/3Depict.cpp:381
 msgid " does not exist. Skipping"
 msgstr " existiert nicht. Überspringe"
 
@@ -2328,12 +2271,12 @@ msgstr "Kann den letzten Dateieintrag nicht interpretieren"
 msgid "Unable to determine filter type in defaults listing."
 msgstr "Kann den Filtertyp im Defaultslisting nicht bestimmen."
 
-#: ../src/backend/configFile.cpp:610
+#: ../src/backend/configFile.cpp:604
 msgid "Online access for non win32/apple platforms is intentionally disabled, "
 msgstr ""
 "Onlinezugang für nicht Win32/apple systeme wurde absichtlich deaktiviert."
 
-#: ../src/backend/configFile.cpp:611
+#: ../src/backend/configFile.cpp:605
 msgid ""
 "regardless of the settings you use here. Use your package manager to keep up-"
 "to-date"
@@ -2341,499 +2284,456 @@ msgstr ""
 "Nutzen Sie Ihren Paketmanager um up-to-date zu sein unabhängig von den "
 "Einstellungen die Sie hier verwenden"
 
-#: ../src/backend/plot.cpp:30 ../src/backend/filters/voxelise.cpp:122
-#: ../src/backend/filters/voxelise.cpp:132
+#: ../src/backend/plot.cpp:28 ../src/backend/filters/voxelise.cpp:123
+#: ../src/backend/filters/voxelise.cpp:133
 msgid "None"
 msgstr "Keiner"
 
-#: ../src/backend/plot.cpp:31
+#: ../src/backend/plot.cpp:29
 msgid "Moving avg."
 msgstr "Gleit.Durchschn."
 
-#: ../src/backend/plot.cpp:35
+#: ../src/backend/plot.cpp:33
 msgid "Lines"
 msgstr "Linien"
 
-#: ../src/backend/plot.cpp:36
+#: ../src/backend/plot.cpp:34
 msgid "Bars"
 msgstr "Block"
 
-#: ../src/backend/plot.cpp:37
+#: ../src/backend/plot.cpp:35
 msgid "Steps"
 msgstr "Stufen"
 
-#: ../src/backend/plot.cpp:38
+#: ../src/backend/plot.cpp:36
 msgid "Stem"
 msgstr "Stem"
 
-#: ../src/backend/plot.cpp:39
+#: ../src/backend/plot.cpp:37
 msgid "Points"
 msgstr "Punkte"
 
-#: ../src/backend/plot.cpp:841 ../src/backend/plot.cpp:849
-msgid "Multiple data types"
+#: ../src/backend/plot.cpp:39
+msgid "Density"
 msgstr ""
 
-#: ../src/backend/plot.cpp:1550
-msgid "error"
-msgstr "Fehler"
+#: ../src/backend/plot.cpp:40
+msgid "Scatter"
+msgstr ""
+
+#: ../src/backend/plot.cpp:787 ../src/backend/plot.cpp:795
+msgid "Multiple data types"
+msgstr ""
+
+#: ../src/backend/plot.cpp:1559
+msgid "error"
+msgstr "Fehler"
+
+#: ../src/backend/plot.cpp:1772
+msgid "Amplitude"
+msgstr ""
 
-#: ../src/backend/filtertree.cpp:1051
+#: ../src/backend/filtertree.cpp:1060
 msgid "WARNING: Skipping node "
 msgstr "WARNUNG: Skipping node "
 
-#: ../src/backend/filtertree.cpp:1051
+#: ../src/backend/filtertree.cpp:1060
 msgid " as it was not recognised"
 msgstr " wurde nicht erkannt."
 
-#: ../src/backend/filtertree.cpp:1089
+#: ../src/backend/filtertree.cpp:1098
 msgid "Error processing node: "
 msgstr "Fehler beim Verarbeiten von Node: "
 
-#: ../src/backend/filters/externalProgram.cpp:543
+#: ../src/backend/filters/externalProgram.cpp:545
+#: ../src/backend/filters/externalProgram.cpp:559
 msgid "Command"
 msgstr "Befehl"
 
-#: ../src/backend/filters/externalProgram.cpp:546
+#: ../src/backend/filters/externalProgram.cpp:548
 msgid ""
 "Full command to send to operating system. See manual for escape sequence "
 "meanings"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:550
+#: ../src/backend/filters/externalProgram.cpp:552
 msgid "Work Dir"
 msgstr "Arbeitsverzeichnis"
 
-#: ../src/backend/filters/externalProgram.cpp:553
+#: ../src/backend/filters/externalProgram.cpp:555
 msgid "Directory to run the command in"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:563
+#: ../src/backend/filters/externalProgram.cpp:562
 msgid "Cleanup input"
 msgstr "Bereinige Eingabe"
 
-#: ../src/backend/filters/externalProgram.cpp:566
+#: ../src/backend/filters/externalProgram.cpp:565
 msgid "Erase input files when command completed"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:575
+#: ../src/backend/filters/externalProgram.cpp:570
 msgid "Cache"
 msgstr "Zwischenspeicher"
 
-#: ../src/backend/filters/externalProgram.cpp:578
+#: ../src/backend/filters/externalProgram.cpp:573
 msgid ""
 "Assume program does not alter its output, unless inputs from 3Depict are "
 "altered"
 msgstr ""
 
-#: ../src/backend/filters/externalProgram.cpp:660
-msgid "Error processing command line"
-msgstr "Fehler beim Ausführen der Kommandozeile"
-
-#: ../src/backend/filters/externalProgram.cpp:662
-msgid "Unable to set working directory"
-msgstr "Kann Arbeitsverzeichnis nicht festlegen"
-
-#: ../src/backend/filters/externalProgram.cpp:664
-msgid "Error saving posfile result for external program"
-msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm"
-
-#: ../src/backend/filters/externalProgram.cpp:666
-msgid "Error saving plot result for externalprogram"
-msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm"
-
-#: ../src/backend/filters/externalProgram.cpp:668
-msgid "Error creating temporary directory"
-msgstr "Fehler beim Anlegen des temporären Verzeichnisses"
-
-#: ../src/backend/filters/externalProgram.cpp:670
-msgid "Detected unusable number of columns in plot"
-msgstr "Detected unusable number of columns in plot"
-
-#: ../src/backend/filters/externalProgram.cpp:672
-msgid "Unable to parse plot result from external program"
-msgstr "Unable to parse plot result from external program"
-
-#: ../src/backend/filters/externalProgram.cpp:674
-msgid "Unable to load ions from external program"
-msgstr "Kann Ionen von externem Programm nicht laden"
-
-#: ../src/backend/filters/externalProgram.cpp:676
-msgid "Unable to perform commandline substitution"
-msgstr "Unable to perform commandline substitution"
-
-#: ../src/backend/filters/externalProgram.cpp:678
-msgid "Error executing external program"
-msgstr "Fehler beim Ausführen von externem Programm"
-
-#: ../src/backend/filters/ionClip.cpp:59
-#: ../src/backend/filters/compositionProfile.cpp:43
+#: ../src/backend/filters/ionClip.cpp:60
+#: ../src/backend/filters/compositionProfile.cpp:44
 msgid "Sphere"
 msgstr "Kugel"
 
-#: ../src/backend/filters/ionClip.cpp:60
+#: ../src/backend/filters/ionClip.cpp:61
 msgid "Plane"
 msgstr "Ebene"
 
-#: ../src/backend/filters/ionClip.cpp:61
-#: ../src/backend/filters/compositionProfile.cpp:42
+#: ../src/backend/filters/ionClip.cpp:62
+#: ../src/backend/filters/compositionProfile.cpp:43
 msgid "Cylinder"
 msgstr "Zylinder"
 
-#: ../src/backend/filters/ionClip.cpp:62
+#: ../src/backend/filters/ionClip.cpp:63
 msgid "Aligned box"
 msgstr "Ausgerichtete Box"
 
-#: ../src/backend/filters/ionClip.cpp:495
+#: ../src/backend/filters/ionClip.cpp:488
+#: ../src/backend/filters/compositionProfile.cpp:943
 msgid "Primitive"
 msgstr "Primitiv"
 
-#: ../src/backend/filters/ionClip.cpp:498
+#: ../src/backend/filters/ionClip.cpp:491
 msgid "Shape of clipping object"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:504
-#: ../src/backend/filters/compositionProfile.cpp:1000
+#: ../src/backend/filters/ionClip.cpp:497
+#: ../src/backend/filters/compositionProfile.cpp:949
 msgid "Show Primitive"
 msgstr "Zeige Primitiv"
 
-#: ../src/backend/filters/ionClip.cpp:507
+#: ../src/backend/filters/ionClip.cpp:500
 msgid "Display the 3D interaction object"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:512
+#: ../src/backend/filters/ionClip.cpp:505
 msgid "Invert Clip"
 msgstr "Invertiere Clip"
 
-#: ../src/backend/filters/ionClip.cpp:515
+#: ../src/backend/filters/ionClip.cpp:508
 msgid ""
 "Switch between retaining points inside (false) and outside (true) of "
 "primitive"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:529
-#: ../src/backend/filters/compositionProfile.cpp:1059
+#: ../src/backend/filters/ionClip.cpp:522
+#: ../src/backend/filters/compositionProfile.cpp:1005
 msgid "Position for centre of sphere"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:534
-#: ../src/backend/filters/ionClip.cpp:597
-#: ../src/backend/filters/compositionProfile.cpp:1042
-#: ../src/backend/filters/compositionProfile.cpp:1064
-#: ../src/backend/filters/spatialAnalysis.cpp:93
-#: ../src/backend/filters/spatialAnalysis.cpp:616
+#: ../src/backend/filters/ionClip.cpp:527
+#: ../src/backend/filters/ionClip.cpp:587
+#: ../src/backend/filters/compositionProfile.cpp:988
+#: ../src/backend/filters/compositionProfile.cpp:1010
+#: ../src/backend/filters/spatialAnalysis.cpp:111
+#: ../src/backend/filters/spatialAnalysis.cpp:791
 msgid "Radius"
 msgstr "Radius"
 
-#: ../src/backend/filters/ionClip.cpp:537
-#: ../src/backend/filters/compositionProfile.cpp:1067
+#: ../src/backend/filters/ionClip.cpp:530
+#: ../src/backend/filters/compositionProfile.cpp:1013
 msgid "Radius of sphere"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:551
+#: ../src/backend/filters/ionClip.cpp:544
 msgid "Position that plane passes through"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:556
+#: ../src/backend/filters/ionClip.cpp:549
 msgid "Plane Normal"
 msgstr "Plane Normal"
 
-#: ../src/backend/filters/ionClip.cpp:559
+#: ../src/backend/filters/ionClip.cpp:552
 msgid "Perpendicular direction for plane"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:573
+#: ../src/backend/filters/ionClip.cpp:566
 msgid "Centre of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:578
-#: ../src/backend/filters/compositionProfile.cpp:1023
-#: ../src/backend/filters/spatialAnalysis.cpp:607
-#: ../src/backend/filters/transform.cpp:1325
+#: ../src/backend/filters/ionClip.cpp:571
+#: ../src/backend/filters/compositionProfile.cpp:972
+#: ../src/backend/filters/spatialAnalysis.cpp:782
+#: ../src/backend/filters/transform.cpp:1277
 msgid "Axis"
 msgstr "Achse"
 
-#: ../src/backend/filters/ionClip.cpp:581
+#: ../src/backend/filters/ionClip.cpp:574
 msgid "Positive vector for cylinder"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:589
-#: ../src/backend/filters/compositionProfile.cpp:1034
+#: ../src/backend/filters/ionClip.cpp:579
+#: ../src/backend/filters/compositionProfile.cpp:980
 msgid "Lock Axis Mag."
 msgstr "Achsen Vergr. sperren"
 
-#: ../src/backend/filters/ionClip.cpp:592
+#: ../src/backend/filters/ionClip.cpp:582
 msgid "Prevent changing length of cylinder during 3D interaction"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:600
-#: ../src/backend/filters/compositionProfile.cpp:1045
-#: ../src/backend/filters/spatialAnalysis.cpp:619
+#: ../src/backend/filters/ionClip.cpp:590
+#: ../src/backend/filters/compositionProfile.cpp:991
+#: ../src/backend/filters/spatialAnalysis.cpp:794
 msgid "Radius of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:613
+#: ../src/backend/filters/ionClip.cpp:603
 msgid "Centre of axis aligned box"
 msgstr ""
 
-#: ../src/backend/filters/ionClip.cpp:618
+#: ../src/backend/filters/ionClip.cpp:608
 msgid "Corner offset"
 msgstr "Corner offset"
 
-#: ../src/backend/filters/ionClip.cpp:621
+#: ../src/backend/filters/ionClip.cpp:611
 msgid "Vector to corner of box"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:77
-#: ../src/backend/filters/clusterAnalysis.cpp:1017
+#: ../src/backend/filters/clusterAnalysis.cpp:80
+#: ../src/backend/filters/clusterAnalysis.cpp:1045
 msgid "Size Distribution"
 msgstr "Größenverteilung"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:78
+#: ../src/backend/filters/clusterAnalysis.cpp:81
 msgid "Chemistry Distribution"
 msgstr "Chemische Verteilung"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:491
+#: ../src/backend/filters/clusterAnalysis.cpp:499
 msgid "No range data. Can't cluster."
 msgstr "Keine Rangedaten. Clusteranalyse nicht möglich."
 
-#: ../src/backend/filters/clusterAnalysis.cpp:502
+#: ../src/backend/filters/clusterAnalysis.cpp:510
 msgid ""
 "No ranges selected for cluster \"core\". Cannot continue with clustering."
 msgstr ""
 "Kein Range für cluster \"core\" ausgewählt. Kann mit Clusteranalyse nicht "
 "weitermachen."
 
-#: ../src/backend/filters/clusterAnalysis.cpp:511
+#: ../src/backend/filters/clusterAnalysis.cpp:519
 msgid ""
 "No ranges selected for cluster \"bulk\". Cannot continue with clustering."
 msgstr ""
 "Kein Range für \"bulk\" ausgewählt. Kann mit Clusteranalyse nicht "
 "weitermachen."
 
-#: ../src/backend/filters/clusterAnalysis.cpp:684
-msgid "Morphology Plot"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:685
-msgid "\\lambda_1:\\lambda_2 ratio"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:686
-msgid "\\lambda_2:\\lambda_3 ratio"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:723
-msgid "No clusters had sufficient dimensionality to compute singular values"
-msgstr ""
-
-#: ../src/backend/filters/clusterAnalysis.cpp:780
+#: ../src/backend/filters/clusterAnalysis.cpp:789
 msgid "Found :"
 msgstr "Gefunden:"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:782
+#: ../src/backend/filters/clusterAnalysis.cpp:791
 msgid " clusters"
 msgstr " Cluster"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:850
+#: ../src/backend/filters/clusterAnalysis.cpp:873
 msgid "Compositions (fractional, core+bulk)"
 msgstr "Zusammensetzungen (fractional, core+bulk)"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:852
+#: ../src/backend/filters/clusterAnalysis.cpp:875
 msgid "Compositions (fractional, core only)"
 msgstr "Zusammensetzungen (fractional, core only)"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:870
+#: ../src/backend/filters/clusterAnalysis.cpp:893
 msgid "Frequencies (core+bulk)"
 msgstr "Häufigkeiten (core+bulk)"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:898
+#: ../src/backend/filters/clusterAnalysis.cpp:924
 msgid "Core Link + Erode"
 msgstr "Core Link + Erode"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:902
-#: ../src/backend/filters/spatialAnalysis.cpp:373
-#: ../src/backend/filters/ionInfo.cpp:440
+#: ../src/backend/filters/clusterAnalysis.cpp:928
+#: ../src/backend/filters/clusterAnalysis.cpp:936
+#: ../src/backend/filters/spatialAnalysis.cpp:541
+#: ../src/backend/filters/spatialAnalysis.cpp:549
+#: ../src/backend/filters/transform.cpp:1140
+#: ../src/backend/filters/ionInfo.cpp:441
 msgid "Algorithm"
 msgstr "Algorithmus"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:906
+#: ../src/backend/filters/clusterAnalysis.cpp:932
 msgid "Cluster algorithm mode"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:915
+#: ../src/backend/filters/clusterAnalysis.cpp:943
 msgid "Core Classify"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:918
+#: ../src/backend/filters/clusterAnalysis.cpp:946
 msgid ""
 "Enable core-classifcation pre-step in clustering (Stephenson et al, 2007)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:924
+#: ../src/backend/filters/clusterAnalysis.cpp:952
 msgid "Core Classify Dist"
 msgstr "Core Classify Dist"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:927
+#: ../src/backend/filters/clusterAnalysis.cpp:955
 msgid "Restrict only atoms by distance to be cluster sources"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:932
+#: ../src/backend/filters/clusterAnalysis.cpp:960
 msgid "Classify Knn Max"
 msgstr "Classify Knn Max"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:935
+#: ../src/backend/filters/clusterAnalysis.cpp:963
 msgid ""
 "Require that the kth NN (this number) is within the classify distance, to be "
 "a cluster source"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:941
+#: ../src/backend/filters/clusterAnalysis.cpp:969
 msgid "Core Link Dist"
 msgstr "Core Link Dist"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:944
+#: ../src/backend/filters/clusterAnalysis.cpp:972
 msgid "Distance between clusters to allow linking"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:949
+#: ../src/backend/filters/clusterAnalysis.cpp:977
 msgid "Bulk Link"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:952
-#: ../src/backend/filters/clusterAnalysis.cpp:970
+#: ../src/backend/filters/clusterAnalysis.cpp:980
+#: ../src/backend/filters/clusterAnalysis.cpp:998
 msgid "Enable  linking of non-cluster species - eg for composition analysis "
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:959
+#: ../src/backend/filters/clusterAnalysis.cpp:987
 msgid "Bulk Link (Envelope) Dist"
 msgstr "Bulk Link (Envelope) Dist"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:962
+#: ../src/backend/filters/clusterAnalysis.cpp:990
 msgid ""
 "Distance from core points that form cluster that is used to grab surrounding "
 "bulk points"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:967
+#: ../src/backend/filters/clusterAnalysis.cpp:995
 msgid "Erosion"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:976
+#: ../src/backend/filters/clusterAnalysis.cpp:1004
 msgid "Erode Dist"
 msgstr "Erode Dist"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:979
+#: ../src/backend/filters/clusterAnalysis.cpp:1007
 msgid ""
 "Distance from unclustered material in which bulk points are eroded from "
 "cluster"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:985
+#: ../src/backend/filters/clusterAnalysis.cpp:1013
 msgid "Clustering Params"
 msgstr "Cluster Parameter"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:990
+#: ../src/backend/filters/clusterAnalysis.cpp:1018
 msgid "Size Cropping"
 msgstr "Größeneinschrankungen"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:993
+#: ../src/backend/filters/clusterAnalysis.cpp:1021
 msgid "Remove clusters based upon size distribution"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1000
+#: ../src/backend/filters/clusterAnalysis.cpp:1028
 msgid "Min Size"
 msgstr "Min Größe"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1003
+#: ../src/backend/filters/clusterAnalysis.cpp:1031
 msgid "Remove clusters below this size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1008
+#: ../src/backend/filters/clusterAnalysis.cpp:1036
 msgid "Max Size"
 msgstr "Max Größe"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1011
+#: ../src/backend/filters/clusterAnalysis.cpp:1039
 msgid "Remove clusters above this size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1020
+#: ../src/backend/filters/clusterAnalysis.cpp:1048
 msgid "Show number of clusters as a function of cluster size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1026
+#: ../src/backend/filters/clusterAnalysis.cpp:1054
 msgid "Log Scale"
 msgstr "Log. Skala"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1029
+#: ../src/backend/filters/clusterAnalysis.cpp:1057
 msgid "Use logarithmic scale for size distribution"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1045
+#: ../src/backend/filters/clusterAnalysis.cpp:1075
+msgid "Cluster Id"
+msgstr ""
+
+#: ../src/backend/filters/clusterAnalysis.cpp:1078
+msgid "Assign cluster output a unique per-cluster value (id)."
+msgstr ""
+
+#: ../src/backend/filters/clusterAnalysis.cpp:1085
 msgid "Chemistry Dist."
 msgstr "Chemistry Dist."
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1048
+#: ../src/backend/filters/clusterAnalysis.cpp:1088
 msgid "Create a plot showing chemistry for each cluster size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1055
-#: ../src/backend/filters/compositionProfile.cpp:1107
-#: ../src/backend/filters/spatialAnalysis.cpp:674
+#: ../src/backend/filters/clusterAnalysis.cpp:1095
+#: ../src/backend/filters/compositionProfile.cpp:1053
+#: ../src/backend/filters/spatialAnalysis.cpp:849
 #: ../src/backend/filters/ionInfo.cpp:412
 msgid "Normalise"
 msgstr "Normalisieren"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1058
+#: ../src/backend/filters/clusterAnalysis.cpp:1098
 msgid "Convert cluster counts to composition"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1064
+#: ../src/backend/filters/clusterAnalysis.cpp:1104
 msgid "Postprocess"
 msgstr "Postprozess"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1083
+#: ../src/backend/filters/clusterAnalysis.cpp:1123
 msgid "If selected, use as \"core\" ion type (can make clusters)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1088
+#: ../src/backend/filters/clusterAnalysis.cpp:1128
 msgid "Core Ranges"
 msgstr "Core Ranges"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1102
+#: ../src/backend/filters/clusterAnalysis.cpp:1142
 msgid ""
 "If selected, use as \"bulk\" ion type (can be included in existing clusters)"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1107
+#: ../src/backend/filters/clusterAnalysis.cpp:1147
 msgid "Bulk Ranges"
 msgstr "Bulk Ranges"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1123
+#: ../src/backend/filters/clusterAnalysis.cpp:1163
 msgid "Max. Sep + Erode"
 msgstr "Max. Sep + Erode"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1803
-msgid "Clustering aborted"
-msgstr "Clustering abgebrochen"
-
-#: ../src/backend/filters/clusterAnalysis.cpp:1805
-msgid "No core ions for cluster"
-msgstr "Keine Kernionen für Cluster"
-
-#: ../src/backend/filters/clusterAnalysis.cpp:1807
-msgid "No bulk ions for cluster"
-msgstr "Keine Bulkionen für Cluster"
-
-#: ../src/backend/filters/clusterAnalysis.cpp:1885
+#: ../src/backend/filters/clusterAnalysis.cpp:1891
 msgid " --------------------------- Parameter selection notice ------------- "
 msgstr " --------------------------- Parameterauswahl Notiz ------------- "
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1886
+#: ../src/backend/filters/clusterAnalysis.cpp:1892
 msgid "You have specified a bulk distance larger than half your link distance."
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1887
+#: ../src/backend/filters/clusterAnalysis.cpp:1893
 msgid ""
 "You can do this; thats OK, but the output is no longer independent of the "
 "computational process;"
@@ -2841,7 +2741,7 @@ msgstr ""
 "Sie könne das machen, das ist in Ordnung, aber die Ausgabe ist nicht länger "
 "unabhängig vom Berechnungsprozess"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1888
+#: ../src/backend/filters/clusterAnalysis.cpp:1894
 msgid ""
 "This will be a problem in the case where two or more clusters can equally "
 "lay claim to a \"bulk\" ion. "
@@ -2849,7 +2749,7 @@ msgstr ""
 "Dies ist ein Problem wenn zwei oder mehrere Cluster auf dasselbe \"bulk\" "
 "Ion Anspruch erheben. "
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1889
+#: ../src/backend/filters/clusterAnalysis.cpp:1895
 msgid ""
 " If your inter-cluster distance is sufficiently large (larger than your bulk "
 "linking distance), then you can get away with this."
@@ -2857,7 +2757,7 @@ msgstr ""
 " If your inter-cluster distance is sufficiently large (larger than your bulk "
 "linking distance), then you can get away with this."
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1890
+#: ../src/backend/filters/clusterAnalysis.cpp:1896
 msgid ""
 " In theory it is possible to \"join\" the clusters, but this has not been "
 "implemented for speed reasons."
@@ -2865,7 +2765,7 @@ msgstr ""
 "Theoretisch ist es möglich die Cluster zu 'verbinden', dies wurde jedoch aus "
 "Gescheindigkeitsgründen nicht implementiert."
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1891
+#: ../src/backend/filters/clusterAnalysis.cpp:1897
 msgid ""
 "If you want this, please contact the author, or just use the source to add "
 "this in yourself."
@@ -2873,752 +2773,773 @@ msgstr ""
 "Sollten Sie dies wollen, kontaktieren Sie den Autor oder verwenden Sie den "
 "Sourcecode um es selbst hinzuzufügen."
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1892
+#: ../src/backend/filters/clusterAnalysis.cpp:1898
 msgid "---------------------------------------------------------------------- "
 msgstr "---------------------------------------------------------------------- "
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1902
-#: ../src/backend/filters/spatialAnalysis.cpp:1757
-#: ../src/backend/filters/spatialAnalysis.cpp:2084
-#: ../src/backend/filters/spatialAnalysis.cpp:2382
-#: ../src/backend/filters/spatialAnalysis.cpp:3078
-#: ../src/backend/filters/transform.cpp:1033
+#: ../src/backend/filters/clusterAnalysis.cpp:1908
+#: ../src/backend/filters/spatialAnalysis.cpp:1971
+#: ../src/backend/filters/spatialAnalysis.cpp:2314
+#: ../src/backend/filters/spatialAnalysis.cpp:2605
+#: ../src/backend/filters/spatialAnalysis.cpp:3293
+#: ../src/backend/filters/transform.cpp:991
 msgid "Collate"
 msgstr "Abgleichen"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1921
+#: ../src/backend/filters/clusterAnalysis.cpp:1927
 msgid "Build Core"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:1939
+#: ../src/backend/filters/clusterAnalysis.cpp:1945
 msgid "Classify Core"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2032
+#: ../src/backend/filters/clusterAnalysis.cpp:2038
 msgid "Build Bulk"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2052
+#: ../src/backend/filters/clusterAnalysis.cpp:2058
 msgid "Core"
 msgstr "Kern"
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2197
+#: ../src/backend/filters/clusterAnalysis.cpp:2203
 msgid "Bulk"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2327
+#: ../src/backend/filters/clusterAnalysis.cpp:2333
 msgid "Erode"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2401
+#: ../src/backend/filters/clusterAnalysis.cpp:2407
 msgid "Re-Collate"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2669
-#: ../src/backend/filters/clusterAnalysis.cpp:2873
+#: ../src/backend/filters/clusterAnalysis.cpp:2675
+#: ../src/backend/filters/clusterAnalysis.cpp:2879
 msgid "Cluster Size"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2670
-#: ../src/backend/filters/clusterAnalysis.cpp:2877
+#: ../src/backend/filters/clusterAnalysis.cpp:2676
+#: ../src/backend/filters/clusterAnalysis.cpp:2883
 msgid "Frequency"
 msgstr ""
 
-#: ../src/backend/filters/clusterAnalysis.cpp:2875
+#: ../src/backend/filters/clusterAnalysis.cpp:2881
 msgid "Composition"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:109
+#: ../src/backend/filters/voxelise.cpp:110
 msgid "None (Raw count)"
 msgstr "Keine (Roh count)"
 
-#: ../src/backend/filters/voxelise.cpp:110
+#: ../src/backend/filters/voxelise.cpp:111
 msgid "Volume (Density)"
 msgstr "Volumen (Dichte)"
 
-#: ../src/backend/filters/voxelise.cpp:111
+#: ../src/backend/filters/voxelise.cpp:112
 msgid "All Ions (conc)"
 msgstr "Alle Ionen (Konz)"
 
-#: ../src/backend/filters/voxelise.cpp:112
+#: ../src/backend/filters/voxelise.cpp:113
 msgid "Ratio (Num/Denom)"
 msgstr "Verhältnis (Zähler/Nenner)"
 
-#: ../src/backend/filters/voxelise.cpp:116
+#: ../src/backend/filters/voxelise.cpp:117
 msgid "Point Cloud"
 msgstr "Punktwolke"
 
-#: ../src/backend/filters/voxelise.cpp:117
+#: ../src/backend/filters/voxelise.cpp:118
 msgid "Isosurface"
 msgstr "Isosurface"
 
-#: ../src/backend/filters/voxelise.cpp:118
+#: ../src/backend/filters/voxelise.cpp:119
 msgid "Axial slice"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:123
+#: ../src/backend/filters/voxelise.cpp:124
 msgid "Gaussian (2𝜎)"
 msgstr "Gauss (2𝜎)"
 
-#: ../src/backend/filters/voxelise.cpp:127
+#: ../src/backend/filters/voxelise.cpp:128
 msgid "Zero"
 msgstr "Null"
 
-#: ../src/backend/filters/voxelise.cpp:128
+#: ../src/backend/filters/voxelise.cpp:129
 msgid "Bounce"
 msgstr "Bounce"
 
-#: ../src/backend/filters/voxelise.cpp:133
+#: ../src/backend/filters/voxelise.cpp:134
 msgid "Linear"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:604
+#: ../src/backend/filters/voxelise.cpp:601
 msgid "Voxel Limits (min,max): ("
 msgstr "Voxel Grenzen (min,max): ("
 
-#: ../src/backend/filters/voxelise.cpp:754
+#: ../src/backend/filters/voxelise.cpp:751
 msgid "Fixed width"
 msgstr "Fixe Breite"
 
-#: ../src/backend/filters/voxelise.cpp:758
+#: ../src/backend/filters/voxelise.cpp:755
 msgid "If true, use fixed size voxels, otherwise use fixed count"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:764
+#: ../src/backend/filters/voxelise.cpp:761
 msgid "Bin width x"
 msgstr "Bin-Breite x"
 
-#: ../src/backend/filters/voxelise.cpp:768
+#: ../src/backend/filters/voxelise.cpp:765
 msgid "Voxel size in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:772
+#: ../src/backend/filters/voxelise.cpp:769
 msgid "Bin width y"
 msgstr "Bin-Breite y"
 
-#: ../src/backend/filters/voxelise.cpp:775
+#: ../src/backend/filters/voxelise.cpp:772
 msgid "Voxel size in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:781
+#: ../src/backend/filters/voxelise.cpp:778
 msgid "Bin width z"
 msgstr "Bin-Breite Z"
 
-#: ../src/backend/filters/voxelise.cpp:784
+#: ../src/backend/filters/voxelise.cpp:781
 msgid "Voxel size in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:791
+#: ../src/backend/filters/voxelise.cpp:788
 msgid "Num bins x"
 msgstr "Anzahl Bins x"
 
-#: ../src/backend/filters/voxelise.cpp:795
+#: ../src/backend/filters/voxelise.cpp:792
 msgid "Number of voxels to use in X direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:800
+#: ../src/backend/filters/voxelise.cpp:797
 msgid "Num bins y"
 msgstr "Anzahl Bins y"
 
-#: ../src/backend/filters/voxelise.cpp:803
+#: ../src/backend/filters/voxelise.cpp:800
 msgid "Number of voxels to use in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:809
+#: ../src/backend/filters/voxelise.cpp:806
 msgid "Num bins z"
 msgstr "Anzahl Bins z"
 
-#: ../src/backend/filters/voxelise.cpp:811
+#: ../src/backend/filters/voxelise.cpp:808
 msgid "Number of voxels to use in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:832
+#: ../src/backend/filters/voxelise.cpp:838
 msgid "Normalise by"
 msgstr "Normalisieren mit"
 
-#: ../src/backend/filters/voxelise.cpp:835
+#: ../src/backend/filters/voxelise.cpp:841
 msgid "Method to use to normalise scalar value in each voxel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:838
+#: ../src/backend/filters/voxelise.cpp:844
 msgid "Computation"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:845
+#: ../src/backend/filters/voxelise.cpp:851
 msgid "Numerator"
 msgstr "Zähler"
 
-#: ../src/backend/filters/voxelise.cpp:848
+#: ../src/backend/filters/voxelise.cpp:854
 msgid "Parmeter \"a\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:868
+#: ../src/backend/filters/voxelise.cpp:871
 msgid "Enable this ion for numerator"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:879
+#: ../src/backend/filters/voxelise.cpp:883
 msgid "Denominator"
 msgstr "Nenner"
 
-#: ../src/backend/filters/voxelise.cpp:882
+#: ../src/backend/filters/voxelise.cpp:886
 msgid "Parameter \"b\" used in fraction (a/b) to get voxel value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:898
+#: ../src/backend/filters/voxelise.cpp:899
 msgid "Enable this ion for denominator contribution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:919
-#: ../src/backend/filters/voxelise.cpp:954
+#: ../src/backend/filters/voxelise.cpp:920
+#: ../src/backend/filters/voxelise.cpp:955
 msgid "Filtering"
 msgstr "Filtern"
 
-#: ../src/backend/filters/voxelise.cpp:923
+#: ../src/backend/filters/voxelise.cpp:924
 msgid "Smoothing method to use on voxels"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:926
+#: ../src/backend/filters/voxelise.cpp:927
 msgid "Processing"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:932
+#: ../src/backend/filters/voxelise.cpp:933
 msgid "Kernel Bins"
 msgstr "Kernel Bins"
 
-#: ../src/backend/filters/voxelise.cpp:936
+#: ../src/backend/filters/voxelise.cpp:937
 msgid "Number of bins in convolution kernel"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:947
+#: ../src/backend/filters/voxelise.cpp:948
 msgid "Exterior values"
 msgstr "Exterior values"
 
-#: ../src/backend/filters/voxelise.cpp:950
+#: ../src/backend/filters/voxelise.cpp:951
 msgid "Method to use to treat boundaries of voxel data for convolution"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:970
+#: ../src/backend/filters/voxelise.cpp:971
 msgid "Representation"
 msgstr "Representation"
 
-#: ../src/backend/filters/voxelise.cpp:973
+#: ../src/backend/filters/voxelise.cpp:974
 msgid "3D display method"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:984
+#: ../src/backend/filters/voxelise.cpp:985
 msgid "Spot size"
 msgstr "Spot size"
 
-#: ../src/backend/filters/voxelise.cpp:987
+#: ../src/backend/filters/voxelise.cpp:988
 msgid "Size of the spots to use for display"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:992
-#: ../src/backend/filters/voxelise.cpp:1030
+#: ../src/backend/filters/voxelise.cpp:993
+#: ../src/backend/filters/voxelise.cpp:1028
 msgid "Transparency"
 msgstr "Transparenz"
 
-#: ../src/backend/filters/voxelise.cpp:995
+#: ../src/backend/filters/voxelise.cpp:996
 msgid "How \"see through\" each point is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1004
+#: ../src/backend/filters/voxelise.cpp:1005
 msgid "Surf. param."
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1007
+#: ../src/backend/filters/voxelise.cpp:1008
 msgid "Isovalue"
 msgstr "Isovalue"
 
-#: ../src/backend/filters/voxelise.cpp:1010
+#: ../src/backend/filters/voxelise.cpp:1011
 msgid "Scalar value to show as isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1025
+#: ../src/backend/filters/voxelise.cpp:1016
+#: ../src/backend/filters/voxelise.cpp:1081
+#: ../src/backend/filters/spatialAnalysis.cpp:2019
+#: ../src/backend/filters/spatialAnalysis.cpp:2073
+msgid "Surface"
+msgstr "Oberfläche"
+
+#: ../src/backend/filters/voxelise.cpp:1023
 msgid "Colour of isosurface"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1033
+#: ../src/backend/filters/voxelise.cpp:1031
 msgid "How \"see through\" each facet is (0 - opaque, 1 - invisible)"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1045
+#: ../src/backend/filters/voxelise.cpp:1042
 msgid "Slice param."
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1053
+#: ../src/backend/filters/voxelise.cpp:1050
 msgid "Slice Axis"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1056
+#: ../src/backend/filters/voxelise.cpp:1053
 msgid "Normal for the planar slice"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1063
+#: ../src/backend/filters/voxelise.cpp:1060
 msgid "Slice Coord"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1066
+#: ../src/backend/filters/voxelise.cpp:1063
 msgid "Fractional coordinate that slice plane passes through"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1071
+#: ../src/backend/filters/voxelise.cpp:1068
 msgid "Interp. Mode"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1079
+#: ../src/backend/filters/voxelise.cpp:1076
 msgid "Interpolation mode for direction normal to slice"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1094
+#: ../src/backend/filters/voxelise.cpp:1092
 msgid "Colour mode"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1097
-#: ../src/backend/filters/ionColour.cpp:262
+#: ../src/backend/filters/voxelise.cpp:1095
+#: ../src/backend/filters/ionColour.cpp:265
 msgid "Colour scheme used to assign points colours by value"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1106
-#: ../src/backend/filters/ionColour.cpp:274
+#: ../src/backend/filters/voxelise.cpp:1100
+#: ../src/backend/filters/ionColour.cpp:277
 msgid "Show Bar"
 msgstr "Zeige Balken"
 
-#: ../src/backend/filters/voxelise.cpp:1116
+#: ../src/backend/filters/voxelise.cpp:1107
 msgid "Auto Bounds"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1117
+#: ../src/backend/filters/voxelise.cpp:1108
 msgid "Auto-compute min/max values in map"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1127
-#: ../src/backend/filters/ionColour.cpp:289
+#: ../src/backend/filters/voxelise.cpp:1118
+#: ../src/backend/filters/ionColour.cpp:298
 msgid "Map start"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1128
-#: ../src/backend/filters/ionColour.cpp:290
+#: ../src/backend/filters/voxelise.cpp:1119
+#: ../src/backend/filters/ionColour.cpp:299
 msgid "Assign points with this value to the first colour in map"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1135
-#: ../src/backend/filters/ionColour.cpp:297
+#: ../src/backend/filters/voxelise.cpp:1126
+#: ../src/backend/filters/ionColour.cpp:306
 msgid "Map end"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1136
-#: ../src/backend/filters/ionColour.cpp:298
+#: ../src/backend/filters/voxelise.cpp:1127
+#: ../src/backend/filters/ionColour.cpp:307
 msgid "Assign points with this value to the last colour in map"
 msgstr ""
 
-#: ../src/backend/filters/voxelise.cpp:1707
-msgid "Voxelisation aborted"
-msgstr "Voxelisation abgebrochen"
-
-#: ../src/backend/filters/voxelise.cpp:1709
-msgid "Out of memory"
-msgstr "Zu wenig Speicher"
-
-#: ../src/backend/filters/voxelise.cpp:1711
-msgid "Unable to perform filter convolution"
-msgstr "Kann Filter convolution nicht durchführen"
-
-#: ../src/backend/filters/voxelise.cpp:1713
-msgid "Voxelisation bounds are invalid"
-msgstr "Voxelisation Grenzen sin ungültig"
-
-#: ../src/backend/filters/ionColour.cpp:258
+#: ../src/backend/filters/ionColour.cpp:261
 msgid "Colour Map"
 msgstr "Farbtabelle"
 
-#: ../src/backend/filters/ionColour.cpp:266
+#: ../src/backend/filters/ionColour.cpp:269
 msgid "Reverse map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:267
+#: ../src/backend/filters/ionColour.cpp:270
 msgid "Reverse the colour scale"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:281
+#: ../src/backend/filters/ionColour.cpp:283
+msgid "Opacity"
+msgstr ""
+
+#: ../src/backend/filters/ionColour.cpp:290
 msgid "Num Colours"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:283
+#: ../src/backend/filters/ionColour.cpp:292
 msgid "Number of unique colours to use in colour map"
 msgstr ""
 
-#: ../src/backend/filters/ionColour.cpp:416
-#: ../src/backend/filters/transform.cpp:1579
-#: ../src/backend/filters/ionInfo.cpp:541
+#: ../src/backend/filters/ionColour.cpp:413
 msgid "Aborted"
 msgstr "Abgebrochen"
 
-#: ../src/backend/filters/compositionProfile.cpp:536
+#: ../src/backend/filters/compositionProfile.cpp:568
 msgid "Distance"
 msgstr "Abstand"
 
-#: ../src/backend/filters/compositionProfile.cpp:544
+#: ../src/backend/filters/compositionProfile.cpp:576
 msgid "Fraction"
 msgstr "Anteil"
 
-#: ../src/backend/filters/compositionProfile.cpp:546
+#: ../src/backend/filters/compositionProfile.cpp:578
 msgid "Density (\\frac{\\#}{len^3})"
 msgstr "Dichte (\\frac{\\#}{len^3})"
 
-
-#: ../src/backend/filters/compositionProfile.cpp:573
+#: ../src/backend/filters/compositionProfile.cpp:605
 msgid "Freq. Profile"
 msgstr "Häufigkeitsprofil"
 
-#: ../src/backend/filters/compositionProfile.cpp:641
-msgid "Too many bins in comp. profile."
-msgstr "Zu viele Bins im Konzentrationsprofil."
-
-#: ../src/backend/filters/compositionProfile.cpp:643
-msgid "Not enough memory for comp. profile."
-msgstr "Nicht genug Speicher für Konz.-Profil."
-
-#: ../src/backend/filters/compositionProfile.cpp:645
-msgid "Aborted composition prof."
-msgstr "Konzentrationspr. abgebr."
+#: ../src/backend/filters/compositionProfile.cpp:657
+msgid "No data remained in profile - cannot display result"
+msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:989
+#: ../src/backend/filters/compositionProfile.cpp:937
 msgid "Primitive type"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:993
+#: ../src/backend/filters/compositionProfile.cpp:941
 msgid "Basic shape to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1004
+#: ../src/backend/filters/compositionProfile.cpp:953
 msgid "Display the 3D composition profile interaction object"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1018
-#: ../src/backend/filters/spatialAnalysis.cpp:602
+#: ../src/backend/filters/compositionProfile.cpp:967
+#: ../src/backend/filters/spatialAnalysis.cpp:777
 msgid "Position for centre of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1026
+#: ../src/backend/filters/compositionProfile.cpp:975
 msgid "Vector between ends of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1037
+#: ../src/backend/filters/compositionProfile.cpp:983
 msgid "Prevent length of cylinder changing during interaction"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1077
+#: ../src/backend/filters/compositionProfile.cpp:1023
 msgid "Fixed Bin Num"
 msgstr "Fix. Bin-Anz."
 
-#: ../src/backend/filters/compositionProfile.cpp:1080
+#: ../src/backend/filters/compositionProfile.cpp:1026
 msgid ""
 "If true, use a fixed number of bins for profile, otherwise use fixed step "
 "size"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1086
-#: ../src/backend/filters/spatialAnalysis.cpp:433
-#: ../src/backend/filters/spatialAnalysis.cpp:575
+#: ../src/backend/filters/compositionProfile.cpp:1032
+#: ../src/backend/filters/spatialAnalysis.cpp:612
+#: ../src/backend/filters/spatialAnalysis.cpp:754
 msgid "Num Bins"
 msgstr "Bin-Anz."
 
-#: ../src/backend/filters/compositionProfile.cpp:1091
+#: ../src/backend/filters/compositionProfile.cpp:1037
 msgid "Number of bins to use for profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1096
-#: ../src/backend/filters/spectrumPlot.cpp:396
+#: ../src/backend/filters/compositionProfile.cpp:1042
+#: ../src/backend/filters/spectrumPlot.cpp:386
 msgid "Bin width"
 msgstr "Bin-Breite"
 
-#: ../src/backend/filters/compositionProfile.cpp:1102
+#: ../src/backend/filters/compositionProfile.cpp:1048
 msgid "Size of each bin in profile"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1111
+#: ../src/backend/filters/compositionProfile.cpp:1057
 msgid "Convert bin counts into relative frequencies in each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1115
+#: ../src/backend/filters/compositionProfile.cpp:1061
 msgid "Min. events"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1119
+#: ../src/backend/filters/compositionProfile.cpp:1065
 msgid "Drop data that does not have this many events"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1143
-#: ../src/backend/filters/spectrumPlot.cpp:459
+#: ../src/backend/filters/compositionProfile.cpp:1068
+msgid "Settings"
+msgstr ""
+
+#: ../src/backend/filters/compositionProfile.cpp:1090
+#: ../src/backend/filters/spectrumPlot.cpp:445
 msgid "Plot Type"
 msgstr "Plot Type"
 
-#: ../src/backend/filters/compositionProfile.cpp:1146
+#: ../src/backend/filters/compositionProfile.cpp:1093
 msgid "Visual style for plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1159
+#: ../src/backend/filters/compositionProfile.cpp:1103
 msgid "Colour of plot"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1175
+#: ../src/backend/filters/compositionProfile.cpp:1119
 msgid "Err. Estimator"
 msgstr "Fehlerschätzer"
 
-#: ../src/backend/filters/compositionProfile.cpp:1178
+#: ../src/backend/filters/compositionProfile.cpp:1122
 msgid "Method of estimating error associated with each bin"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1185
+#: ../src/backend/filters/compositionProfile.cpp:1129
 msgid "Avg. Window"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1188
+#: ../src/backend/filters/compositionProfile.cpp:1132
 msgid "Number of bins to include in moving average filter"
 msgstr ""
 
-#: ../src/backend/filters/compositionProfile.cpp:1192
+#: ../src/backend/filters/compositionProfile.cpp:1136
 msgid "Error analysis"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:84
+#: ../src/backend/filters/spatialAnalysis.cpp:101
 msgid "Local Density"
 msgstr "Lokale Dichte"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:85
+#: ../src/backend/filters/spatialAnalysis.cpp:102
 msgid "Density Filtering"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:86
+#: ../src/backend/filters/spatialAnalysis.cpp:103
 msgid "Radial Distribution"
 msgstr "Radial Distribution"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:87
+#: ../src/backend/filters/spatialAnalysis.cpp:104
 msgid "Axial Distribution"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:88
+#: ../src/backend/filters/spatialAnalysis.cpp:105
 msgid "Binomial Distribution"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:92
+#: ../src/backend/filters/spatialAnalysis.cpp:106
+msgid "Point Em/Replacement"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:110
 msgid "Neighbour Count"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:376
+#: ../src/backend/filters/spatialAnalysis.cpp:544
 msgid "Spatial analysis algorithm to use"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:398
+#: ../src/backend/filters/spatialAnalysis.cpp:567
 msgid "Stop Mode"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:401
+#: ../src/backend/filters/spatialAnalysis.cpp:570
 msgid "Method to use to terminate algorithm when examining each point"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:408
+#: ../src/backend/filters/spatialAnalysis.cpp:577
 msgid "NN Max"
 msgstr "NN Max"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:411
+#: ../src/backend/filters/spatialAnalysis.cpp:580
 msgid "Maximum number of neighbours to examine"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:417
+#: ../src/backend/filters/spatialAnalysis.cpp:586
+msgid "Normalise bins"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:589
+msgid ""
+"Normalise counts by binwidth. Needed when comparing NN histograms against "
+"one another"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:596
 msgid "Dist Max"
 msgstr "Abst. Max."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:420
+#: ../src/backend/filters/spatialAnalysis.cpp:599
 msgid "Maximum distance from each point for search"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:436
-#: ../src/backend/filters/spatialAnalysis.cpp:578
+#: ../src/backend/filters/spatialAnalysis.cpp:615
+#: ../src/backend/filters/spatialAnalysis.cpp:757
 msgid "Number of bins for output 1D RDF plot"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:442
+#: ../src/backend/filters/spatialAnalysis.cpp:621
 msgid "Surface Remove"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:445
+#: ../src/backend/filters/spatialAnalysis.cpp:624
 msgid ""
 "Exclude surface as part of source to minimise bias in RDF (at cost of "
 "increased noise)"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:452
+#: ../src/backend/filters/spatialAnalysis.cpp:631
 msgid "Remove Dist"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:455
+#: ../src/backend/filters/spatialAnalysis.cpp:634
 msgid "Minimum distance to remove from surface"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:466
-#: ../src/backend/filters/spatialAnalysis.cpp:587
+#: ../src/backend/filters/spatialAnalysis.cpp:642
+#: ../src/backend/filters/spatialAnalysis.cpp:762
 msgid "Plot colour "
 msgstr "Plotfarbe "
 
-#: ../src/backend/filters/spatialAnalysis.cpp:469
-#: ../src/backend/filters/spatialAnalysis.cpp:590
+#: ../src/backend/filters/spatialAnalysis.cpp:645
+#: ../src/backend/filters/spatialAnalysis.cpp:765
 msgid "Colour of output plot"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:488
+#: ../src/backend/filters/spatialAnalysis.cpp:649
+#: ../src/backend/filters/spatialAnalysis.cpp:743
+#: ../src/backend/filters/spatialAnalysis.cpp:748
+#: ../src/backend/filters/spatialAnalysis.cpp:797
+#: ../src/backend/filters/spatialAnalysis.cpp:836
+msgid "Alg. Params."
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:665
 msgid "Source"
 msgstr "Quelle"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:491
+#: ../src/backend/filters/spatialAnalysis.cpp:668
 msgid "Ions to use for initiating RDF search"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:504
+#: ../src/backend/filters/spatialAnalysis.cpp:681
 msgid "Enable/disable ion as source"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:521
+#: ../src/backend/filters/spatialAnalysis.cpp:687
+msgid "Source Ion"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:700
 msgid "Enable/disable all ions as target"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:533
+#: ../src/backend/filters/spatialAnalysis.cpp:712
 msgid "Enable/disable this ion as target"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:541
-#: ../src/backend/filters/spatialAnalysis.cpp:564
-#: ../src/backend/filters/spatialAnalysis.cpp:569
-#: ../src/backend/filters/spatialAnalysis.cpp:622
-#: ../src/backend/filters/spatialAnalysis.cpp:661
-msgid "Alg. Params."
+#: ../src/backend/filters/spatialAnalysis.cpp:717
+msgid "Target Ion"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:548
+#: ../src/backend/filters/spatialAnalysis.cpp:727
 msgid "Cutoff"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:551
+#: ../src/backend/filters/spatialAnalysis.cpp:730
 msgid "Remove points with local density above/below this value"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:557
+#: ../src/backend/filters/spatialAnalysis.cpp:736
 msgid "Retain Upper"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:560
+#: ../src/backend/filters/spatialAnalysis.cpp:739
 msgid "Retain either points with density above (enabled) or below cutoff"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:610
+#: ../src/backend/filters/spatialAnalysis.cpp:785
 msgid "Vector between centre and end of cylinder"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:629
-#: ../src/backend/filters/spatialAnalysis.cpp:3217
-#: ../src/backend/filters/spatialAnalysis.cpp:3286
+#: ../src/backend/filters/spatialAnalysis.cpp:804
+#: ../src/backend/filters/spatialAnalysis.cpp:3432
+#: ../src/backend/filters/spatialAnalysis.cpp:3491
 msgid "Block size"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:632
+#: ../src/backend/filters/spatialAnalysis.cpp:807
 msgid "Number of ions to use per block"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:639
+#: ../src/backend/filters/spatialAnalysis.cpp:814
 msgid "Max Block Aspect"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:642
+#: ../src/backend/filters/spatialAnalysis.cpp:817
 msgid ""
 "Maximum allowable block aspect ratio. Blocks above this aspect are "
 "discarded. Setting too high decreases correlation strength. Too low causes "
 "loss of statistical power."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:653
+#: ../src/backend/filters/spatialAnalysis.cpp:828
 msgid "Extrusion Direction"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:656
+#: ../src/backend/filters/spatialAnalysis.cpp:831
 msgid "Direction in which blocks are extended during construction."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:665
+#: ../src/backend/filters/spatialAnalysis.cpp:840
 msgid "Plot Counts"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:668
+#: ../src/backend/filters/spatialAnalysis.cpp:843
 msgid "Show the counts in the binomial histogram"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:677
+#: ../src/backend/filters/spatialAnalysis.cpp:852
 msgid ""
 "Normalise the counts in the binomial histogram to a probability density "
 "function"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:691
+#: ../src/backend/filters/spatialAnalysis.cpp:866
 msgid "Display Grid"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:700
+#: ../src/backend/filters/spatialAnalysis.cpp:875
 msgid "View Options"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1227
-msgid "Spatial analysis aborted by user"
-msgstr "Spatial analysis aborted by user"
+#: ../src/backend/filters/spatialAnalysis.cpp:881
+msgid "Data File"
+msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1229
-msgid "Insufficient data to complete analysis."
-msgstr "Ungenügend Daten zum Fertigstellen der Analyse."
+#: ../src/backend/filters/spatialAnalysis.cpp:885
+msgid "Pos file of points to subtract/replace/etc"
+msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1231
-msgid "Insufficient bins in histogram for analysis."
+#: ../src/backend/filters/spatialAnalysis.cpp:890
+msgid "Match Tol."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1233
-msgid "Insufficient memory for binomial. Reduce input size?"
+#: ../src/backend/filters/spatialAnalysis.cpp:893
+msgid "Tolerance to allow for matching"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1235
-msgid "Binomial requires a parent range file"
+#: ../src/backend/filters/spatialAnalysis.cpp:909
+msgid "Replacment condition"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1791
-#: ../src/backend/filters/spatialAnalysis.cpp:1843
-#: ../src/backend/filters/spatialAnalysis.cpp:2090
-#: ../src/backend/filters/spatialAnalysis.cpp:2388
-#: ../src/backend/filters/spatialAnalysis.cpp:2920
-msgid "Build"
+#: ../src/backend/filters/spatialAnalysis.cpp:915
+msgid "Replace value"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1803
-#: ../src/backend/filters/spatialAnalysis.cpp:1855
-msgid "Surface"
-msgstr "Oberfläche"
+#: ../src/backend/filters/spatialAnalysis.cpp:918
+msgid "Use value data from file when replacing ions"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:923
+msgid "Replacement"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:2005
+#: ../src/backend/filters/spatialAnalysis.cpp:2059
+#: ../src/backend/filters/spatialAnalysis.cpp:2320
+#: ../src/backend/filters/spatialAnalysis.cpp:2611
+#: ../src/backend/filters/spatialAnalysis.cpp:3136
+msgid "Build"
+msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1895
-#: ../src/backend/filters/spatialAnalysis.cpp:2117
-#: ../src/backend/filters/spatialAnalysis.cpp:2415
+#: ../src/backend/filters/spatialAnalysis.cpp:2113
+#: ../src/backend/filters/spatialAnalysis.cpp:2347
+#: ../src/backend/filters/spatialAnalysis.cpp:2638
 msgid "Analyse"
 msgstr "Analyse"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1952
-#: ../src/backend/filters/spatialAnalysis.cpp:2021
+#: ../src/backend/filters/spatialAnalysis.cpp:2195
+#: ../src/backend/filters/spatialAnalysis.cpp:2258
 msgid "Radial Distance"
 msgstr "Radialer Abstand"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:1956
+#: ../src/backend/filters/spatialAnalysis.cpp:2197
+msgid "Count/Distance"
+msgstr ""
+
+#: ../src/backend/filters/spatialAnalysis.cpp:2202
 msgid "NN Freq."
 msgstr "NN Freq."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2012
+#: ../src/backend/filters/spatialAnalysis.cpp:2249
 msgid "Warning, "
 msgstr "Warnung, "
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2013
+#: ../src/backend/filters/spatialAnalysis.cpp:2250
 msgid ""
 " points were unable to find neighbour points that exceeded the search "
 "radius, and thus terminated prematurely"
@@ -3626,219 +3547,215 @@ msgstr ""
 " Punkte konnten keine Nachbapunkte die den Suchradius überschritten finden "
 "und beendeten vorzeitig."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2023
+#: ../src/backend/filters/spatialAnalysis.cpp:2260
 msgid " RDF"
 msgstr " RDF"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2313
-#: ../src/backend/filters/spatialAnalysis.cpp:2621
+#: ../src/backend/filters/spatialAnalysis.cpp:2543
+#: ../src/backend/filters/spatialAnalysis.cpp:2844
 msgid "Number Density (\\#/Vol^3)"
 msgstr "Number Density (\\#/Vol^3)"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2342
-#: ../src/backend/filters/spatialAnalysis.cpp:2648
+#: ../src/backend/filters/spatialAnalysis.cpp:2565
+#: ../src/backend/filters/spatialAnalysis.cpp:2864
 msgid "Warning,"
 msgstr "Warnung,"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2343
-#: ../src/backend/filters/spatialAnalysis.cpp:2649
+#: ../src/backend/filters/spatialAnalysis.cpp:2566
+#: ../src/backend/filters/spatialAnalysis.cpp:2865
 msgid " points were un-analysable. These have been dropped"
 msgstr " points were un-analysable. These have been dropped"
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2365
-#: ../src/backend/filters/spatialAnalysis.cpp:2671
+#: ../src/backend/filters/spatialAnalysis.cpp:2588
+#: ../src/backend/filters/spatialAnalysis.cpp:2887
 msgid "And so on..."
 msgstr "Und so weiter..."
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2754
+#: ../src/backend/filters/spatialAnalysis.cpp:2970
 msgid "Extract"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2829
+#: ../src/backend/filters/spatialAnalysis.cpp:3045
 msgid "Reduce"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2937
+#: ../src/backend/filters/spatialAnalysis.cpp:3155
 msgid "Compute"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:2965
+#: ../src/backend/filters/spatialAnalysis.cpp:3200
 msgid "Insufficient points to complete analysis"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3001
+#: ../src/backend/filters/spatialAnalysis.cpp:3223
 msgid "Axial Distance"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3003
+#: ../src/backend/filters/spatialAnalysis.cpp:3225
 msgid " 1D Dist. Func."
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3087
+#: ../src/backend/filters/spatialAnalysis.cpp:3302
 msgid "Binomial"
 msgstr ""
 
-#: ../src/backend/filters/spatialAnalysis.cpp:3219
-#: ../src/backend/filters/spatialAnalysis.cpp:3288
+#: ../src/backend/filters/spatialAnalysis.cpp:3434
+#: ../src/backend/filters/spatialAnalysis.cpp:3493
 msgid "Rel. Frequency"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:77
+#: ../src/backend/filters/transform.cpp:78
 msgid "Translate"
 msgstr "Translate"
 
-#: ../src/backend/filters/transform.cpp:78
+#: ../src/backend/filters/transform.cpp:79
 msgid "Scale (isotropic)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:79
+#: ../src/backend/filters/transform.cpp:80
 msgid "Scale (anisotropic)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:80
+#: ../src/backend/filters/transform.cpp:81
 msgid "Rotate"
 msgstr "Rotieren"
 
-#: ../src/backend/filters/transform.cpp:81
+#: ../src/backend/filters/transform.cpp:82
 msgid "Value Shuffle"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:82
+#: ../src/backend/filters/transform.cpp:83
 msgid "Spatial Noise"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:83
+#: ../src/backend/filters/transform.cpp:84
 msgid "Translate Value"
 msgstr "Translate Wert"
 
-#: ../src/backend/filters/transform.cpp:87
+#: ../src/backend/filters/transform.cpp:88
 msgid "Specify"
 msgstr "Angeben"
 
-#: ../src/backend/filters/transform.cpp:88
+#: ../src/backend/filters/transform.cpp:89
 msgid "Boundbox Centre"
 msgstr "Boundbox Zentrum"
 
-#: ../src/backend/filters/transform.cpp:89
+#: ../src/backend/filters/transform.cpp:90
 msgid "Mass Centre"
 msgstr "Massen-Zentrum"
 
-#: ../src/backend/filters/transform.cpp:1052
+#: ../src/backend/filters/transform.cpp:1010
 msgid "Mass-to-Charge (amu/e)"
 msgstr "Masse-zu-Ladung (amu/e)"
 
-#: ../src/backend/filters/transform.cpp:1106
+#: ../src/backend/filters/transform.cpp:1064
 msgid "Shuffle"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1130
+#: ../src/backend/filters/transform.cpp:1088
 msgid "Splice"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1185
+#: ../src/backend/filters/transform.cpp:1136
 msgid "Algorithm to use to transform point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1201
+#: ../src/backend/filters/transform.cpp:1153
 msgid "Origin mode"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1204
+#: ../src/backend/filters/transform.cpp:1156
 msgid "Select how transform origin is computed"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1209
+#: ../src/backend/filters/transform.cpp:1161
 msgid "Show marker"
 msgstr "Zeige Markierung"
 
-#: ../src/backend/filters/transform.cpp:1213
+#: ../src/backend/filters/transform.cpp:1165
 msgid "Display an interactive object to set transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1215
+#: ../src/backend/filters/transform.cpp:1167
 msgid "Display a small marker to denote transform origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1231
+#: ../src/backend/filters/transform.cpp:1183
 msgid "Translation"
 msgstr "Translation"
 
-#: ../src/backend/filters/transform.cpp:1234
+#: ../src/backend/filters/transform.cpp:1186
 msgid "Translation vector for transform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1246
+#: ../src/backend/filters/transform.cpp:1198
 msgid "Offset"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1250
+#: ../src/backend/filters/transform.cpp:1202
 msgid "Scalar to use to offset each point's associated value"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1267
-#: ../src/backend/filters/transform.cpp:1294
+#: ../src/backend/filters/transform.cpp:1219
+#: ../src/backend/filters/transform.cpp:1246
 msgid "Origin of scale trasnform"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1274
-#: ../src/backend/filters/transform.cpp:1301
+#: ../src/backend/filters/transform.cpp:1226
+#: ../src/backend/filters/transform.cpp:1253
 msgid "Scale Fact."
 msgstr "Skalierungsfaktor"
 
-#: ../src/backend/filters/transform.cpp:1277
-#: ../src/backend/filters/transform.cpp:1304
+#: ../src/backend/filters/transform.cpp:1229
+#: ../src/backend/filters/transform.cpp:1256
 msgid "Enlargement factor for scaling around origin"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1320
+#: ../src/backend/filters/transform.cpp:1272
 msgid "Origin of rotation"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1328
+#: ../src/backend/filters/transform.cpp:1280
 msgid "Axis around which to revolve"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1333
+#: ../src/backend/filters/transform.cpp:1285
 msgid "Angle (deg)"
 msgstr "Winkel (deg)"
 
-#: ../src/backend/filters/transform.cpp:1336
+#: ../src/backend/filters/transform.cpp:1288
 msgid "Angle to perform rotation (ACW, as viewed from axis towards origin)"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1353
+#: ../src/backend/filters/transform.cpp:1305
 msgid "Noise Type"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1356
+#: ../src/backend/filters/transform.cpp:1308
 msgid "Method to use to degrade point data"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1363
+#: ../src/backend/filters/transform.cpp:1315
 msgid "Noise level"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1365
+#: ../src/backend/filters/transform.cpp:1317
 msgid "Standard dev."
 msgstr "Standardabweichung"
 
-#: ../src/backend/filters/transform.cpp:1373
+#: ../src/backend/filters/transform.cpp:1325
 msgid "Amplitude of noise"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1385
+#: ../src/backend/filters/transform.cpp:1337
 msgid "Transform Params"
 msgstr "Transformationsparameter"
 
-#: ../src/backend/filters/transform.cpp:1582
-msgid "Unable to allocate memory"
-msgstr "Kann Speicher nicht zuweisen"
-
-#: ../src/backend/filters/transform.cpp:1761
+#: ../src/backend/filters/transform.cpp:1675
 msgid "White"
 msgstr ""
 
-#: ../src/backend/filters/transform.cpp:1763
+#: ../src/backend/filters/transform.cpp:1677
 msgid "Gaussian"
 msgstr ""
 
@@ -3854,102 +3771,106 @@ msgstr ""
 msgid "Dimension"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:524
+#: ../src/backend/filters/boundingBox.cpp:525
 msgid "If true, show box, otherwise hide box"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:537
+#: ../src/backend/filters/boundingBox.cpp:538
 msgid "Style"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:540
+#: ../src/backend/filters/boundingBox.cpp:541
 msgid "Box display mode"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:551
+#: ../src/backend/filters/boundingBox.cpp:544
+msgid "Display mode"
+msgstr ""
+
+#: ../src/backend/filters/boundingBox.cpp:553
 msgid "Fixed Tick Num"
 msgstr "Fixed Tick Num"
 
-#: ../src/backend/filters/boundingBox.cpp:555
+#: ../src/backend/filters/boundingBox.cpp:557
 msgid ""
 "If true, evenly use specified number of ticks. Otherwise, use distance to "
 "determine tick count"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:563
+#: ../src/backend/filters/boundingBox.cpp:565
 msgid "Num X"
 msgstr "Num X"
 
-#: ../src/backend/filters/boundingBox.cpp:566
+#: ../src/backend/filters/boundingBox.cpp:568
 msgid "Tick count in X direction"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:571
+#: ../src/backend/filters/boundingBox.cpp:573
 msgid "Num Y"
 msgstr "Num Y"
 
-#: ../src/backend/filters/boundingBox.cpp:574
+#: ../src/backend/filters/boundingBox.cpp:576
 msgid "Tick count in Y direction"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:579
+#: ../src/backend/filters/boundingBox.cpp:581
 msgid "Num Z"
 msgstr "Num Z"
 
-#: ../src/backend/filters/boundingBox.cpp:582
+#: ../src/backend/filters/boundingBox.cpp:584
 msgid "Tick count in Z direction"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:588
+#: ../src/backend/filters/boundingBox.cpp:590
 msgid "Spacing X"
 msgstr "X-Abstand"
 
-#: ../src/backend/filters/boundingBox.cpp:592
+#: ../src/backend/filters/boundingBox.cpp:594
 msgid "Distance between ticks on X axis"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:596
+#: ../src/backend/filters/boundingBox.cpp:598
 msgid "Spacing Y"
 msgstr "Y-Abstand"
 
-#: ../src/backend/filters/boundingBox.cpp:600
+#: ../src/backend/filters/boundingBox.cpp:602
 msgid "Distance between ticks on Y axis"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:604
+#: ../src/backend/filters/boundingBox.cpp:606
 msgid "Spacing Z"
 msgstr "Z-Abstand"
 
-#: ../src/backend/filters/boundingBox.cpp:608
+#: ../src/backend/filters/boundingBox.cpp:610
 msgid "Distance between ticks on Z axis"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:611
+#: ../src/backend/filters/boundingBox.cpp:613
 msgid "Tick marks"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:621
+#: ../src/backend/filters/boundingBox.cpp:620
 msgid "Box Colour"
 msgstr "Box Farbe"
 
-#: ../src/backend/filters/boundingBox.cpp:625
+#: ../src/backend/filters/boundingBox.cpp:624
 msgid "Colour of the bounding box"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:630
+#: ../src/backend/filters/boundingBox.cpp:629
 msgid "Line thickness"
 msgstr "Linienbreite"
 
-#: ../src/backend/filters/boundingBox.cpp:634
+#: ../src/backend/filters/boundingBox.cpp:633
 msgid "Thickness of the lines used to draw the box"
 msgstr ""
 
-#: ../src/backend/filters/boundingBox.cpp:642
-#: ../src/backend/filters/annotation.cpp:845
+#: ../src/backend/filters/boundingBox.cpp:641
+#: ../src/backend/filters/annotation.cpp:843
 msgid "Font Size"
 msgstr "Schriftgröße"
 
-#: ../src/backend/filters/boundingBox.cpp:645
+#: ../src/backend/filters/boundingBox.cpp:644
 msgid "Relative size for text"
 msgstr ""
 
@@ -3973,248 +3894,250 @@ msgstr "Winkel"
 msgid "Ruler"
 msgstr "Lineal"
 
-#: ../src/backend/filters/annotation.cpp:526
+#: ../src/backend/filters/annotation.cpp:519
 msgid "Enable"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:529
+#: ../src/backend/filters/annotation.cpp:522
 msgid "Enable/disable annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:550
+#: ../src/backend/filters/annotation.cpp:543
 msgid "Type or style of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:565
-#: ../src/backend/filters/annotation.cpp:667
+#: ../src/backend/filters/annotation.cpp:559
+#: ../src/backend/filters/annotation.cpp:663
 msgid "Text of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:573
+#: ../src/backend/filters/annotation.cpp:567
 msgid "Position of annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:577
-#: ../src/backend/filters/annotation.cpp:681
-#: ../src/backend/filters/annotation.cpp:739
-#: ../src/backend/filters/annotation.cpp:828
+#: ../src/backend/filters/annotation.cpp:571
+#: ../src/backend/filters/annotation.cpp:678
+#: ../src/backend/filters/annotation.cpp:737
+#: ../src/backend/filters/annotation.cpp:826
 msgid "Up dir"
 msgstr "Up dir"
 
-#: ../src/backend/filters/annotation.cpp:581
-#: ../src/backend/filters/annotation.cpp:832
+#: ../src/backend/filters/annotation.cpp:575
+#: ../src/backend/filters/annotation.cpp:830
 msgid "Vector for up direction of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:585
-#: ../src/backend/filters/annotation.cpp:688
-#: ../src/backend/filters/annotation.cpp:731
-#: ../src/backend/filters/annotation.cpp:836
+#: ../src/backend/filters/annotation.cpp:579
+#: ../src/backend/filters/annotation.cpp:685
+#: ../src/backend/filters/annotation.cpp:729
+#: ../src/backend/filters/annotation.cpp:834
 msgid "Across dir"
 msgstr "Across dir"
 
-#: ../src/backend/filters/annotation.cpp:589
-#: ../src/backend/filters/annotation.cpp:840
+#: ../src/backend/filters/annotation.cpp:583
+#: ../src/backend/filters/annotation.cpp:838
 msgid "Reading direction for annotation"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:594
-#: ../src/backend/filters/annotation.cpp:673
-#: ../src/backend/filters/annotation.cpp:766
+#: ../src/backend/filters/annotation.cpp:588
+#: ../src/backend/filters/annotation.cpp:670
+#: ../src/backend/filters/annotation.cpp:764
 msgid "Text size"
 msgstr "Textgröße"
 
-#: ../src/backend/filters/annotation.cpp:598
-#: ../src/backend/filters/annotation.cpp:677
-#: ../src/backend/filters/annotation.cpp:848
+#: ../src/backend/filters/annotation.cpp:592
+#: ../src/backend/filters/annotation.cpp:674
+#: ../src/backend/filters/annotation.cpp:846
 msgid "Relative size of annotation text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:610
-#: ../src/backend/filters/annotation.cpp:649
+#: ../src/backend/filters/annotation.cpp:604
+#: ../src/backend/filters/annotation.cpp:645
 msgid "3D position for tail of arrow"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:618
-#: ../src/backend/filters/annotation.cpp:658
+#: ../src/backend/filters/annotation.cpp:612
+#: ../src/backend/filters/annotation.cpp:654
 msgid "3D Position to which arrow points"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:624
-#: ../src/backend/filters/annotation.cpp:695
+#: ../src/backend/filters/annotation.cpp:615
+#: ../src/backend/filters/annotation.cpp:725
+msgid "Positioning"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:620
+#: ../src/backend/filters/annotation.cpp:692
 msgid "Tip radius"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:628
+#: ../src/backend/filters/annotation.cpp:624
 msgid "Size of the arrow head"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:632
+#: ../src/backend/filters/annotation.cpp:628
 msgid "Line size"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:636
+#: ../src/backend/filters/annotation.cpp:632
 msgid "Thickness of line used to draw arrow stem"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:705
+#: ../src/backend/filters/annotation.cpp:666
+msgid "Options"
+msgstr ""
+
+#: ../src/backend/filters/annotation.cpp:702
 msgid "Position A"
 msgstr "Position A"
 
-#: ../src/backend/filters/annotation.cpp:709
+#: ../src/backend/filters/annotation.cpp:706
 msgid "Location of first non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:713
+#: ../src/backend/filters/annotation.cpp:710
 msgid "Origin "
 msgstr "Ursprung "
 
-#: ../src/backend/filters/annotation.cpp:717
+#: ../src/backend/filters/annotation.cpp:714
 msgid "Location of central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:721
+#: ../src/backend/filters/annotation.cpp:718
 msgid "Position B"
 msgstr "Position B"
 
-#: ../src/backend/filters/annotation.cpp:725
+#: ../src/backend/filters/annotation.cpp:722
 msgid "Location of second non-central vertex"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:735
+#: ../src/backend/filters/annotation.cpp:733
 msgid "Reading direction for angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:740
+#: ../src/backend/filters/annotation.cpp:738
 msgid "Vector for up direction of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:748
+#: ../src/backend/filters/annotation.cpp:746
 msgid "Reflexive"
 msgstr "Reflexive"
 
-#: ../src/backend/filters/annotation.cpp:751
+#: ../src/backend/filters/annotation.cpp:749
 msgid "Measure interor (enabled) or exterior angle (disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:756
+#: ../src/backend/filters/annotation.cpp:754
 msgid "Show Angle"
 msgstr "Zeige Winkel"
 
-#: ../src/backend/filters/annotation.cpp:760
+#: ../src/backend/filters/annotation.cpp:758
 msgid "Display angle text (when enabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:770
+#: ../src/backend/filters/annotation.cpp:768
 msgid "Size of angle text"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:788
+#: ../src/backend/filters/annotation.cpp:786
 msgid "Digit format"
 msgstr "Zahlenformat"
 
-#: ../src/backend/filters/annotation.cpp:792
+#: ../src/backend/filters/annotation.cpp:790
 msgid ""
 "Format of angle text; # for numeral position, '.' for separator, eg ##.## "
 "gives 12.34"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:798
-#: ../src/backend/filters/annotation.cpp:886
+#: ../src/backend/filters/annotation.cpp:796
+#: ../src/backend/filters/annotation.cpp:881
 msgid "Sphere size"
 msgstr "Kugelgröße"
 
-#: ../src/backend/filters/annotation.cpp:802
-#: ../src/backend/filters/annotation.cpp:890
+#: ../src/backend/filters/annotation.cpp:800
+#: ../src/backend/filters/annotation.cpp:885
 msgid "Marker sphere size for manipulating tool"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:816
+#: ../src/backend/filters/annotation.cpp:814
 msgid "Ruler beginning 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:824
+#: ../src/backend/filters/annotation.cpp:822
 msgid "Ruler finish 3D location"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:857
+#: ../src/backend/filters/annotation.cpp:852
 msgid "Fixed ticks"
 msgstr "Fixe Marker"
 
-#: ../src/backend/filters/annotation.cpp:860
+#: ../src/backend/filters/annotation.cpp:855
 msgid ""
 "Use fixed (enabled) number of text markers, or one every fixed distance "
 "(disabled)"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:867
+#: ../src/backend/filters/annotation.cpp:862
 msgid "Num Ticks"
 msgstr "Anzahl Marker"
 
-#: ../src/backend/filters/annotation.cpp:870
+#: ../src/backend/filters/annotation.cpp:865
 msgid "Number of tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:877
+#: ../src/backend/filters/annotation.cpp:872
 msgid "Tick Spacing"
 msgstr "Markerabstand"
 
-#: ../src/backend/filters/annotation.cpp:880
+#: ../src/backend/filters/annotation.cpp:875
 msgid "Distance between tick marks along ruler"
 msgstr ""
 
-#: ../src/backend/filters/annotation.cpp:906
+#: ../src/backend/filters/annotation.cpp:899
 msgid "Colour for ruler and ticks"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:460
+#: ../src/backend/filters/ionDownsample.cpp:445
 msgid "By Count"
 msgstr "Nach Anzahl"
 
-#: ../src/backend/filters/ionDownsample.cpp:463
+#: ../src/backend/filters/ionDownsample.cpp:448
 msgid "Sample up to a fixed number of ions"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:469
+#: ../src/backend/filters/ionDownsample.cpp:454
 msgid "Per Species"
 msgstr "Nach Spezies"
 
-#: ../src/backend/filters/ionDownsample.cpp:473
+#: ../src/backend/filters/ionDownsample.cpp:458
 msgid "Use species specific (from ranging) sampling values"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:478
-msgid "Sampling rates"
+#: ../src/backend/filters/ionDownsample.cpp:487
+msgid "Sampling value for species"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:501
-msgid "Sampling value for species"
+#: ../src/backend/filters/ionDownsample.cpp:495
+#: ../src/backend/filters/ionDownsample.cpp:519
+msgid "Sampling rates"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:513
+#: ../src/backend/filters/ionDownsample.cpp:503
 msgid "Output Count"
 msgstr "Ausgabe Anzahl"
 
-#: ../src/backend/filters/ionDownsample.cpp:516
+#: ../src/backend/filters/ionDownsample.cpp:506
 msgid "Sample up to this value of points"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:521
+#: ../src/backend/filters/ionDownsample.cpp:511
 msgid "Out Fraction"
 msgstr "Ausgabe Anteil"
 
-#: ../src/backend/filters/ionDownsample.cpp:525
+#: ../src/backend/filters/ionDownsample.cpp:515
 msgid "Sample this fraction of points"
 msgstr ""
 
-#: ../src/backend/filters/ionDownsample.cpp:669
-msgid "Downsample Aborted"
-msgstr "Datenreduktion abgebrochen"
-
-#: ../src/backend/filters/ionDownsample.cpp:671
-msgid "Insuffient memory for downsample"
-msgstr "Nicht genug Speicher zur Datenreduktion"
-
 #: ../src/backend/filters/ionInfo.cpp:30
 msgid "Rectilinear"
 msgstr "Geradlinig"
@@ -4295,25 +4218,25 @@ msgstr ""
 msgid "Normalise count data"
 msgstr ""
 
-#: ../src/backend/filters/ionInfo.cpp:425
+#: ../src/backend/filters/ionInfo.cpp:421
+msgid "Ion data"
+msgstr ""
+
+#: ../src/backend/filters/ionInfo.cpp:426
 msgid "Volume"
 msgstr "Volumen"
 
-#: ../src/backend/filters/ionInfo.cpp:428
+#: ../src/backend/filters/ionInfo.cpp:429
 msgid "Compute volume for point data"
 msgstr ""
 
-#: ../src/backend/filters/ionInfo.cpp:443
+#: ../src/backend/filters/ionInfo.cpp:444
 msgid "Select volume counting technique"
 msgstr ""
 
-#: ../src/backend/filters/ionInfo.cpp:539
-msgid "Insufficient memory for operation"
-msgstr "Nicht genügend Speicher für Operation"
-
-#: ../src/backend/filters/ionInfo.cpp:543
-msgid "Bug? Problem with qhull library, cannot run convex hull."
-msgstr "Bug? Problem mit qhull Bibliothek. Kann convex hull nicht ausführen."
+#: ../src/backend/filters/ionInfo.cpp:457
+msgid "Volume data"
+msgstr ""
 
 #: ../src/backend/filters/dataLoad.cpp:56
 msgid "Auto"
@@ -4339,45 +4262,45 @@ msgstr "Text-Daten"
 msgid "ATO Data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:242
+#: ../src/backend/filters/dataLoad.cpp:238
 msgid " does not exist"
 msgstr " existiert nicht"
 
-#: ../src/backend/filters/dataLoad.cpp:280
-#: ../src/backend/filters/dataLoad.cpp:293
-#: ../src/backend/filters/dataLoad.cpp:336
-#: ../src/backend/filters/dataLoad.cpp:347
-#: ../src/backend/filters/dataLoad.cpp:408
+#: ../src/backend/filters/dataLoad.cpp:276
+#: ../src/backend/filters/dataLoad.cpp:289
+#: ../src/backend/filters/dataLoad.cpp:332
+#: ../src/backend/filters/dataLoad.cpp:343
+#: ../src/backend/filters/dataLoad.cpp:404
 msgid "Error loading file: "
 msgstr "Fehler beim Laden der Datei: "
 
-#: ../src/backend/filters/dataLoad.cpp:310
+#: ../src/backend/filters/dataLoad.cpp:306
 msgid "Sampling is active, loaded "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:311
+#: ../src/backend/filters/dataLoad.cpp:307
 msgid " available."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:319
+#: ../src/backend/filters/dataLoad.cpp:315
 msgid "Loaded entire dataset, "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:319
-#: ../src/backend/filters/dataLoad.cpp:418
+#: ../src/backend/filters/dataLoad.cpp:315
+#: ../src/backend/filters/dataLoad.cpp:414
 msgid " points."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:362
+#: ../src/backend/filters/dataLoad.cpp:358
 msgid ""
 "Data file contained incorrect number of columns -- should be 3 or 4, was "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:417
+#: ../src/backend/filters/dataLoad.cpp:413
 msgid "Loaded dataset, "
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:449
+#: ../src/backend/filters/dataLoad.cpp:445
 msgid ""
 "Warning:One or more bounds of the loaded data approaches the limits of "
 "numerical stability for the internal data type(magnitude too large). "
@@ -4387,291 +4310,295 @@ msgstr ""
 "der numerischen Stabilität des internen Datentyps (Größenordnung zu groß). "
 "Erwägen Sie die Daten vor dem Laden zu skalieren. "
 
-#: ../src/backend/filters/dataLoad.cpp:481
-#: ../src/backend/filters/rangeFile.cpp:567
+#: ../src/backend/filters/dataLoad.cpp:469
+#: ../src/backend/filters/dataLoad.cpp:490
+#: ../src/backend/filters/rangeFile.cpp:569
+#: ../src/backend/filters/rangeFile.cpp:589
 msgid "File"
 msgstr "Datei"
 
-#: ../src/backend/filters/dataLoad.cpp:482
+#: ../src/backend/filters/dataLoad.cpp:470
 msgid "File from which to load data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:493
+#: ../src/backend/filters/dataLoad.cpp:473
+msgid ""
+"Readable files (*.xml, *.pos, *.txt,*.csv, *.ato)|*.xml;*.pos;*.txt;*.csv;*."
+"ato|All Files|*"
+msgstr ""
+
+#: ../src/backend/filters/dataLoad.cpp:483
 msgid "File type"
 msgstr "Dateityp"
 
-#: ../src/backend/filters/dataLoad.cpp:495
+#: ../src/backend/filters/dataLoad.cpp:485
 msgid "Type of file to be loaded"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:509
+#: ../src/backend/filters/dataLoad.cpp:500
 msgid "Entries per point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:510
+#: ../src/backend/filters/dataLoad.cpp:501
 msgid "Number of decimal values in file per 3D point (normally 4)"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:529
+#: ../src/backend/filters/dataLoad.cpp:520
 msgid "File \"Endianness\""
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:530
+#: ../src/backend/filters/dataLoad.cpp:521
 msgid "On-disk data storage format. If file won't load, just try each"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:555
+#: ../src/backend/filters/dataLoad.cpp:546
 msgid "Relative offset of each entry in file for point's X position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:563
+#: ../src/backend/filters/dataLoad.cpp:554
 msgid "Relative offset of each entry in file for point's Y position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:571
+#: ../src/backend/filters/dataLoad.cpp:562
 msgid "Relative offset of each entry in file for point's Z position"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:579
+#: ../src/backend/filters/dataLoad.cpp:570
 msgid ""
 "Relative offset of each entry in file to use for scalar value of 3D point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:582
+#: ../src/backend/filters/dataLoad.cpp:573
 msgid "Value Label"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:586
+#: ../src/backend/filters/dataLoad.cpp:577
 msgid "Name for the scalar value associated with each point"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:589
+#: ../src/backend/filters/dataLoad.cpp:580
 msgid "Format params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:595
+#: ../src/backend/filters/dataLoad.cpp:586
 msgid "Enabled"
 msgstr "Aktiviert"
 
-#: ../src/backend/filters/dataLoad.cpp:599
+#: ../src/backend/filters/dataLoad.cpp:590
 msgid "Load this file?"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:610
+#: ../src/backend/filters/dataLoad.cpp:601
 msgid "Sample data"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:613
+#: ../src/backend/filters/dataLoad.cpp:604
 msgid ""
 "Perform random selection on file contents, instead of loading entire file"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:620
+#: ../src/backend/filters/dataLoad.cpp:611
 msgid "Load Limit (MB)"
 msgstr "Ladelimit (MB)"
 
-#: ../src/backend/filters/dataLoad.cpp:623
+#: ../src/backend/filters/dataLoad.cpp:614
 msgid "Limit for size of data to load"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:630
+#: ../src/backend/filters/dataLoad.cpp:621
 msgid "Monitor"
 msgstr "Monitor"
 
-#: ../src/backend/filters/dataLoad.cpp:634
+#: ../src/backend/filters/dataLoad.cpp:625
 msgid ""
 "Watch file timestamp to track changes to file contents from other programs"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:636
+#: ../src/backend/filters/dataLoad.cpp:629
 msgid "Load params."
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:646
+#: ../src/backend/filters/dataLoad.cpp:636
 msgid "Default colour "
 msgstr "Bevorzugte Farbe "
 
-#: ../src/backend/filters/dataLoad.cpp:649
+#: ../src/backend/filters/dataLoad.cpp:639
 msgid "Default colour for points, if not overridden by other filters"
 msgstr ""
 
-#: ../src/backend/filters/dataLoad.cpp:654
+#: ../src/backend/filters/dataLoad.cpp:644
 msgid "Draw Size"
 msgstr "Draw Size"
 
-#: ../src/backend/filters/dataLoad.cpp:657
+#: ../src/backend/filters/dataLoad.cpp:647
 msgid "Default size for points, if not overridden by other filters"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:125
+#: ../src/backend/filters/spectrumPlot.cpp:122
 msgid "Extrema"
 msgstr "Extrema"
 
-#: ../src/backend/filters/spectrumPlot.cpp:174
+#: ../src/backend/filters/spectrumPlot.cpp:171
 msgid "count"
 msgstr "Anzahl"
 
-#: ../src/backend/filters/spectrumPlot.cpp:259
+#: ../src/backend/filters/spectrumPlot.cpp:256
 msgid "Mixed data"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:400
+#: ../src/backend/filters/spectrumPlot.cpp:390
 msgid "Step size for spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:409
+#: ../src/backend/filters/spectrumPlot.cpp:395
 msgid "Auto Min/max"
 msgstr "Auto Min/max"
 
-#: ../src/backend/filters/spectrumPlot.cpp:413
+#: ../src/backend/filters/spectrumPlot.cpp:399
 msgid "Automatically compute spectrum upper and lower bound"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:418
+#: ../src/backend/filters/spectrumPlot.cpp:404
 msgid "Min"
 msgstr "Min"
 
-#: ../src/backend/filters/spectrumPlot.cpp:421
+#: ../src/backend/filters/spectrumPlot.cpp:407
 msgid "Starting position for spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:426
+#: ../src/backend/filters/spectrumPlot.cpp:412
 msgid "Max"
 msgstr "Max"
 
-#: ../src/backend/filters/spectrumPlot.cpp:429
+#: ../src/backend/filters/spectrumPlot.cpp:415
 msgid "Ending position for spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:437
+#: ../src/backend/filters/spectrumPlot.cpp:423
 msgid "Logarithmic"
 msgstr "Logarithmisch"
 
-#: ../src/backend/filters/spectrumPlot.cpp:440
+#: ../src/backend/filters/spectrumPlot.cpp:426
 msgid "Convert the plot to logarithmic mode"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:462
+#: ../src/backend/filters/spectrumPlot.cpp:448
 msgid "Visual style of plot"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:475
+#: ../src/backend/filters/spectrumPlot.cpp:455
 msgid "Colour of plotted spectrum"
 msgstr ""
 
-#: ../src/backend/filters/spectrumPlot.cpp:709
-msgid "Insufficient memory for spectrum filter."
-msgstr "Nicht genügend Speicher für Spektrumfilter"
-
-#: ../src/backend/filters/spectrumPlot.cpp:711
-msgid "Bad bincount value in spectrum filter."
-msgstr "Falsche Binanzahl im Spektrumfilter."
-
-#: ../src/backend/filters/rangeFile.cpp:149
+#: ../src/backend/filters/rangeFile.cpp:151
 msgid "Pre-Allocate"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:280 ../src/backend/filter.cpp:46
+#: ../src/backend/filters/rangeFile.cpp:282 ../src/backend/filter.cpp:48
 msgid "Range"
 msgstr "Range"
 
-#: ../src/backend/filters/rangeFile.cpp:569
+#: ../src/backend/filters/rangeFile.cpp:572
 msgid "File to use for range data"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:581
+#: ../src/backend/filters/rangeFile.cpp:582
 msgid "Drop unranged"
 msgstr "Nicht gerangete ausschalten"
 
-#: ../src/backend/filters/rangeFile.cpp:583
+#: ../src/backend/filters/rangeFile.cpp:584
 msgid "Remove unranged points when generating output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:603
+#: ../src/backend/filters/rangeFile.cpp:594
+msgid "Legend"
+msgstr ""
+
+#: ../src/backend/filters/rangeFile.cpp:596
+msgid "Display colour legend for enabled ions"
+msgstr ""
+
+#: ../src/backend/filters/rangeFile.cpp:600
+msgid "View"
+msgstr ""
+
+#: ../src/backend/filters/rangeFile.cpp:616
 msgid "All Ions"
 msgstr "Alle Ionen"
 
-#: ../src/backend/filters/rangeFile.cpp:604
+#: ../src/backend/filters/rangeFile.cpp:617
 msgid "Enable/disable all ions at once"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:612
+#: ../src/backend/filters/rangeFile.cpp:625
 msgid "Species"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:619
+#: ../src/backend/filters/rangeFile.cpp:632
 msgid "IonID "
 msgstr "IonID "
 
-#: ../src/backend/filters/rangeFile.cpp:620
+#: ../src/backend/filters/rangeFile.cpp:633
 msgid "Enable/disable specified ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:633
+#: ../src/backend/filters/rangeFile.cpp:643
 msgid "Active Ion "
 msgstr "Actives Ion "
 
-#: ../src/backend/filters/rangeFile.cpp:635
+#: ../src/backend/filters/rangeFile.cpp:645
 msgid "If true, ion is used in output"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:649
+#: ../src/backend/filters/rangeFile.cpp:655
 msgid "Colour "
 msgstr "Farbe"
 
-#: ../src/backend/filters/rangeFile.cpp:652
+#: ../src/backend/filters/rangeFile.cpp:659
 msgid "Colour used to represent ion"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:676
+#: ../src/backend/filters/rangeFile.cpp:682
 msgid "All Ranges"
 msgstr "Alle Range"
 
-#: ../src/backend/filters/rangeFile.cpp:677
+#: ../src/backend/filters/rangeFile.cpp:683
 msgid "Enable/disable all ranges"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:695
+#: ../src/backend/filters/rangeFile.cpp:698
 msgid "Active Rng "
 msgstr "Activer Rng "
 
-#: ../src/backend/filters/rangeFile.cpp:698
+#: ../src/backend/filters/rangeFile.cpp:701
 msgid ""
 "Enable/disable specified range (ion must also be enabled to activiate range)"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:702
+#: ../src/backend/filters/rangeFile.cpp:705
 msgid "Ion "
 msgstr "Ion "
 
-#: ../src/backend/filters/rangeFile.cpp:705
+#: ../src/backend/filters/rangeFile.cpp:708
 msgid "Name of ion associate to this range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:714
+#: ../src/backend/filters/rangeFile.cpp:717
 msgid "Start rng "
 msgstr "Start rng "
 
-#: ../src/backend/filters/rangeFile.cpp:717
+#: ../src/backend/filters/rangeFile.cpp:720
 msgid "Start value for range"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:722
+#: ../src/backend/filters/rangeFile.cpp:725
 msgid "End rng "
 msgstr "End rng "
 
-#: ../src/backend/filters/rangeFile.cpp:725
+#: ../src/backend/filters/rangeFile.cpp:728
 msgid "Stopping value for range`"
 msgstr ""
 
-#: ../src/backend/filters/rangeFile.cpp:1029
-msgid "Ranging aborted by user"
-msgstr "Ranging durch User abgebrochen"
-
-#: ../src/backend/filters/rangeFile.cpp:1031
-msgid "Insufficient memory for range"
-msgstr "Nicht genug Speicher für Range"
-
 #: ../src/backend/state.cpp:137
 msgid ""
 "This file is a \"state\" file for the 3Depict program, and stores "
@@ -4686,25 +4613,25 @@ msgstr ""
 msgid "Failed to allocate parser"
 msgstr "Kann Parser nicht zuordnen"
 
-#: ../src/backend/state.cpp:326
+#: ../src/backend/state.cpp:325
 msgid ""
 "Unable to retrieve root node in input state file... Is this really a non-"
 "empty XML file?"
 msgstr ""
 
-#: ../src/backend/state.cpp:333
+#: ../src/backend/state.cpp:332
 msgid "Base state node missing. Is this really a state XML file??"
 msgstr ""
 
-#: ../src/backend/state.cpp:362
+#: ../src/backend/state.cpp:361
 msgid "State was created by a newer version of this program.. "
 msgstr "Status wurde von einer neueren Version dieses Programmes erstellt.. "
 
-#: ../src/backend/state.cpp:363
+#: ../src/backend/state.cpp:362
 msgid "file reading will continue, but may fail."
 msgstr "Datei wird weiter eingelesen kann aber unter Umständen fehlschlagen."
 
-#: ../src/backend/state.cpp:368
+#: ../src/backend/state.cpp:367
 msgid ""
 "Warning, unparseable version number in state file. File reading will "
 "continue, but may fail"
@@ -4712,115 +4639,107 @@ msgstr ""
 "Warnung: Nicht lesbare Versionsnummer in Statusdatei. Datei wird weiter "
 "eingelesen kann aber unter Umständen fehlschlagen."
 
-#: ../src/backend/state.cpp:375
+#: ../src/backend/state.cpp:374
 msgid "Unable to find the \"writer\" node"
 msgstr "Kann \"writer\" node nicht finden"
 
-#: ../src/backend/state.cpp:385
+#: ../src/backend/state.cpp:384
 msgid "Unable to find the \"backcolour\" node."
 msgstr "Unable to find the \"backcolour\" node."
 
-#: ../src/backend/state.cpp:392
+#: ../src/backend/state.cpp:391
 msgid "\"backcolour\" node missing \"r\" value."
 msgstr "\"backcolour\" node fehlt \"r\" Wert."
 
-#: ../src/backend/state.cpp:397
+#: ../src/backend/state.cpp:396
 msgid "Unable to interpret \"backColour\" node's \"r\" value."
 msgstr "Kann \"backColour\" node's \"r\" Wert nicht interpretieren."
 
-#: ../src/backend/state.cpp:405
+#: ../src/backend/state.cpp:404
 msgid "\"backcolour\" node missing \"g\" value."
 msgstr "\"backcolour\" node fehlt \"g\" Wert."
 
-#: ../src/backend/state.cpp:411
+#: ../src/backend/state.cpp:410
 msgid "Unable to interpret \"backColour\" node's \"g\" value."
 msgstr "Kann \"backColour\" node's \"g\" Wert nicht interpretieren."
 
-#: ../src/backend/state.cpp:419
+#: ../src/backend/state.cpp:418
 msgid "\"backcolour\" node missing \"b\" value."
 msgstr "\"backcolour\" node fehlt \"b\" Wert."
 
-#: ../src/backend/state.cpp:425
+#: ../src/backend/state.cpp:424
 msgid "Unable to interpret \"backColour\" node's \"b\" value."
 msgstr "Kann \"backColour\" node's \"b\" Wert nicht interpretieren."
 
-#: ../src/backend/state.cpp:432
+#: ../src/backend/state.cpp:431
 msgid "\"backcolour\"s rgb values must be in range [0,1]"
 msgstr "\"backcolour\"s rgb Wert muss im Bereich [0,1] liegen"
 
-#: ../src/backend/state.cpp:460
+#: ../src/backend/state.cpp:459
 msgid "Unable to find or interpret \"showaxis\" node"
 msgstr "Kann \"showaxis\" node nicht interpretieren"
 
-#: ../src/backend/state.cpp:504
+#: ../src/backend/state.cpp:503
 msgid "Unable to locate \"filtertree\" node."
 msgstr "Kann \"filtertree\" node nicht finden."
 
-#: ../src/backend/state.cpp:520
+#: ../src/backend/state.cpp:519
 msgid "Cameras section missing \"active\" node."
 msgstr "Cameras section fehlt \"active\" node."
 
-#: ../src/backend/state.cpp:528
+#: ../src/backend/state.cpp:527
 msgid "Unable to find property \"value\"  for \"cameras->active\" node."
 msgstr "Kann \"Eigenschaftswert\"  für \"Kamera->aktiv\" Node nicht finden."
 
-#: ../src/backend/state.cpp:534
+#: ../src/backend/state.cpp:533
 msgid "Unable to interpret property \"value\"  for \"cameras->active\" node."
 msgstr ""
 "Kann \"Eigenschaftswert\"  für \"Kamera->aktiv\" Node nicht interpretieren."
 
-#: ../src/backend/state.cpp:553
+#: ../src/backend/state.cpp:552
 msgid "Failed to interpret camera state for camera : "
 msgstr ""
 
-#: ../src/backend/state.cpp:561
+#: ../src/backend/state.cpp:560
 msgid "Unable to interpret the camera type for camera : "
 msgstr "Kann den Kameratype nicht interpretieren für :"
 
-#: ../src/backend/state.cpp:597
+#: ../src/backend/state.cpp:596
 msgid "Unable to locate stash name for stash "
 msgstr "Kann den Stashnamen für Stash  nicht finden"
 
-#: ../src/backend/state.cpp:604
+#: ../src/backend/state.cpp:603
 msgid "Empty stash name for stash "
 msgstr "Leerer Stashname für Stash"
 
-#: ../src/backend/state.cpp:613
+#: ../src/backend/state.cpp:612
 msgid "No filter tree for stash:"
 msgstr ""
 
-#: ../src/backend/state.cpp:619
+#: ../src/backend/state.cpp:618
 msgid "For stash "
 msgstr "Für Stash "
 
-#: ../src/backend/state.cpp:651
+#: ../src/backend/state.cpp:650
 msgid "Unrecognised effect :"
 msgstr "Nichterkannter Effekt :"
 
-#: ../src/backend/state.cpp:661
+#: ../src/backend/state.cpp:660
 msgid "Duplicate effect found"
 msgstr "Doppelter Effekt gefunden"
 
-#: ../src/backend/state.cpp:661
+#: ../src/backend/state.cpp:660
 msgid " cannot use."
 msgstr "kann nicht   verwenden."
 
-#: ../src/backend/state.cpp:671
+#: ../src/backend/state.cpp:670
 msgid "Error reading effect : "
 msgstr "Fehler beim Lesen:"
 
-#: ../src/backend/state.cpp:789
+#: ../src/backend/state.cpp:866
 msgid "-merge"
 msgstr ""
 
-#: ../src/backend/state.cpp:794
-msgid ""
-" Unable to merge stashes correctly. This is improbable, so please report "
-"this."
-msgstr ""
-" Kann stashes nicht korrekt zusammenführen. Dies ist nicht möglich bitte "
-"melden Sie das."
-
 #: ../src/backend/filtertreeAnalyse.cpp:199
 msgid ""
 "Parent filter has no output, but filter requires input -- there is no point "
@@ -4873,94 +4792,127 @@ msgstr ""
 msgid "Filter missing needed parent"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:554
+#: ../src/backend/filtertreeAnalyse.cpp:555
 msgid "Composition results possibly altered"
 msgstr ""
 
-#: ../src/backend/filtertreeAnalyse.cpp:555
+#: ../src/backend/filtertreeAnalyse.cpp:556
 msgid ""
 "Filters and settings selected that could bias reported composition. Check to "
 "see if species biasing may occcur in the filter tree - this warning is "
 "provisional only."
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:40
+#: ../src/backend/APT/APTFileIO.cpp:43 ../src/backend/APT/APTFileIO.cpp:78
+#: ../src/backend/APT/APTFileIO.cpp:102
+msgid "Error opening file"
+msgstr "Fehler beim Öffnen der Datei"
+
+#: ../src/backend/APT/APTFileIO.cpp:44
+msgid "Only found header, no data"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:45
+msgid "Unable to reopen file after first scan"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:46
+msgid "Error whilst reading file contents"
+msgstr "Fehler beim Lesen des Dateiinhaltes"
+
+#: ../src/backend/APT/APTFileIO.cpp:47 ../src/backend/APT/APTFileIO.cpp:48
+msgid "Unexpected file format"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:49
+msgid "Insufficient memory to continue"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:53
 msgid "Memory allocation failure on POS load"
 msgstr "Speicherzuweisungsfeher beim Laden der pos-Datei"
 
-#: ../src/backend/APT/APTFileIO.cpp:41
+#: ../src/backend/APT/APTFileIO.cpp:54
 msgid "Error opening pos file"
 msgstr "Fehler beim Öffnen der pos-Datei"
 
-#: ../src/backend/APT/APTFileIO.cpp:42
+#: ../src/backend/APT/APTFileIO.cpp:55
 msgid "Pos file empty"
 msgstr "Pos-Datei ist leer"
 
-#: ../src/backend/APT/APTFileIO.cpp:43
+#: ../src/backend/APT/APTFileIO.cpp:56
 msgid "Pos file size appears to have non-integer number of entries"
 msgstr ""
 "Pos-Dateigröße scheint eine nicht ganzzahlige Anzahl an Einträgen zu haben"
 
-#: ../src/backend/APT/APTFileIO.cpp:44
+#: ../src/backend/APT/APTFileIO.cpp:57
 msgid "Error reading from pos file (after open)"
 msgstr "Fehler beim Lesen aus pos-Datei (nach dem öffnen)"
 
-#: ../src/backend/APT/APTFileIO.cpp:45
+#: ../src/backend/APT/APTFileIO.cpp:58
 msgid "Error - Found NaN in pos file"
 msgstr "Fehler - Fand NaN in pos-Datei"
 
-#: ../src/backend/APT/APTFileIO.cpp:46
+#: ../src/backend/APT/APTFileIO.cpp:59
+msgid "Error - Found Inf in pos file"
+msgstr ""
+
+#: ../src/backend/APT/APTFileIO.cpp:60
 msgid "Pos load aborted by interrupt."
 msgstr "Pos laden durch Interrupt abgebrochen."
 
-#: ../src/backend/APT/APTFileIO.cpp:66
+#: ../src/backend/APT/APTFileIO.cpp:79
 msgid "No numerical data found"
 msgstr "Keine numerischen Daten gefunden"
 
-#: ../src/backend/APT/APTFileIO.cpp:67
+#: ../src/backend/APT/APTFileIO.cpp:80
 msgid "Error re-opening file, after first scan"
 msgstr "Fehler beim nochmaligen Öffnen der Datei nach dem ersten Scan"
 
-#: ../src/backend/APT/APTFileIO.cpp:68
+#: ../src/backend/APT/APTFileIO.cpp:81
 msgid "Unable to read file contents after open"
 msgstr "Kann den Dateiinhalt nach dem Öffnen nich lesen"
 
-#: ../src/backend/APT/APTFileIO.cpp:70
+#: ../src/backend/APT/APTFileIO.cpp:82
+msgid "Error interpreting field in file"
+msgstr "Fehler beim Interpretieren eine Feldes in der Datei"
+
+#: ../src/backend/APT/APTFileIO.cpp:83
 msgid "Incorrect number of fields in file"
 msgstr "Die Datei enthält eine falsche Anzahl von Feldern"
 
-#: ../src/backend/APT/APTFileIO.cpp:71 ../src/backend/APT/APTFileIO.cpp:93
+#: ../src/backend/APT/APTFileIO.cpp:84 ../src/backend/APT/APTFileIO.cpp:106
 msgid "Unable to allocate memory to store data"
 msgstr "Kann Speicher nicht zuordnen"
 
-#: ../src/backend/APT/APTFileIO.cpp:90
+#: ../src/backend/APT/APTFileIO.cpp:103
 msgid "File is empty"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:91
+#: ../src/backend/APT/APTFileIO.cpp:104
 msgid "Filesize does not match expected format"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:92
+#: ../src/backend/APT/APTFileIO.cpp:105
 msgid "File version number not <4, as expected"
 msgstr ""
 
-#: ../src/backend/APT/APTFileIO.cpp:94
+#: ../src/backend/APT/APTFileIO.cpp:107
 msgid "Unable to detect endian-ness in file"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:47
+#: ../src/backend/APT/APTRanges.cpp:48
 msgid "Error opening file, check name and permissions."
 msgstr "Fehler beim Öffnen der Datei, überprüfe Namen und Berechtigungen."
 
-#: ../src/backend/APT/APTRanges.cpp:48
+#: ../src/backend/APT/APTRanges.cpp:49
 msgid ""
 "Error interpreting range file header, expecting ion count and range count, "
 "respectively."
 msgstr ""
 "Fehler beim Rangedatei interpretieren, erwarte Ionenanzahl bzw. Rangeanzahl."
 
-#: ../src/backend/APT/APTRanges.cpp:49
+#: ../src/backend/APT/APTRanges.cpp:50
 msgid ""
 "Range file appears to be empty, check file is a proper range file and is not "
 "empty."
@@ -4968,15 +4920,15 @@ msgstr ""
 "Rangedatei scheint leer zu sein. Prüfe ob die Datei wirklich ein Rangedatei "
 "und nicht leer ist."
 
-#: ../src/backend/APT/APTRanges.cpp:50
+#: ../src/backend/APT/APTRanges.cpp:51
 msgid "Error reading the long name for ion."
 msgstr "Fehler beim Lesen des langen Namens für Ion."
 
-#: ../src/backend/APT/APTRanges.cpp:51
+#: ../src/backend/APT/APTRanges.cpp:52
 msgid "Error reading the short name for ion."
 msgstr "Fehler beim Lesen des kurzen Namens für Ion."
 
-#: ../src/backend/APT/APTRanges.cpp:52
+#: ../src/backend/APT/APTRanges.cpp:53
 msgid ""
 "Error reading colour data in the file, expecting 3 decimal values, space "
 "separated."
@@ -4984,39 +4936,39 @@ msgstr ""
 "Fehler beim Lesen der Farbinformationen in der Datei. Erwarte 3, durch "
 "Leerzeichen getrennte, Dezimalwerte."
 
-#: ../src/backend/APT/APTRanges.cpp:53
+#: ../src/backend/APT/APTRanges.cpp:54
 msgid ""
 "Tried skipping to table separator line (line with dashes), but did not find "
 "it."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:54
+#: ../src/backend/APT/APTRanges.cpp:55
 msgid ""
 "Number of ions in the table header did not match the number specified at the "
 "start of the file"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:55
+#: ../src/backend/APT/APTRanges.cpp:56
 msgid ""
 "Unexpected failure whilst trying to skip over range lead-in data (bit before "
 "range start value)"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:56
+#: ../src/backend/APT/APTRanges.cpp:57
 msgid ""
 "Range table had an incorrect number of entries, should be 2 or 3 + number of "
 "ranges"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:57
+#: ../src/backend/APT/APTRanges.cpp:58
 msgid "Unable to read range start and end values"
 msgstr "Kann Anfangs und Endwert des Range nicht lesen"
 
-#: ../src/backend/APT/APTRanges.cpp:58
+#: ../src/backend/APT/APTRanges.cpp:59
 msgid "Unable to read range table entry"
 msgstr "Kann Rangetabelleneintrag nich lesen"
 
-#: ../src/backend/APT/APTRanges.cpp:59
+#: ../src/backend/APT/APTRanges.cpp:60
 msgid ""
 "Error reading file, unexpected format, are you sure it is a proper range "
 "file?"
@@ -5024,31 +4976,35 @@ msgstr ""
 "Fehler beim Lesen der Datei: Unerwartetes Format, sind Sie sicher, dass dies "
 "eine korrekte Rangedatei ist?"
 
-#: ../src/backend/APT/APTRanges.cpp:60
+#: ../src/backend/APT/APTRanges.cpp:61
 msgid ""
 "Too many ranges appeared to have range entries with no usable data (eg, all "
 "blank)"
 msgstr "Zu viele Ranges scheinen  ungültige Einträge zu haben (z.B. alle leer)"
 
-#: ../src/backend/APT/APTRanges.cpp:61
+#: ../src/backend/APT/APTRanges.cpp:62
 msgid ""
 "Range file appears to contain malformed data, check things like start and "
 "ends of m/c are not equal or flipped."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:62
+#: ../src/backend/APT/APTRanges.cpp:63
 msgid "Range file appears to be inconsistent (eg, overlapping ranges)"
 msgstr "Rangedatei schein inkonsistent zu sein (z.B. überlappende Ranges)"
 
-#: ../src/backend/APT/APTRanges.cpp:63
+#: ../src/backend/APT/APTRanges.cpp:64
 msgid "No ion name mapping found  for multiple ion."
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:64
+#: ../src/backend/APT/APTRanges.cpp:65
 msgid "Polyatomic extension range matches multiple masses in first section"
 msgstr ""
 
-#: ../src/backend/APT/APTRanges.cpp:1387
+#: ../src/backend/APT/APTRanges.cpp:66
+msgid "Range file is exceedingly large. Refusing to open"
+msgstr ""
+
+#: ../src/backend/APT/APTRanges.cpp:1403
 msgid ""
 "Range headings do not match order of the ions listed in the name "
 "specifications. The name specification ordering will be used when reading "
@@ -5057,15 +5013,19 @@ msgid ""
 "Check range-species associations actually match what you expect."
 msgstr ""
 
-#: ../src/backend/filter.cpp:45
+#: ../src/backend/filter.cpp:46
+msgid "2D Plot"
+msgstr ""
+
+#: ../src/backend/filter.cpp:47
 msgid "Draw"
 msgstr "Zeichnen"
 
-#: ../src/backend/filter.cpp:47
+#: ../src/backend/filter.cpp:49
 msgid "Voxel"
 msgstr "Voxel"
 
-#: ../src/wx/wxcomponents.h:98
+#: ../src/wx/wxcomponents.h:82
 msgid "treeCtrl"
 msgstr ""
 
@@ -5073,7 +5033,7 @@ msgstr ""
 msgid "Ion. Transform"
 msgstr "Ion. Transformieren"
 
-#: ../src/backend/filters/ionColour.h:61
+#: ../src/backend/filters/ionColour.h:63
 msgid "Spectral Colour"
 msgstr "Spectral Farbe"
 
@@ -5089,7 +5049,7 @@ msgstr "Ion Sampler"
 msgid "Ion info"
 msgstr "Ioneninfo"
 
-#: ../src/backend/filters/dataLoad.h:136
+#: ../src/backend/filters/dataLoad.h:135
 msgid "Pos Data"
 msgstr "POS-Daten"
 
@@ -5097,7 +5057,7 @@ msgstr "POS-Daten"
 msgid "Ext. Program"
 msgstr "Ext. Programm"
 
-#: ../src/backend/filters/rangeFile.h:89
+#: ../src/backend/filters/rangeFile.h:93
 msgid "Ranging"
 msgstr "Ranging"
 
@@ -5212,5 +5172,158 @@ msgid ""
 "views"
 msgstr ""
 
+#~ msgid "Inconsistent number of columns found"
+#~ msgstr "Inkonsistente Anzahl an Spalten gefunden"
+
+#~ msgid "Tile "
+#~ msgstr "Tile "
+
+#~ msgid "Filter Defaults"
+#~ msgstr "Filtervoreinstellungen"
+
+#~ msgid "Notice"
+#~ msgstr "Notiz"
+
+#~ msgid "For security reasons, defaults are not modifiable for this filter"
+#~ msgstr ""
+#~ "Aus Sicherheitsgründen können die Voreinstellungen für diesen Filter "
+#~ "nicht geändert werden."
+
+#~ msgid "Pref"
+#~ msgstr "Pref"
+
+#~ msgid "New stash name...."
+#~ msgstr "Neuer Stashname..."
+
+#~ msgid ""
+#~ "Range Files (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
+#~ "Environment File (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|All Files (*)|*"
+#~ msgstr ""
+#~ "Rangedatei (*rng; *env; *rrng)|*rng;*env;*rrng|RNG File (*.rng)|*.rng|"
+#~ "Environment Datei (*.env)|*.env|RRNG Files (*.rrng)|*.rrng|Alle Dateien "
+#~ "(*)|*"
+
+#~ msgid "Next Fullscreen mode: none"
+#~ msgstr "Nächster Vollbildmodus: keiner"
+
+#~ msgid "Next Fullscreen mode: complete"
+#~ msgstr "Nächster Vollbildmodus: vollständig"
+
+#~ msgid "Next Fullscreen mode: with toolbars"
+#~ msgstr "Nächster Vollbildmodus: mit Werkzeugleisten"
+
+#~ msgid "Next Mode: No fullscreen"
+#~ msgstr "Nächster Modus: Kein Vollbild"
+
+#~ msgid "Next Mode: fullscreen w/o toolbar"
+#~ msgstr "Nächster Modus: Vollbild ohne Werkzeugleiste"
+
+#~ msgid "Next Mode: fullscreen with toolbar"
+#~ msgstr "Nächster Modus: Vollbild mit Werkzeugleiste"
+
+#~ msgid "displays this message"
+#~ msgstr "zeigt diese Nachricht"
+
+#~ msgid "inputfile"
+#~ msgstr "Eingabedatei"
+
+#~ msgid "Error processing command line"
+#~ msgstr "Fehler beim Ausführen der Kommandozeile"
+
+#~ msgid "Unable to set working directory"
+#~ msgstr "Kann Arbeitsverzeichnis nicht festlegen"
+
+#~ msgid "Error saving posfile result for external program"
+#~ msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm"
+
+#~ msgid "Error saving plot result for externalprogram"
+#~ msgstr "Fehler beim Speichern von Posdateiergebnis für externes Programm"
+
+#~ msgid "Error creating temporary directory"
+#~ msgstr "Fehler beim Anlegen des temporären Verzeichnisses"
+
+#~ msgid "Detected unusable number of columns in plot"
+#~ msgstr "Detected unusable number of columns in plot"
+
+#~ msgid "Unable to parse plot result from external program"
+#~ msgstr "Unable to parse plot result from external program"
+
+#~ msgid "Unable to load ions from external program"
+#~ msgstr "Kann Ionen von externem Programm nicht laden"
+
+#~ msgid "Unable to perform commandline substitution"
+#~ msgstr "Unable to perform commandline substitution"
+
+#~ msgid "Error executing external program"
+#~ msgstr "Fehler beim Ausführen von externem Programm"
+
+#~ msgid "Clustering aborted"
+#~ msgstr "Clustering abgebrochen"
+
+#~ msgid "No core ions for cluster"
+#~ msgstr "Keine Kernionen für Cluster"
+
+#~ msgid "No bulk ions for cluster"
+#~ msgstr "Keine Bulkionen für Cluster"
+
+#~ msgid "Voxelisation aborted"
+#~ msgstr "Voxelisation abgebrochen"
+
+#~ msgid "Out of memory"
+#~ msgstr "Zu wenig Speicher"
+
+#~ msgid "Unable to perform filter convolution"
+#~ msgstr "Kann Filter convolution nicht durchführen"
+
+#~ msgid "Voxelisation bounds are invalid"
+#~ msgstr "Voxelisation Grenzen sin ungültig"
+
+#~ msgid "Too many bins in comp. profile."
+#~ msgstr "Zu viele Bins im Konzentrationsprofil."
+
+#~ msgid "Not enough memory for comp. profile."
+#~ msgstr "Nicht genug Speicher für Konz.-Profil."
+
+#~ msgid "Aborted composition prof."
+#~ msgstr "Konzentrationspr. abgebr."
+
+#~ msgid "Spatial analysis aborted by user"
+#~ msgstr "Spatial analysis aborted by user"
+
+#~ msgid "Insufficient data to complete analysis."
+#~ msgstr "Ungenügend Daten zum Fertigstellen der Analyse."
+
+#~ msgid "Unable to allocate memory"
+#~ msgstr "Kann Speicher nicht zuweisen"
+
+#~ msgid "Downsample Aborted"
+#~ msgstr "Datenreduktion abgebrochen"
+
+#~ msgid "Insuffient memory for downsample"
+#~ msgstr "Nicht genug Speicher zur Datenreduktion"
+
+#~ msgid "Insufficient memory for operation"
+#~ msgstr "Nicht genügend Speicher für Operation"
+
+#~ msgid "Bug? Problem with qhull library, cannot run convex hull."
+#~ msgstr ""
+#~ "Bug? Problem mit qhull Bibliothek. Kann convex hull nicht ausführen."
+
+#~ msgid "Insufficient memory for spectrum filter."
+#~ msgstr "Nicht genügend Speicher für Spektrumfilter"
+
+#~ msgid "Bad bincount value in spectrum filter."
+#~ msgstr "Falsche Binanzahl im Spektrumfilter."
+
+#~ msgid "Ranging aborted by user"
+#~ msgstr "Ranging durch User abgebrochen"
 
+#~ msgid "Insufficient memory for range"
+#~ msgstr "Nicht genug Speicher für Range"
 
+#~ msgid ""
+#~ " Unable to merge stashes correctly. This is improbable, so please report "
+#~ "this."
+#~ msgstr ""
+#~ " Kann stashes nicht korrekt zusammenführen. Dies ist nicht möglich bitte "
+#~ "melden Sie das."
diff --git a/translations/makeTranslations b/translations/makeTranslations
index 6f176d8..1be87fe 100755
--- a/translations/makeTranslations
+++ b/translations/makeTranslations
@@ -6,7 +6,7 @@
 #follow some random poorly documented hierarchy and naming system. (Looking at you gettextize!)
 
 #extract program name from sources -- Now with added case sensitivity hack!
-PROGRAM_NAME=`cat ../src/common/basics.cpp | grep PROGRAM_NAME | awk -F= '{print $2}' | sed 's/;//g' | sed 's/\"//g' | sed 's/;//' | sed 's/^\s*//'`
+PROGRAM_NAME=`cat ../src/common/constants.cpp | grep PROGRAM_NAME | awk -F= '{print $2}' | sed 's/;//g' | sed 's/\"//g' | sed 's/;//' | sed 's/^\s*//'`
 #Where do we want to install the translations? (if using this script).
 TRANSLATION_INSTALL="/usr/share/locale/"
 
@@ -15,6 +15,10 @@ MAINTAINED_LOCALES="de_DE"
 
 echo "Program name is $PROGRAM_NAME"
 
+if [ x"$PROGRAM_NAME" == x"" ] ; then
+	echo "Unable to extract program name. Aborting"
+	exit 1;
+fi
 
 
 if [ $# -eq 0 ] ; then

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/3depict.git



More information about the debian-science-commits mailing list