[dasher: 31/43] Rewrite event system, RM DasherComponent, add Settings{User, Listener}



commit df5eebe2cfb9b5225787f0174d49782e2d1f72a1
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Mon Jun 13 23:43:59 2011 +0100

    Rewrite event system, RM DasherComponent, add Settings{User,Listener}
    
    Remove central CEventHandler; Objects broadcasting events subclass Observable,
      parameterized by event type (maintains observer list).
    
    CSettingsUsers created in a tree, (for now) sharing single SettingsStore, passed
      into CDashIntfBase constructor (=> rm CreateSettingsStore)
    
    static settings data (only) kept in global {bool,long,string}paramtable,
     decl extern in Parameters.h with defn in Parameters.cpp. SettingsStore
     then stores (only) actual runtime values in each instance, initialized
     from store or default by LoadPersistent.
    Gtk2/Makefile.am includes ../DasherCore/Parameters.cpp into generateschema.
    
    Add DashIntfSettings for common case of redeclaring Get/Set(B/L/S)Param
    
    GC BP_CONVERSION_MODE (written in one place, never read)
    
    Win32 inc. project file + change to use CAppSettings for all access to settings
     (was via CDasherInterfaceBase)

 Src/DasherCore/AlphabetManager.cpp                 |   32 +-
 Src/DasherCore/AlphabetManager.h                   |   10 +-
 Src/DasherCore/AlternatingDirectMode.cpp           |    6 +-
 Src/DasherCore/AlternatingDirectMode.h             |    3 +-
 Src/DasherCore/AutoSpeedControl.cpp                |    4 +-
 Src/DasherCore/AutoSpeedControl.h                  |    7 +-
 Src/DasherCore/BasicLog.cpp                        |    6 +-
 Src/DasherCore/BasicLog.h                          |    2 +-
 Src/DasherCore/ButtonMode.cpp                      |   26 +-
 Src/DasherCore/ButtonMode.h                        |    5 +-
 Src/DasherCore/ButtonMultiPress.cpp                |    4 +-
 Src/DasherCore/ButtonMultiPress.h                  |    2 +-
 Src/DasherCore/CircleStartHandler.cpp              |   31 +-
 Src/DasherCore/CircleStartHandler.h                |   10 +-
 Src/DasherCore/ClickFilter.cpp                     |   13 +-
 Src/DasherCore/ClickFilter.h                       |   19 +-
 Src/DasherCore/CompassMode.cpp                     |   17 +-
 Src/DasherCore/CompassMode.h                       |    5 +-
 Src/DasherCore/ControlManager.cpp                  |   56 ++--
 Src/DasherCore/ControlManager.h                    |   23 +-
 Src/DasherCore/ConversionHelper.cpp                |   11 +-
 Src/DasherCore/ConversionHelper.h                  |    2 +-
 Src/DasherCore/ConversionManager.cpp               |    6 +-
 Src/DasherCore/ConversionManager.h                 |    6 +-
 Src/DasherCore/ConvertingAlphMgr.cpp               |    4 +-
 Src/DasherCore/ConvertingAlphMgr.h                 |    2 +-
 Src/DasherCore/DashIntfScreenMsgs.cpp              |    4 +
 Src/DasherCore/DashIntfScreenMsgs.h                |   12 +-
 Src/DasherCore/DashIntfSettings.cpp                |   32 ++
 Src/DasherCore/DashIntfSettings.h                  |   52 +++
 Src/DasherCore/DasherButtons.cpp                   |    8 +-
 Src/DasherCore/DasherButtons.h                     |    5 +-
 Src/DasherCore/DasherComponent.cpp                 |   58 ----
 Src/DasherCore/DasherComponent.h                   |   40 ---
 Src/DasherCore/DasherCore_vc80.vcproj              |   24 +-
 Src/DasherCore/DasherGameMode.cpp                  |  143 ++++-----
 Src/DasherCore/DasherGameMode.h                    |   24 +-
 Src/DasherCore/DasherInput.h                       |   12 +-
 Src/DasherCore/DasherInterfaceBase.cpp             |  288 +++++++---------
 Src/DasherCore/DasherInterfaceBase.h               |  137 +++------
 Src/DasherCore/DasherModel.cpp                     |   54 ++--
 Src/DasherCore/DasherModel.h                       |    5 +-
 Src/DasherCore/DasherModule.cpp                    |    3 +-
 Src/DasherCore/DasherModule.h                      |    5 +-
 Src/DasherCore/DasherView.cpp                      |    6 +-
 Src/DasherCore/DasherView.h                        |   20 +-
 Src/DasherCore/DasherViewSquare.cpp                |   24 +-
 Src/DasherCore/DasherViewSquare.h                  |   15 +-
 Src/DasherCore/DefaultFilter.cpp                   |   26 +-
 Src/DasherCore/DefaultFilter.h                     |    6 +-
 Src/DasherCore/DynamicFilter.cpp                   |   27 +-
 Src/DasherCore/DynamicFilter.h                     |    6 +-
 Src/DasherCore/Event.h                             |   34 +--
 Src/DasherCore/EventHandler.cpp                    |   79 -----
 Src/DasherCore/EventHandler.h                      |   49 ---
 Src/DasherCore/FrameRate.cpp                       |   30 +-
 Src/DasherCore/FrameRate.h                         |    8 +-
 Src/DasherCore/InputFilter.h                       |    5 +-
 .../LanguageModelling/DictLanguageModel.cpp        |    4 +-
 .../LanguageModelling/DictLanguageModel.h          |    4 +-
 .../LanguageModelling/JapaneseLanguageModel.cpp    |   12 +-
 .../LanguageModelling/JapaneseLanguageModel.h      |    3 +-
 .../LanguageModelling/MixtureLanguageModel.h       |    9 +-
 .../LanguageModelling/PPMLanguageModel.cpp         |    8 +-
 .../LanguageModelling/PPMLanguageModel.h           |    9 +-
 .../LanguageModelling/PPMPYLanguageModel.cpp       |    4 +-
 .../LanguageModelling/PPMPYLanguageModel.h         |    2 +-
 .../LanguageModelling/WordLanguageModel.cpp        |    6 +-
 .../LanguageModelling/WordLanguageModel.h          |    8 +-
 Src/DasherCore/Makefile.am                         |    8 +-
 Src/DasherCore/MandarinAlphMgr.cpp                 |   16 +-
 Src/DasherCore/MandarinAlphMgr.h                   |    4 +-
 Src/DasherCore/NodeCreationManager.cpp             |   68 ++--
 Src/DasherCore/NodeCreationManager.h               |   11 +-
 Src/DasherCore/Observable.h                        |   91 +++++
 Src/DasherCore/OneButtonDynamicFilter.cpp          |    4 +-
 Src/DasherCore/OneButtonDynamicFilter.h            |    2 +-
 Src/DasherCore/OneButtonFilter.cpp                 |    4 +-
 Src/DasherCore/OneButtonFilter.h                   |    6 +-
 Src/DasherCore/OneDimensionalFilter.cpp            |   19 +-
 Src/DasherCore/OneDimensionalFilter.h              |    4 +-
 Src/DasherCore/Parameters.cpp                      |  221 ++++++++++++
 Src/DasherCore/Parameters.h                        |  355 ++++----------------
 Src/DasherCore/SettingsStore.cpp                   |  200 ++++++------
 Src/DasherCore/SettingsStore.h                     |  115 +++++--
 Src/DasherCore/SocketInput.cpp                     |    4 +-
 Src/DasherCore/SocketInput.h                       |    5 +-
 Src/DasherCore/SocketInputBase.cpp                 |   55 ++--
 Src/DasherCore/SocketInputBase.h                   |   11 +-
 Src/DasherCore/StartHandler.h                      |   12 +-
 Src/DasherCore/StylusFilter.cpp                    |    6 +-
 Src/DasherCore/StylusFilter.h                      |    7 +-
 Src/DasherCore/TwoBoxStartHandler.cpp              |   14 +-
 Src/DasherCore/TwoBoxStartHandler.h                |    6 +-
 Src/DasherCore/TwoButtonDynamicFilter.cpp          |   34 +--
 Src/DasherCore/TwoButtonDynamicFilter.h            |    4 +-
 Src/DasherCore/TwoPushDynamicFilter.cpp            |  144 ++++-----
 Src/DasherCore/TwoPushDynamicFilter.h              |    8 +-
 Src/DasherCore/UserLog.cpp                         |   58 ++--
 Src/DasherCore/UserLog.h                           |   10 +-
 Src/DasherCore/UserLogBase.cpp                     |   21 +-
 Src/DasherCore/UserLogBase.h                       |   15 +-
 Src/Gtk2/DasherAppSettings.cpp                     |    2 +
 Src/Gtk2/DasherControl.cpp                         |   54 ++--
 Src/Gtk2/DasherControl.h                           |   11 +-
 Src/Gtk2/GConfStore.cpp                            |    2 +-
 Src/Gtk2/GSettingsStore.cpp                        |    2 +-
 Src/Gtk2/GenerateSchema.cpp                        |    2 +
 Src/Gtk2/GnomeSettingsStore.h                      |    4 +-
 Src/Gtk2/Makefile.am                               |    2 +-
 Src/Gtk2/mouse_input.h                             |    7 +-
 Src/MacOSX/COSXDasherControl.h                     |   14 +-
 Src/MacOSX/COSXDasherControl.mm                    |   93 +++--
 Src/MacOSX/COSXMouseInput.h                        |    8 +-
 Src/MacOSX/COSXSettingsStore.h                     |    8 +-
 Src/MacOSX/COSXSettingsStore.mm                    |   49 +---
 Src/MacOSX/Dasher.xcodeproj/project.pbxproj        |   32 +-
 Src/MacOSX/ModuleSettingsController.h              |    4 +-
 Src/MacOSX/ModuleSettingsController.mm             |    7 +-
 Src/Win32/AppSettings.cpp                          |   14 +-
 Src/Win32/AppSettings.h                            |   36 +--
 Src/Win32/BTSocketInput.cpp                        |    4 +-
 Src/Win32/BTSocketInput.h                          |    2 +-
 Src/Win32/Common/WinOptions.cpp                    |    2 +-
 Src/Win32/Common/WinOptions.h                      |    6 +-
 Src/Win32/Dasher.cpp                               |   26 +-
 Src/Win32/Dasher.h                                 |    3 +-
 Src/Win32/DasherMouseInput.cpp                     |    4 +-
 Src/Win32/DasherMouseInput.h                       |    2 +-
 Src/Win32/DasherWindow.cpp                         |    2 +-
 Src/Win32/ModuleControl.h                          |    8 +-
 Src/Win32/ModuleControlBool.cpp                    |    8 +-
 Src/Win32/ModuleControlBool.h                      |    4 +-
 Src/Win32/ModuleControlLong.cpp                    |    8 +-
 Src/Win32/ModuleControlLong.h                      |    4 +-
 Src/Win32/ModuleControlLongSpin.cpp                |    8 +-
 Src/Win32/ModuleControlLongSpin.h                  |    4 +-
 Src/Win32/ModuleControlString.cpp                  |    8 +-
 Src/Win32/ModuleControlString.h                    |    4 +-
 Src/Win32/ModuleSettings.cpp                       |    8 +-
 Src/Win32/ModuleSettings.h                         |    6 +-
 Src/Win32/Sockets/SocketInput.cpp                  |    4 +-
 Src/Win32/Sockets/SocketInput.h                    |    2 +-
 Src/Win32/Widgets/AdvancedPage.cpp                 |    5 +-
 Src/Win32/Widgets/AdvancedPage.h                   |    8 +-
 Src/Win32/Widgets/AlphabetBox.cpp                  |   18 +-
 Src/Win32/Widgets/AlphabetBox.h                    |    7 +-
 Src/Win32/Widgets/Canvas.cpp                       |   20 +-
 Src/Win32/Widgets/Canvas.h                         |    7 +-
 Src/Win32/Widgets/ControlPage.cpp                  |    8 +-
 Src/Win32/Widgets/ControlPage.h                    |    2 +
 Src/Win32/Widgets/LMPage.cpp                       |    4 +-
 Src/Win32/Widgets/LMPage.h                         |    5 +-
 Src/Win32/Widgets/Prefs.cpp                        |    6 +-
 Src/Win32/Widgets/PrefsPageBase.cpp                |    4 +-
 Src/Win32/Widgets/PrefsPageBase.h                  |    7 +-
 Src/Win32/Widgets/Slidebar.cpp                     |    4 +-
 Src/Win32/Widgets/Slidebar.h                       |    3 +-
 Src/Win32/Widgets/StatusControl.cpp                |   21 +-
 Src/Win32/Widgets/StatusControl.h                  |    6 +-
 Src/Win32/Widgets/ViewPage.cpp                     |   10 +-
 Src/Win32/Widgets/ViewPage.h                       |    4 +-
 Src/iPhone/Classes/ActionConfigurator.mm           |    6 +-
 Src/iPhone/Classes/CDasherInterfaceBridge.h        |    5 +-
 Src/iPhone/Classes/CDasherInterfaceBridge.mm       |   63 ++---
 Src/iPhone/Classes/COSXSettingsStore.h             |    4 +-
 Src/iPhone/Classes/COSXSettingsStore.mm            |    2 +-
 Src/iPhone/Classes/IPhoneFilters.h                 |    6 +-
 Src/iPhone/Classes/IPhoneFilters.mm                |   14 +-
 Src/iPhone/Classes/IPhoneInputs.h                  |   12 +-
 Src/iPhone/Classes/IPhoneInputs.mm                 |   12 +-
 Src/iPhone/Classes/InputMethodSelector.mm          |    4 +-
 Src/iPhone/Classes/ParametersController.mm         |    5 +-
 Src/iPhone/Dasher.xcodeproj/project.pbxproj        |   24 +-
 174 files changed, 1809 insertions(+), 2139 deletions(-)
---
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index 9bc7f32..5a3626d 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -25,7 +25,7 @@
 #include "DasherInterfaceBase.h"
 #include "DasherNode.h"
 #include "Event.h"
-#include "EventHandler.h"
+#include "Observable.h"
 #include "NodeCreationManager.h"
 #include "LanguageModelling/PPMLanguageModel.h"
 #include "LanguageModelling/WordLanguageModel.h"
@@ -50,8 +50,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet)
-  : m_pFirstGroup(NULL), m_pNCManager(pNCManager), m_pAlphabet(pAlphabet), m_pAlphabetMap(pAlphabet->MakeMap()), m_pInterface(pInterface), m_pLastOutput(NULL) {
+CAlphabetManager::CAlphabetManager(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet)
+  : CSettingsUser(pCreateFrom), m_pFirstGroup(NULL), m_pNCManager(pNCManager), m_pAlphabet(pAlphabet), m_pAlphabetMap(pAlphabet->MakeMap()), m_pInterface(pInterface), m_pLastOutput(NULL) {
   //Look for a (single-octet) character not in the alphabet...
   for (char c=33; (c&0x80)==0; c++) {
     string s(&c,1);
@@ -66,20 +66,20 @@ CAlphabetManager::CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreati
   m_vLabels.resize(m_pAlphabet->GetNumberTextSymbols()+1);
 }
 
-void CAlphabetManager::CreateLanguageModel(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore) {
+void CAlphabetManager::CreateLanguageModel() {
   // FIXME - return to using enum here
-  switch (m_pInterface->GetLongParameter(LP_LANGUAGE_MODEL_ID)) {
+  switch (GetLongParameter(LP_LANGUAGE_MODEL_ID)) {
     default:
       // If there is a bogus value for the language model ID, we'll default
       // to our trusty old PPM language model.
     case 0:
-      m_pLanguageModel = new CPPMLanguageModel(pEventHandler, pSettingsStore, m_pAlphabet->GetNumberTextSymbols());
+      m_pLanguageModel = new CPPMLanguageModel(this, m_pAlphabet->GetNumberTextSymbols());
       break;
     case 2:
-      m_pLanguageModel = new CWordLanguageModel(pEventHandler, pSettingsStore, m_pAlphabet, m_pAlphabetMap);
+      m_pLanguageModel = new CWordLanguageModel(this, m_pAlphabet, m_pAlphabetMap);
       break;
     case 3:
-      m_pLanguageModel = new CMixtureLanguageModel(pEventHandler, pSettingsStore, m_pAlphabet, m_pAlphabetMap);
+      m_pLanguageModel = new CMixtureLanguageModel(this, m_pAlphabet, m_pAlphabetMap);
       break;
     case 4:
       m_pLanguageModel = new CCTWLanguageModel(m_pAlphabet->GetNumberTextSymbols());
@@ -331,7 +331,7 @@ void CAlphabetManager::CSymbolNode::PopulateChildren() {
 }
 int CAlphabetManager::CAlphNode::ExpectedNumChildren() {
   int i=m_pMgr->m_pAlphabet->iNumChildNodes;
-  return (m_pMgr->m_pNCManager->GetBoolParameter(BP_CONTROL_MODE)) ? i+1 : i;
+  return (m_pMgr->GetBoolParameter(BP_CONTROL_MODE)) ? i+1 : i;
 }
 
 void CAlphabetManager::GetProbs(vector<unsigned int> *pProbInfo, CLanguageModel::Context context) {
@@ -343,7 +343,7 @@ void CAlphabetManager::GetProbs(vector<unsigned int> *pProbInfo, CLanguageModel:
   const unsigned long iNorm(m_pNCManager->GetAlphNodeNormalization());
   //the case for control mode on, generalizes to handle control mode off also,
   // as then iNorm - control_space == iNorm...
-  const unsigned int iUniformAdd = ((iNorm * m_pNCManager->GetLongParameter(LP_UNIFORM)) / 1000) / iSymbols;
+  const unsigned int iUniformAdd = ((iNorm * GetLongParameter(LP_UNIFORM)) / 1000) / iSymbols;
   const unsigned long iNonUniformNorm = iNorm - iSymbols * iUniformAdd;
   //  m_pLanguageModel->GetProbs(context, Probs, iNorm, ((iNorm * uniform) / 1000));
 
@@ -479,7 +479,7 @@ void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *
   DASHER_ASSERT((*pCProb)[0] == 0);
   const int iMin(pParentGroup ? pParentGroup->iStart : 1);
   const int iMax(pParentGroup ? pParentGroup->iEnd : m_pAlphabet->GetNumberTextSymbols()+1);
-  unsigned int iRange(pParentGroup ? ((*pCProb)[iMax-1] - (*pCProb)[iMin-1]) : m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+  unsigned int iRange(pParentGroup ? ((*pCProb)[iMax-1] - (*pCProb)[iMin-1]) : GetLongParameter(LP_NORMALIZATION));
 
   // TODO: Think through alphabet file formats etc. to make this class easier.
   // TODO: Throw a warning if parent node already has children
@@ -497,10 +497,10 @@ void CAlphabetManager::IterateChildGroups(CAlphNode *pParent, const SGroupInfo *
     const int iStart=i, iEnd = (bSymbol) ? i+1 : pCurrentNode->iEnd;
     //uint64 is platform-dependently #defined in DasherTypes.h as an (unsigned) 64-bit int ("__int64" or "long long int")
     unsigned int iLbnd = (((*pCProb)[iStart-1] - (*pCProb)[iMin-1]) *
-                          (uint64)(m_pNCManager->GetLongParameter(LP_NORMALIZATION))) /
+                          (uint64)(GetLongParameter(LP_NORMALIZATION))) /
                          iRange;
     unsigned int iHbnd = (((*pCProb)[iEnd-1] - (*pCProb)[iMin-1]) *
-                          (uint64)(m_pNCManager->GetLongParameter(LP_NORMALIZATION))) /
+                          (uint64)(GetLongParameter(LP_NORMALIZATION))) /
                          iRange;
     if (bSymbol) {
       pNewChild = (buildAround) ? buildAround->RebuildSymbol(pParent, iLbnd, iHbnd, i) : CreateSymbolNode(pParent, iLbnd, iHbnd, i);
@@ -546,7 +546,7 @@ int CAlphabetManager::CSymbolNode::numChars() {
 }
 
 void CAlphabetManager::CSymbolNode::Output() {
-  if (m_pMgr->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE)) {
+  if (m_pMgr->GetBoolParameter(BP_LM_ADAPTIVE)) {
     if (m_pMgr->m_pLastOutput != Parent()) {
       //Context changed. Flush to disk the old context + text written in it...
       m_pMgr->WriteTrainFileFull(m_pMgr->m_pInterface);
@@ -578,7 +578,7 @@ SymbolProb CAlphabetManager::CSymbolNode::GetSymbolProb(int iNormalization) cons
 
 void CAlphabetManager::CSymbolNode::Undo() {
   DASHER_ASSERT(GetFlag(NF_SEEN));
-  if (m_pMgr->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE)) {
+  if (m_pMgr->GetBoolParameter(BP_LM_ADAPTIVE)) {
     if (m_pMgr->m_pLastOutput == this) {
       //Erase from training buffer, and move lastOutput backwards,
       // iff this node was actually written (i.e. not rebuilt _from_ context!)
@@ -629,7 +629,7 @@ void CAlphabetManager::CAlphBase::RebuildForwardsFromAncestor(CAlphNode *pNewNod
 // For want of a better solution, game mode exemption explicit in this function
 void CAlphabetManager::CSymbolNode::SetFlag(int iFlag, bool bValue) {
   if ((iFlag & NF_COMMITTED) && bValue && !GetFlag(NF_COMMITTED | NF_GAME)
-      && m_pMgr->m_pInterface->GetBoolParameter(BP_LM_ADAPTIVE)) {
+      && m_pMgr->GetBoolParameter(BP_LM_ADAPTIVE)) {
     //try to commit...if we have parent (else rebuilding (backwards) => don't)
     if (Parent()) {
       if (Parent()->mgr() != mgr()) return; //do not set flag
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index be98812..59b7024 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -27,7 +27,7 @@
 #include "Trainer.h"
 #include "Alphabet/AlphInfo.h"
 #include "SettingsStore.h"
-#include "EventHandler.h"
+#include "Observable.h"
 
 class CNodeCreationManager;
 struct SGroupInfo;
@@ -44,13 +44,13 @@ namespace Dasher {
   /// to the appropriate alphabet file, with sizes given by the
   /// language model.
   ///
-  class CAlphabetManager : public CNodeManager {
+  class CAlphabetManager : public CNodeManager, protected CSettingsUser {
   public:
     ///Create a new AlphabetManager. Note, not usable until CreateLanguageModel() called.
-    CAlphabetManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet);
+    CAlphabetManager(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet);
     ///Creates the LM, and stores in m_pLanguageModel. Must be called after construction,
     /// before the AlphMgr is used. Default implementation switches on LP_LANGUAGE_MODEL_ID.
-    virtual void CreateLanguageModel(CEventHandler *pEventHandler, CSettingsStore *pSets);
+    virtual void CreateLanguageModel();
 
     virtual void MakeLabels(CDasherScreen *pScreen);
     ///Gets a new trainer to train this LM. Caller is responsible for deallocating the
@@ -240,7 +240,7 @@ namespace Dasher {
     CNodeCreationManager *m_pNCManager;
     const CAlphInfo *m_pAlphabet;
     const CAlphabetMap *m_pAlphabetMap;
-
+    
   private:
     ///Wraps m_pLanguageModel->GetProbs to implement nonuniformity
     /// (also leaves space for NCManager::AddExtras to add control node)
diff --git a/Src/DasherCore/AlternatingDirectMode.cpp b/Src/DasherCore/AlternatingDirectMode.cpp
index b736763..68ae11c 100644
--- a/Src/DasherCore/AlternatingDirectMode.cpp
+++ b/Src/DasherCore/AlternatingDirectMode.cpp
@@ -5,9 +5,9 @@
 
 #include "../Common/Common.h"
 
-
 #include "AlternatingDirectMode.h"
 #include "DasherScreen.h"
+#include "DasherInterfaceBase.h"
 #include <valarray>
 #include <iostream>
 
@@ -30,8 +30,8 @@ static SModuleSettings sSettings[] = {
   {BP_GLOBAL_KEYBOARD, T_BOOL, -1, -1, -1, -1, _("Global keyboard grab")}
 };
 
-CAlternatingDirectMode::CAlternatingDirectMode(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface)
-  : CDasherButtons(pEventHandler, pSettingsStore, pInterface, false/*menu*/, 12, _("Alternating Direct Mode")) {}
+CAlternatingDirectMode::CAlternatingDirectMode(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+  : CDasherButtons(pCreator, pInterface, false/*menu*/, 12, _("Alternating Direct Mode")) {}
 
 void CAlternatingDirectMode::SetupBoxes()
 {
diff --git a/Src/DasherCore/AlternatingDirectMode.h b/Src/DasherCore/AlternatingDirectMode.h
index ef0ddfc..68ef25b 100644
--- a/Src/DasherCore/AlternatingDirectMode.h
+++ b/Src/DasherCore/AlternatingDirectMode.h
@@ -10,7 +10,6 @@
 #include <iostream>
 #include <fstream>
 #include <algorithm>
-#include "DasherComponent.h"
 #include "Event.h"
 #include "DasherButtons.h"
 
@@ -25,7 +24,7 @@ namespace Dasher {
   class CAlternatingDirectMode : public CDasherButtons
 {
  public:
-  CAlternatingDirectMode(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface);
+  CAlternatingDirectMode(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface);
 
   bool DecorateView(CDasherView *pView, CDasherInput *pInput);
 
diff --git a/Src/DasherCore/AutoSpeedControl.cpp b/Src/DasherCore/AutoSpeedControl.cpp
index 10a8be3..fd7c146 100644
--- a/Src/DasherCore/AutoSpeedControl.cpp
+++ b/Src/DasherCore/AutoSpeedControl.cpp
@@ -25,8 +25,8 @@ double round(double dVal) {
 
 using namespace Dasher;
 
-CAutoSpeedControl::CAutoSpeedControl(CMessageDisplay *pMsgs, Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore)
-  : CDasherComponent(pEventHandler, pSettingsStore), m_pMsgs(pMsgs) {
+CAutoSpeedControl::CAutoSpeedControl(CSettingsUser *pCreateFrom, CMessageDisplay *pMsgs)
+  : CSettingsUser(pCreateFrom), m_pMsgs(pMsgs) {
   //scale #samples by #samples = m_dSamplesScale / (current bitrate) + m_dSampleOffset
   m_dSampleScale = 1.5;
   m_dSampleOffset = 1.3;
diff --git a/Src/DasherCore/AutoSpeedControl.h b/Src/DasherCore/AutoSpeedControl.h
index 74dddfc..4956ad1 100644
--- a/Src/DasherCore/AutoSpeedControl.h
+++ b/Src/DasherCore/AutoSpeedControl.h
@@ -1,18 +1,19 @@
 #ifndef __AUTO_SPEED_CONTROL_H__
 #define __AUTO_SPEED_CONTROL_H__
 
-#include "DasherComponent.h"
 #include "DasherTypes.h"
 #include "DasherView.h"
 #include "Messages.h"
+#include "SettingsStore.h"
+
 #include <deque>
 
 /// \defgroup AutoSpeed Auto speed control
 /// @{
 namespace Dasher {
-class CAutoSpeedControl : public Dasher::CDasherComponent {
+  class CAutoSpeedControl : private CSettingsUser {
  public:
-  CAutoSpeedControl(CMessageDisplay *pMsgs, Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore);
+  CAutoSpeedControl(CSettingsUser *pCreateFrom, CMessageDisplay *pMsgs);
   
   ///
   /// AUTO-SPEED-CONTROL
diff --git a/Src/DasherCore/BasicLog.cpp b/Src/DasherCore/BasicLog.cpp
index 96284ba..6bb4677 100644
--- a/Src/DasherCore/BasicLog.cpp
+++ b/Src/DasherCore/BasicLog.cpp
@@ -1,5 +1,7 @@
 #include "BasicLog.h"
 
+#include "DasherInterfaceBase.h"
+
 #include <cmath>
 #include <fstream>
 #include <iostream>
@@ -10,7 +12,9 @@
 #include <sys/time.h>
 #endif
 
-CBasicLog::CBasicLog(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore) : CUserLogBase(pEventHandler, pSettingsStore) {
+using namespace Dasher;
+
+CBasicLog::CBasicLog(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pIntf) : CUserLogBase(pCreateFrom, pIntf) {
   m_iSymbolCount = 0;
   m_bStarted = false;
 }
diff --git a/Src/DasherCore/BasicLog.h b/Src/DasherCore/BasicLog.h
index 6b42ddc..49e4aec 100644
--- a/Src/DasherCore/BasicLog.h
+++ b/Src/DasherCore/BasicLog.h
@@ -7,7 +7,7 @@
 /// @{
 class CBasicLog : public CUserLogBase {
  public:
-  CBasicLog(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore);
+  CBasicLog(Dasher::CSettingsUser *pCreateFrom, Dasher::CDasherInterfaceBase *pIntf);
   ~CBasicLog();
 
   virtual void AddParam(const string& strName, const string& strValue, int iOptionMask = 0) {};
diff --git a/Src/DasherCore/ButtonMode.cpp b/Src/DasherCore/ButtonMode.cpp
index 39e5c9a..5e8134a 100644
--- a/Src/DasherCore/ButtonMode.cpp
+++ b/Src/DasherCore/ButtonMode.cpp
@@ -5,9 +5,9 @@
 
 #include "../Common/Common.h"
 
-
 #include "ButtonMode.h"
 #include "DasherScreen.h"
+#include "DasherInterfaceBase.h"
 #include <valarray>
 #include <iostream>
 
@@ -41,8 +41,8 @@ static SModuleSettings sSettings[] = {
 
 // FIX iStyle == 0
 
-CButtonMode::CButtonMode(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, bool bMenu, int iID, const char *szName)
-: CDasherButtons(pEventHandler, pSettingsStore, pInterface, bMenu, iID, szName) {}
+CButtonMode::CButtonMode(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, bool bMenu, int iID, const char *szName)
+: CDasherButtons(pCreator, pInterface, bMenu, iID, szName) {}
 
 void CButtonMode::SetupBoxes()
 {
@@ -214,18 +214,14 @@ void CButtonMode::DirectKeyDown(int iTime, int iId, CDasherView *pView, CDasherM
  if (iId!=100) m_iLastTime = iTime;
 }
 
-void CButtonMode::HandleEvent(Dasher::CEvent * pEvent) {
-  if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-
-    switch (pEvt->m_iParameter) {
-    case LP_B:
-    case LP_R:
-      // Delibarate fallthrough
-      delete[] m_pBoxes;
-      SetupBoxes();
-      break;
-    }
+void CButtonMode::HandleEvent(int iParameter) {
+  switch (iParameter) {
+  case LP_B:
+  case LP_R:
+    // Delibarate fallthrough
+    delete[] m_pBoxes;
+    SetupBoxes();
+    break;
   }
 }
 
diff --git a/Src/DasherCore/ButtonMode.h b/Src/DasherCore/ButtonMode.h
index 062a5c2..8126207 100644
--- a/Src/DasherCore/ButtonMode.h
+++ b/Src/DasherCore/ButtonMode.h
@@ -10,7 +10,6 @@
 #include <iostream>
 #include <fstream>
 #include <algorithm>
-#include "DasherComponent.h"
 #include "Event.h"
 #include "DasherButtons.h"
 
@@ -22,9 +21,9 @@ namespace Dasher {
 class CButtonMode : public CDasherButtons
 {
  public:
-  CButtonMode(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface, bool bMenu, int iID, const char *szName);
+  CButtonMode(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, bool bMenu, int iID, const char *szName);
 
-  virtual void HandleEvent(Dasher::CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
   bool Timer(unsigned long Time, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CExpansionPolicy **pol);
   bool DecorateView(CDasherView *pView, CDasherInput *pInput);
 
diff --git a/Src/DasherCore/ButtonMultiPress.cpp b/Src/DasherCore/ButtonMultiPress.cpp
index 8b70ea5..ce597d4 100644
--- a/Src/DasherCore/ButtonMultiPress.cpp
+++ b/Src/DasherCore/ButtonMultiPress.cpp
@@ -23,8 +23,8 @@
 
 using namespace Dasher;
 
-CButtonMultiPress::CButtonMultiPress(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
-  : CDynamicFilter(pEventHandler, pSettingsStore, pInterface, iID, szName) {
+CButtonMultiPress::CButtonMultiPress(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
+  : CDynamicFilter(pCreator, pInterface, iID, szName) {
 }
 
 void CButtonMultiPress::KeyDown(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CUserLogBase *pUserLog) {
diff --git a/Src/DasherCore/ButtonMultiPress.h b/Src/DasherCore/ButtonMultiPress.h
index cd936e4..9c2cb4d 100644
--- a/Src/DasherCore/ButtonMultiPress.h
+++ b/Src/DasherCore/ButtonMultiPress.h
@@ -31,7 +31,7 @@ namespace Dasher {
 /// to the number of presses, for subclasses to handle/decide how to respond.)
 class CButtonMultiPress : public CDynamicFilter {
  public:
-  CButtonMultiPress(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
+  CButtonMultiPress(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
 
   virtual void KeyDown(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CUserLogBase *pUserLog);
 
diff --git a/Src/DasherCore/CircleStartHandler.cpp b/Src/DasherCore/CircleStartHandler.cpp
index 3857e67..7be59ce 100644
--- a/Src/DasherCore/CircleStartHandler.cpp
+++ b/Src/DasherCore/CircleStartHandler.cpp
@@ -26,12 +26,20 @@
 
 using namespace Dasher;
 
-CCircleStartHandler::CCircleStartHandler(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface)
-: CStartHandler(pEventHandler, pSettingsStore, pInterface), m_iEnterTime(std::numeric_limits<long>::max()), m_iScreenRadius(-1) {
+CCircleStartHandler::CCircleStartHandler(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+: CStartHandler(pInterface), CSettingsUserObserver(pCreator), m_iEnterTime(std::numeric_limits<long>::max()), m_iScreenRadius(-1), m_pView(NULL) {
+}
+
+CCircleStartHandler::~CCircleStartHandler() {
+  if (m_pView) m_pView->Unregister(this);
 }
 
 void CCircleStartHandler::ComputeScreenLoc(CDasherView *pView) {
-  if (m_iScreenRadius!=-1) return;
+  if (pView != m_pView) {
+    if (m_pView) m_pView->Unregister(this);
+    (m_pView=pView)->Register(this);
+  } else if (m_iScreenRadius!=-1) return;
+  
   pView->Dasher2Screen(GetLongParameter(LP_OX),GetLongParameter(LP_OY),m_screenCircleCenter.x,m_screenCircleCenter.y);
   //compute radius against orientation. It'd be simpler to use
   // Math.min(screen width, screen height) * LP_CIRCLE_PERCENT / 100
@@ -98,11 +106,8 @@ void CCircleStartHandler::Timer(int iTime, dasherint mouseX, dasherint mouseY,CD
   }
 }
 
-void CCircleStartHandler::HandleEvent(Dasher::CEvent * pEvent) {
-  if(pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-
-    switch (pEvt->m_iParameter) {
+void CCircleStartHandler::HandleEvent(int iParameter) {
+  switch (iParameter) {
     case LP_REAL_ORIENTATION:
     case LP_CIRCLE_PERCENT:
       //recompute geometry.
@@ -116,9 +121,11 @@ void CCircleStartHandler::HandleEvent(Dasher::CEvent * pEvent) {
       // the circle before the start handler does anything. The following ensures this.
       m_bInCircle = true;
       break;
-    }
-  } else if (pEvent->m_iEventType == EV_SCREEN_GEOM) {
-    //need to recompute geometry (in next DecorateView or Timer)
-    m_iScreenRadius = -1;
   }
 }
+
+void CCircleStartHandler::HandleEvent(CDasherView *pNewView) {
+  //need to recompute geometry...
+  m_iScreenRadius = -1; //even if it's the same view
+  ComputeScreenLoc(pNewView);
+}
diff --git a/Src/DasherCore/CircleStartHandler.h b/Src/DasherCore/CircleStartHandler.h
index 10174ea..32ab086 100644
--- a/Src/DasherCore/CircleStartHandler.h
+++ b/Src/DasherCore/CircleStartHandler.h
@@ -5,13 +5,14 @@
 /// \ingroup Start
 /// @{
 namespace Dasher {
-class CCircleStartHandler : public CStartHandler {
+class CCircleStartHandler : public CStartHandler, public CSettingsUserObserver, public Observer<CDasherView *> {
 public:
-  CCircleStartHandler(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface);
-
+  CCircleStartHandler(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface);
+  ~CCircleStartHandler();
   virtual bool DecorateView(CDasherView *pView);
   virtual void Timer(int iTime, dasherint iX, dasherint iY, CDasherView *pView);
-  virtual void HandleEvent(Dasher::CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
+  virtual void HandleEvent(CDasherView *pView);
 
 protected:
   ///Time (as unix timestamp) when user entered circle; max() => already acted upon
@@ -22,6 +23,7 @@ protected:
   int m_iScreenRadius;
   ///Center of screen circle (needs recomputing if radius does)
   CDasherScreen::point m_screenCircleCenter;
+  CDasherView *m_pView;
   virtual void ComputeScreenLoc(CDasherView *pView);
 };
 }
diff --git a/Src/DasherCore/ClickFilter.cpp b/Src/DasherCore/ClickFilter.cpp
index 3c69cb9..7e10905 100644
--- a/Src/DasherCore/ClickFilter.cpp
+++ b/Src/DasherCore/ClickFilter.cpp
@@ -24,7 +24,7 @@ bool CClickFilter::DecorateView(CDasherView *pView, CDasherInput *pInput) {
   if (GetBoolParameter(BP_DRAW_MOUSE_LINE)) {
     myint mouseX, mouseY;
     pInput->GetDasherCoords(mouseX, mouseY, pView);
-    AdjustZoomCoords(mouseX,mouseY,pView);
+    AdjustZoomCoords(mouseX, mouseY, pView);
     if (m_iLastX != mouseX || m_iLastY != mouseY) {
       bChanged = true;
       m_iLastX = mouseX; m_iLastY = mouseY;
@@ -58,19 +58,22 @@ bool CClickFilter::DecorateView(CDasherView *pView, CDasherInput *pInput) {
   return bChanged;
 }
 
-void CClickFilter::AdjustZoomCoords(myint &iDasherX, myint &iDasherY, CDasherView *pView) {
-  const myint ox(pView->GetLongParameter(LP_OX)), safety(pView->GetLongParameter(LP_S));
+CZoomAdjuster::CZoomAdjuster(CSettingsUser *pCreateFrom) : CSettingsUser(pCreateFrom) {
+}
+
+void CZoomAdjuster::AdjustZoomCoords(myint &iDasherX, myint &iDasherY, CDasherView *pView) {
+  const myint ox(GetLongParameter(LP_OX)), safety(GetLongParameter(LP_S));
   //safety param. Used to be just added onto DasherX,
   // but comments suggested should be interpreted as a fraction. Hence...
   myint iNewDasherX = (iDasherX*1024 + ox*safety) / (1024+safety);
 
   //max zoom parameter...
-  iNewDasherX = std::max(ox/pView->GetLongParameter(LP_MAXZOOM),iNewDasherX);
+  iNewDasherX = std::max(ox/GetLongParameter(LP_MAXZOOM),iNewDasherX);
   //force x>=2 (what's wrong with x==1?)
   if (iNewDasherX<2) iNewDasherX=2;
   if (iNewDasherX != iDasherX) {
     //compute new dasher y to keep centre of expansion in same place...
-    const myint oy(pView->GetLongParameter(LP_OY));
+    const myint oy(GetLongParameter(LP_OY));
     myint iNewDasherY = oy + ((ox-iNewDasherX) * (iDasherY-oy))/(ox-iDasherX);
     iDasherX = iNewDasherX; iDasherY = iNewDasherY;
   }
diff --git a/Src/DasherCore/ClickFilter.h b/Src/DasherCore/ClickFilter.h
index 36dedd7..3a1716d 100644
--- a/Src/DasherCore/ClickFilter.h
+++ b/Src/DasherCore/ClickFilter.h
@@ -6,17 +6,26 @@
 /// \ingroup InputFilter
 /// @{
 namespace Dasher {
-class CClickFilter : public CInputFilter {
+  ///Utility class for transforming co-ordinates of a mouse click to zoom target
+  class CZoomAdjuster : protected CSettingsUser {
+  public:
+    //Everything public so we can use composition as well as inheritance
+    CZoomAdjuster(CSettingsUser *pCreator);
+    /// Adjust co-ordinates of mouse click into coordinates for zoom target.
+    /// Adds a safety margin according to LP_S, checks we don't exceed the
+    /// zoom factor given by LP_MAXZOOM, and ensures x>=2.
+    void AdjustZoomCoords(myint &iDasherX, myint &iDasherY, CDasherView *comp);
+  };
+  
+class CClickFilter : public CInputFilter, private CZoomAdjuster {
  public:
-  CClickFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface)
-    : CInputFilter(pEventHandler, pSettingsStore, pInterface, 7, _("Click Mode")) { };
+  CClickFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+    : CInputFilter(pInterface, 7, _("Click Mode")), CZoomAdjuster(pCreator) { };
 
   virtual bool DecorateView(CDasherView *pView, CDasherInput *pInput);
   virtual bool Timer(unsigned long Time, CDasherView *pView, CDasherInput *pInput, CDasherModel *pDasherModel, CExpansionPolicy **pol);
   virtual void KeyDown(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CUserLogBase *pUserLog, bool bPos, int iX, int iY);
   virtual bool GetSettings(SModuleSettings **pSettings, int *iCount);
-
-  static void AdjustZoomCoords(myint &iDasherX, myint &iDasherY, CDasherView *comp);
   
  private:
   //for mouse lines
diff --git a/Src/DasherCore/CompassMode.cpp b/Src/DasherCore/CompassMode.cpp
index 78617ab..5ac50d3 100644
--- a/Src/DasherCore/CompassMode.cpp
+++ b/Src/DasherCore/CompassMode.cpp
@@ -5,9 +5,9 @@
 
 #include "../Common/Common.h"
 
-
 #include "CompassMode.h"
 #include "DasherScreen.h"
+#include "DasherInterfaceBase.h"
 #include <valarray>
 #include <iostream>
 
@@ -34,8 +34,8 @@ static SModuleSettings sSettings[] = {
 
 // FIX iStyle == 2
 
-CCompassMode::CCompassMode(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface)
-  : CDasherButtons(pEventHandler, pSettingsStore, pInterface, false /*bMenu*/, 13, _("Compass Mode")) {}
+CCompassMode::CCompassMode(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+  : CDasherButtons(pCreator, pInterface, false /*bMenu*/, 13, _("Compass Mode")) {}
 
 void CCompassMode::SetupBoxes()
 {
@@ -124,13 +124,10 @@ bool CCompassMode::DecorateView(CDasherView *pView, CDasherInput *pInput) {
   return bRV;
 }
 
-void CCompassMode::HandleEvent(Dasher::CEvent * pEvent) {
-  if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-    if (pEvt->m_iParameter == LP_RIGHTZOOM) {
-      delete[] m_pBoxes;
-      SetupBoxes();
-    }
+void CCompassMode::HandleEvent(int iParameter) {
+  if (iParameter == LP_RIGHTZOOM) {
+    delete[] m_pBoxes;
+    SetupBoxes();
   }
 }
 
diff --git a/Src/DasherCore/CompassMode.h b/Src/DasherCore/CompassMode.h
index 0e949b9..ed4db09 100644
--- a/Src/DasherCore/CompassMode.h
+++ b/Src/DasherCore/CompassMode.h
@@ -10,7 +10,6 @@
 #include <iostream>
 #include <fstream>
 #include <algorithm>
-#include "DasherComponent.h"
 #include "Event.h"
 #include "DasherButtons.h"
 
@@ -22,9 +21,9 @@ namespace Dasher {
 class CCompassMode : public CDasherButtons
 {
  public:
-  CCompassMode(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface);
+  CCompassMode(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface);
 
-  virtual void HandleEvent(Dasher::CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
 
   bool DecorateView(CDasherView *pView, CDasherInput *pInput);
 
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index 3ac66f4..c59d9c4 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -36,8 +36,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CControlBase::CControlBase( CNodeCreationManager *pNCManager)
-  : m_pNCManager(pNCManager), m_pRoot(NULL) {
+CControlBase::CControlBase(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager)
+  : CSettingsUser(pCreateFrom), m_pInterface(pInterface), m_pNCManager(pNCManager), m_pRoot(NULL) {
 }
 
 CControlBase::NodeTemplate *CControlBase::GetRootTemplate() {
@@ -96,7 +96,7 @@ void CControlBase::CContNode::PopulateChildren() {
   CDasherNode *pNewNode;
 
   const unsigned int iNChildren( m_pTemplate->successors.size() );
-  const unsigned int iNorm(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+  const unsigned int iNorm(m_pMgr->GetLongParameter(LP_NORMALIZATION));
   unsigned int iLbnd(0), iIdx(0);
 
   for (vector<NodeTemplate *>::iterator it = m_pTemplate->successors.begin(); it!=m_pTemplate->successors.end(); it++) {
@@ -127,13 +127,13 @@ void CControlBase::CContNode::Output() {
 
 void CControlBase::CContNode::Enter() {
   // Slow down to half the speed we were at. This also disables auto-speed-control.
-  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 50);
+  m_pMgr->SetLongParameter(LP_BOOSTFACTOR, 50);
 }
 
 
 void CControlBase::CContNode::Leave() {
   // Now speed back up, by doubling the speed we were at in control mode
-  m_pMgr->m_pNCManager->SetLongParameter(LP_BOOSTFACTOR, 100);
+  m_pMgr->SetLongParameter(LP_BOOSTFACTOR, 100);
 }
 
 const vector<CControlBase::NodeTemplate *> &CControlParser::parsedNodes() {
@@ -242,8 +242,8 @@ bool CControlParser::LoadFile(CMessageDisplay *pMsgs, const string &strFileName)
   return true;
 }
 
-CControlManager::CControlManager(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CNodeCreationManager *pNCManager, CDasherInterfaceBase *pInterface)
-: CDasherComponent(pEventHandler, pSettingsStore), CControlBase(pNCManager), m_pInterface(pInterface), m_pSpeech(NULL), m_pCopy(NULL) {
+CControlManager::CControlManager(CSettingsUser *pCreateFrom, CNodeCreationManager *pNCManager, CDasherInterfaceBase *pInterface)
+: CControlBase(pCreateFrom, pInterface, pNCManager), CSettingsObserver(pCreateFrom), m_pSpeech(NULL), m_pCopy(NULL) {
   //TODO, used to be able to change label+colour of root/pause/stop from controllabels.xml
   // (or, get the root node title "control" from the alphabet!)
   SetRootTemplate(new NodeTemplate("Control",8)); //default NodeTemplate does nothing
@@ -257,8 +257,8 @@ CControlManager::CControlManager(CEventHandler *pEventHandler, CSettingsStore *p
   m_pStop->successors.push_back(GetRootTemplate());
 
   //TODO, have a parameter to try first, and if that fails:
-  if(!LoadFile(m_pInterface, m_pNCManager->GetStringParameter(SP_USER_LOC) + "control.xml")) {
-    LoadFile(m_pInterface, m_pNCManager->GetStringParameter(SP_SYSTEM_LOC)+"control.xml");
+  if(!LoadFile(m_pInterface, GetStringParameter(SP_USER_LOC) + "control.xml")) {
+    LoadFile(m_pInterface, GetStringParameter(SP_SYSTEM_LOC)+"control.xml");
     //if that fails, we'll have no editing functions. Fine -
     // doesn't seem vital enough to hardcode a fallback as well!
   }
@@ -266,10 +266,10 @@ CControlManager::CControlManager(CEventHandler *pEventHandler, CSettingsStore *p
   updateActions();
 }
 
-CControlManager::Pause::Pause(const string &strLabel, int iColour) : NodeTemplate(strLabel,iColour) {
+CControlBase::Pause::Pause(const string &strLabel, int iColour) : NodeTemplate(strLabel,iColour) {
 }
-void CControlManager::Pause::happen(CContNode *pNode) {
-  static_cast<CControlManager *>(pNode->mgr())->m_pNCManager->SetBoolParameter(BP_DASHER_PAUSED,true);
+void CControlBase::Pause::happen(CContNode *pNode) {
+  pNode->mgr()->SetBoolParameter(BP_DASHER_PAUSED,true);
 }
 
 CControlBase::NodeTemplate *CControlManager::parseOther(const XML_Char *name, const XML_Char **atts) {
@@ -366,18 +366,16 @@ public:
   }
 };
 
-void CControlManager::HandleEvent(CEvent *pEvent) {
-  if (pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    switch (static_cast<CParameterNotificationEvent *>(pEvent)->m_iParameter) {
-      case BP_CONTROL_MODE_HAS_HALT:
-      case BP_CONTROL_MODE_HAS_EDIT:
-      case BP_CONTROL_MODE_HAS_SPEECH:
-      case BP_CONTROL_MODE_HAS_COPY:
-      case BP_COPY_ALL_ON_STOP:
-      case BP_SPEAK_ALL_ON_STOP:
-      case SP_INPUT_FILTER:
-        updateActions();
-    }
+void CControlManager::HandleEvent(int iParameter) {
+  switch (iParameter) {
+    case BP_CONTROL_MODE_HAS_HALT:
+    case BP_CONTROL_MODE_HAS_EDIT:
+    case BP_CONTROL_MODE_HAS_SPEECH:
+    case BP_CONTROL_MODE_HAS_COPY:
+    case BP_COPY_ALL_ON_STOP:
+    case BP_SPEAK_ALL_ON_STOP:
+    case SP_INPUT_FILTER:
+      updateActions();
   }
 }
 
@@ -392,30 +390,30 @@ void CControlManager::updateActions() {
   //stop does something, and we're told to add a node for it
   // (either a dynamic filter where the user can't use the normal stop mechanism precisely,
   //  or a static filter but a 'stop' action is easier than using speak->all / copy->all then pause)
-  if (m_pInterface->hasStopTriggers() && m_pInterface->GetBoolParameter(BP_CONTROL_MODE_HAS_HALT))
+  if (m_pInterface->hasStopTriggers() && GetBoolParameter(BP_CONTROL_MODE_HAS_HALT))
     vRootSuccessors.push_back(m_pStop);
   if (it!=vOldRootSuccessors.end() && *it == m_pStop) it++;
 
   //filter is pauseable, and either 'stop' would do something (so pause is different),
   // or we're told to have a stop node but it would be indistinguishable from pause (=>have pause)
   CInputFilter *pInput(m_pInterface->GetActiveInputMethod());
-  if (pInput->supportsPause() && (m_pInterface->hasStopTriggers() || m_pInterface->GetBoolParameter(BP_CONTROL_MODE_HAS_HALT)))
+  if (pInput->supportsPause() && (m_pInterface->hasStopTriggers() || GetBoolParameter(BP_CONTROL_MODE_HAS_HALT)))
     vRootSuccessors.push_back(m_pPause);
   if (it!=vOldRootSuccessors.end() && *it == m_pPause) it++;
 
-  if (m_pInterface->GetBoolParameter(BP_CONTROL_MODE_HAS_SPEECH) && m_pInterface->SupportsSpeech()) {
+  if (GetBoolParameter(BP_CONTROL_MODE_HAS_SPEECH) && m_pInterface->SupportsSpeech()) {
     if (!m_pSpeech) m_pSpeech = new SpeechHeader(m_pInterface, GetRootTemplate());
     vRootSuccessors.push_back(m_pSpeech);
   }
   if (it!=vOldRootSuccessors.end() && *it == m_pSpeech) it++;
 
-  if (m_pInterface->GetBoolParameter(BP_CONTROL_MODE_HAS_COPY) && m_pInterface->SupportsClipboard()) {
+  if (GetBoolParameter(BP_CONTROL_MODE_HAS_COPY) && m_pInterface->SupportsClipboard()) {
     if (!m_pCopy) m_pCopy = new CopyHeader(m_pInterface, GetRootTemplate());
     vRootSuccessors.push_back(m_pCopy);
   }
   if (it!=vOldRootSuccessors.end() && *it == m_pCopy) it++;
 
-  if (m_pInterface->GetBoolParameter(BP_CONTROL_MODE_HAS_EDIT)) {
+  if (GetBoolParameter(BP_CONTROL_MODE_HAS_EDIT)) {
     for (vector<NodeTemplate *>::const_iterator it2=parsedNodes().begin(); it2!=parsedNodes().end(); it2++)
       vRootSuccessors.push_back(*it2);
   }
diff --git a/Src/DasherCore/ControlManager.h b/Src/DasherCore/ControlManager.h
index 793784e..37c9beb 100644
--- a/Src/DasherCore/ControlManager.h
+++ b/Src/DasherCore/ControlManager.h
@@ -52,7 +52,7 @@ namespace Dasher {
 
   /// A node manager which deals with control nodes.
   ///
-  class CControlBase : public CNodeManager {
+  class CControlBase : public CNodeManager, protected CSettingsUser {
   public:
 
     class NodeTemplate;
@@ -96,6 +96,12 @@ namespace Dasher {
       CDasherScreen::Label *m_pLabel;
     };
 
+    class Pause : public NodeTemplate {
+    public:
+      Pause(const std::string &strLabel, int iColour);
+      void happen(CContNode *pNode);
+    };
+
     template <typename T> class MethodTemplate : public NodeTemplate {
     public:
       ///A "Method" is pointer to a function "void X()", that is a member of a T...
@@ -113,7 +119,7 @@ namespace Dasher {
 
     NodeTemplate *GetRootTemplate();
 
-    CControlBase(CNodeCreationManager *pNCManager);
+    CControlBase(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager);
 
     ///Make this manager ready to make nodes renderable on the screen by preallocating labels
     virtual void MakeLabels(CDasherScreen *pScreen);
@@ -130,6 +136,7 @@ namespace Dasher {
     ///Note, may only be called once, and with a non-null pRoot, or will throw an error message.
     void SetRootTemplate(NodeTemplate *pRoot);
 
+    CDasherInterfaceBase *m_pInterface;
     CNodeCreationManager *m_pNCManager;
 
   private:
@@ -173,15 +180,10 @@ namespace Dasher {
   ///subclass which we actually construct! Parses editing node definitions from a file,
   /// then adds Pause and/or Stop, Speak, and Copy (to clipboard), all as children
   /// of the "root" control node.
-  class CControlManager : public CDasherComponent, public CControlBase, public CControlParser {
+  class CControlManager : public CSettingsObserver, public CControlBase, public CControlParser {
   public:
-    class Pause : public NodeTemplate {
-    public:
-      Pause(const std::string &strLabel, int iColour);
-      void happen(CContNode *pNode);
-    };
-    CControlManager(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CNodeCreationManager *pNCManager, CDasherInterfaceBase *pInterface);
-    void HandleEvent(CEvent *pEvent);
+    CControlManager(CSettingsUser *pCreateFrom, CNodeCreationManager *pNCManager, CDasherInterfaceBase *pInterface);
+    void HandleEvent(int iParameter);
 
     typedef enum {
       EDIT_CHAR, EDIT_WORD, EDIT_LINE, EDIT_FILE
@@ -204,7 +206,6 @@ namespace Dasher {
 
   private:
     NodeTemplate *m_pPause, *m_pStop;
-    CDasherInterfaceBase *m_pInterface;
     ///group headers, with three children each (all/new/repeat)
     NodeTemplate *m_pSpeech, *m_pCopy;
   };
diff --git a/Src/DasherCore/ConversionHelper.cpp b/Src/DasherCore/ConversionHelper.cpp
index a391d75..7f7d4f5 100644
--- a/Src/DasherCore/ConversionHelper.cpp
+++ b/Src/DasherCore/ConversionHelper.cpp
@@ -24,9 +24,10 @@
 
 #include "ConversionHelper.h"
 #include "Event.h"
-#include "EventHandler.h"
+#include "Observable.h"
 #include "NodeCreationManager.h"
 #include "DasherNode.h"
+#include "DasherInterfaceBase.h"
 
 #include <iostream>
 #include <cstring>
@@ -40,8 +41,8 @@
 using namespace Dasher;
 using namespace std;
 
-CConversionHelper::CConversionHelper(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, CLanguageModel *pLanguageModel) :
-  CConversionManager(pInterface, pNCManager, pAlphabet), m_pLanguageModel(pLanguageModel) {
+CConversionHelper::CConversionHelper(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, CLanguageModel *pLanguageModel) :
+  CConversionManager(pCreateFrom, pInterface, pNCManager, pAlphabet), m_pLanguageModel(pLanguageModel) {
 	  colourStore[0][0]=66;//light blue
 	  colourStore[0][1]=64;//very light green
 	  colourStore[0][2]=62;//light yellow
@@ -75,7 +76,7 @@ CConversionManager::CConvNode *CConversionHelper::GetRoot(CDasherNode *pParent,
 
 void CConversionHelper::AssignChildSizes(const std::vector<SCENode *> &nodes, CLanguageModel::Context context) {
 
-  AssignSizes(nodes, context, m_pNCManager->GetLongParameter(LP_NORMALIZATION), m_pNCManager->GetLongParameter(LP_UNIFORM));
+  AssignSizes(nodes, context, GetLongParameter(LP_NORMALIZATION), GetLongParameter(LP_UNIFORM));
 
 }
 
@@ -112,7 +113,7 @@ void CConversionHelper::CConvHNode::PopulateChildren() {
       DASHER_ASSERT(pCurrentSCEChild != NULL);
       unsigned int iLbnd(iCum);
       unsigned int iHbnd(iCum + pCurrentSCEChild->NodeSize);
-		//m_pNCManager->GetLongParameter(LP_NORMALIZATION));//
+		//GetLongParameter(LP_NORMALIZATION));//
 
       iCum = iHbnd;
 
diff --git a/Src/DasherCore/ConversionHelper.h b/Src/DasherCore/ConversionHelper.h
index 65a25fe..8438240 100644
--- a/Src/DasherCore/ConversionHelper.h
+++ b/Src/DasherCore/ConversionHelper.h
@@ -42,7 +42,7 @@ namespace Dasher{
 ///
   class CConversionHelper : public CConversionManager {
   public:
-	CConversionHelper(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, CLanguageModel *pLanguageModel);
+	CConversionHelper(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, CLanguageModel *pLanguageModel);
 
 	/// Convert a given string to a lattice of candidates. Sizes for
 	/// candidates aren't assigned at this point. The input string
diff --git a/Src/DasherCore/ConversionManager.cpp b/Src/DasherCore/ConversionManager.cpp
index 4e66155..6a4aca5 100644
--- a/Src/DasherCore/ConversionManager.cpp
+++ b/Src/DasherCore/ConversionManager.cpp
@@ -24,7 +24,7 @@
 
 #include "ConversionManager.h"
 #include "Event.h"
-#include "EventHandler.h"
+#include "Observable.h"
 #include "NodeCreationManager.h"
 #include "DasherModel.h"
 #include "DasherInterfaceBase.h"
@@ -41,7 +41,7 @@
 using namespace Dasher;
 using namespace std;
 
-CConversionManager::CConversionManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet) {
+CConversionManager::CConversionManager(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet) : CSettingsUser(pCreateFrom) {
   m_pInterface = pInterface;
   m_pNCManager = pNCManager;
   m_pAlphabet = pAlphabet;
@@ -111,7 +111,7 @@ void CConversionManager::CConvNode::PopulateChildren() {
   // user should have been warned here.
   //
   unsigned int iLbnd(0);
-  unsigned int iHbnd(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
+  unsigned int iHbnd(m_pMgr->GetLongParameter(LP_NORMALIZATION));
 
   CDasherNode *pNewNode = m_pMgr->m_pNCManager->GetAlphabetManager()->GetRoot(this, iLbnd, iHbnd, false, offset() + 1);
 
diff --git a/Src/DasherCore/ConversionManager.h b/Src/DasherCore/ConversionManager.h
index 0d910ec..a32b20d 100644
--- a/Src/DasherCore/ConversionManager.h
+++ b/Src/DasherCore/ConversionManager.h
@@ -27,6 +27,7 @@
 #include "SCENode.h"
 #include "NodeManager.h"
 #include "Alphabet/AlphInfo.h"
+#include "SettingsStore.h"
 
 // TODO: Conversion manager needs to deal with offsets and contexts - Will: See Phil for an explanation.
 
@@ -59,10 +60,9 @@ namespace Dasher {
   /// aspects of conversion, and CNodeManager for details of the node
   /// management process.
   ///
-  class CConversionManager : public CNodeManager {
+  class CConversionManager : public CNodeManager, protected CSettingsUser {
   public:
-    // TODO: We shouldn't need to know about this stuff, but the code is somewhat in knots at the moment
-    CConversionManager(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet);
+    CConversionManager(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet);
 
     ///Tells us to use the specified screen to create node labels.
     /// (note we cache the screen and create labels lazily)
diff --git a/Src/DasherCore/ConvertingAlphMgr.cpp b/Src/DasherCore/ConvertingAlphMgr.cpp
index 42c95d5..4838ba5 100644
--- a/Src/DasherCore/ConvertingAlphMgr.cpp
+++ b/Src/DasherCore/ConvertingAlphMgr.cpp
@@ -12,8 +12,8 @@
 
 using namespace Dasher;
 
-CConvertingAlphMgr::CConvertingAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CConversionManager *pConvMgr, const CAlphInfo *pAlphabet)
- : CAlphabetManager(pInterface, pNCManager, pAlphabet), m_pConvMgr(pConvMgr) {
+CConvertingAlphMgr::CConvertingAlphMgr(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CConversionManager *pConvMgr, const CAlphInfo *pAlphabet)
+ : CAlphabetManager(pCreateFrom, pInterface, pNCManager, pAlphabet), m_pConvMgr(pConvMgr) {
  }
 
 void CConvertingAlphMgr::MakeLabels(CDasherScreen *pScreen) {
diff --git a/Src/DasherCore/ConvertingAlphMgr.h b/Src/DasherCore/ConvertingAlphMgr.h
index a30dcd9..e3a9a68 100644
--- a/Src/DasherCore/ConvertingAlphMgr.h
+++ b/Src/DasherCore/ConvertingAlphMgr.h
@@ -22,7 +22,7 @@ namespace Dasher {
   //TODO do we also need to override GetProbs? Existing impl will add uniformity onto the conversion root too.
   class CConvertingAlphMgr : public CAlphabetManager {
   public:
-    CConvertingAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CConversionManager *pConvMgr, const CAlphInfo *pAlphabet);
+    CConvertingAlphMgr(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, CConversionManager *pConvMgr, const CAlphInfo *pAlphabet);
     ///Override to also tell the ConversionManager that the screen has changed.
     void MakeLabels(CDasherScreen *pScreen);
     virtual ~CConvertingAlphMgr();
diff --git a/Src/DasherCore/DashIntfScreenMsgs.cpp b/Src/DasherCore/DashIntfScreenMsgs.cpp
index ae7fa84..d0bfded 100644
--- a/Src/DasherCore/DashIntfScreenMsgs.cpp
+++ b/Src/DasherCore/DashIntfScreenMsgs.cpp
@@ -2,6 +2,10 @@
 
 using namespace Dasher;
 
+CDashIntfScreenMsgs::CDashIntfScreenMsgs(CSettingsStore *pSettingsStore)
+ : CDashIntfSettings(pSettingsStore) {
+}
+
 void CDashIntfScreenMsgs::Message(const string &strText, bool bInterrupt) {
   //Just store the messages for Redraw...
   CDasherScreen::Label *lab = m_DasherScreen->MakeLabel(strText,GetLongParameter(LP_MESSAGE_FONTSIZE));
diff --git a/Src/DasherCore/DashIntfScreenMsgs.h b/Src/DasherCore/DashIntfScreenMsgs.h
index 6881a39..0a766c6 100644
--- a/Src/DasherCore/DashIntfScreenMsgs.h
+++ b/Src/DasherCore/DashIntfScreenMsgs.h
@@ -22,11 +22,19 @@
 #ifndef __DASH_INTF_SCREEN_MSGS_H__
 #define __DASH_INTF_SCREEN_MSGS_H__
 
-#include "DasherInterfaceBase.h"
+#include "DashIntfSettings.h"
 
 namespace Dasher {
-class CDashIntfScreenMsgs : public CDasherInterfaceBase {
+///Implements the MessageDisplay part of CDasherInterfaceBase by rendering messages
+/// directly onto the CDasherScreen (using MakeLabel wrapping to LP_MESSAGE_FONTSIZE).
+/// Note we subclass CDashIntfSettings as currently all platforms want to inherit from
+/// the latter; if this changes, we could declare ScreenMsgs & Settings separately and
+/// combine via multiple inheritance?? (from CSettingsUser, not DashIntfBase!)
+class CDashIntfScreenMsgs : public CDashIntfSettings {
 public:
+
+  CDashIntfScreenMsgs(CSettingsStore *pSettingsStore);
+
   /// Stores messages for Redraw to render onto the Screen on top of the view.
   /// For modal messages (bInterrupt=true), pauses Dasher, and keeps the message
   /// onscreen until the user starts moving again (via normal mechanisms);
diff --git a/Src/DasherCore/DashIntfSettings.cpp b/Src/DasherCore/DashIntfSettings.cpp
new file mode 100644
index 0000000..226ab19
--- /dev/null
+++ b/Src/DasherCore/DashIntfSettings.cpp
@@ -0,0 +1,32 @@
+#include "DashIntfSettings.h"
+
+using namespace Dasher;
+using std::string;
+
+CDashIntfSettings::CDashIntfSettings(CSettingsStore *pSettingsStore)
+ : CDasherInterfaceBase(pSettingsStore) {
+}
+
+bool CDashIntfSettings::GetBoolParameter(int iParameter) const {
+  return CDasherInterfaceBase::GetBoolParameter(iParameter);
+}
+
+long CDashIntfSettings::GetLongParameter(int iParameter) const {
+  return CDasherInterfaceBase::GetLongParameter(iParameter);
+}
+
+const string &CDashIntfSettings::GetStringParameter(int iParameter) const {
+  return CDasherInterfaceBase::GetStringParameter(iParameter);
+}
+
+void CDashIntfSettings::SetBoolParameter(int iParameter, bool bValue) {
+  CDasherInterfaceBase::SetBoolParameter(iParameter, bValue);
+}
+
+void CDashIntfSettings::SetLongParameter(int iParameter, long lValue) {
+  CDasherInterfaceBase::SetLongParameter(iParameter, lValue);
+}
+
+void CDashIntfSettings::SetStringParameter(int iParameter, const string &strValue) {
+  CDasherInterfaceBase::SetStringParameter(iParameter, strValue);
+}
diff --git a/Src/DasherCore/DashIntfSettings.h b/Src/DasherCore/DashIntfSettings.h
new file mode 100644
index 0000000..a9e43b2
--- /dev/null
+++ b/Src/DasherCore/DashIntfSettings.h
@@ -0,0 +1,52 @@
+// DashIntfSettings.h
+//
+// Created 2011 by Alan Lawrence
+// Copyright (c) 2011 The Dasher Team
+//
+// This file is part of Dasher.
+//
+// Dasher 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.
+//
+// Dasher 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 Dasher; if not, write to the Free Software 
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+#ifndef __DASH_INTF_SETTINGS_H__
+#define __DASH_INTF_SETTINGS_H__
+
+#include "DasherInterfaceBase.h"
+
+namespace Dasher {
+///Class exists only to redefine the settings accessor methods in CDasherInterfaceBase
+/// and make them public (otherwise they are protected). As opposed to making them public
+/// in CDasherInterfaceBase directly, this has the advantage that it forces all settings
+/// accesses to use the proper channel of CSettingsUser _within_DasherCore_ (as all types etc.
+/// are CDasherInterfaceBase, and should be kept that way!). However, in platform-specific code,
+/// we are often writing stuff in other languages besides C++ and thus cannot get through its
+/// access control; hence, rather than each platform-specific subclass of CDasherInterfaceBase
+/// redeclaring all the settings methods itself, we'll do it once here.
+/// Possible TODO: could make a subclass of CSettingsUser rather than CDasherInterfaceBase, and use multiple inheritance?
+class CDashIntfSettings : public CDasherInterfaceBase {
+public:
+
+  CDashIntfSettings(CSettingsStore *pSettingsStore);
+
+  bool GetBoolParameter(int iParameter) const;
+  long GetLongParameter(int iParameter) const;
+  const std::string &GetStringParameter(int iParameter) const;
+  void SetBoolParameter(int iParameter, bool bValue);
+  void SetLongParameter(int iParameter, long lValue);
+  void SetStringParameter(int iParameter, const string &sValue);
+
+};
+
+}
+#endif
diff --git a/Src/DasherCore/DasherButtons.cpp b/Src/DasherCore/DasherButtons.cpp
index f581969..fe70d89 100644
--- a/Src/DasherCore/DasherButtons.cpp
+++ b/Src/DasherCore/DasherButtons.cpp
@@ -5,9 +5,9 @@
 
 #include "../Common/Common.h"
 
-
 #include "DasherButtons.h"
 #include "DasherScreen.h"
+#include "DasherInterfaceBase.h"
 #include <valarray>
 #include <iostream>
 
@@ -23,10 +23,8 @@ static char THIS_FILE[] = __FILE__;
 
 using namespace Dasher;
 
-// FIXME - should compass mode be made a separate class?
-
-CDasherButtons::CDasherButtons(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, bool bMenu, ModuleID_t iID, const char *szName)
-  : CInputFilter(pEventHandler, pSettingsStore, pInterface, iID, szName), m_bMenu(bMenu), m_bDecorationChanged(true), m_pBoxes(NULL), iActiveBox(0) {}
+CDasherButtons::CDasherButtons(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, bool bMenu, ModuleID_t iID, const char *szName)
+  : CSettingsUser(pCreator), CInputFilter(pInterface, iID, szName), m_bMenu(bMenu), m_bDecorationChanged(true), m_pBoxes(NULL), iActiveBox(0) {}
 
 CDasherButtons::~CDasherButtons()
 {
diff --git a/Src/DasherCore/DasherButtons.h b/Src/DasherCore/DasherButtons.h
index 07aa13f..fb3de08 100644
--- a/Src/DasherCore/DasherButtons.h
+++ b/Src/DasherCore/DasherButtons.h
@@ -10,7 +10,6 @@
 #include <iostream>
 #include <fstream>
 #include <algorithm>
-#include "DasherComponent.h"
 #include "Event.h"
 #include "InputFilter.h"
 
@@ -19,10 +18,10 @@ using namespace std;
 namespace Dasher {
 /// \ingroup Input
 /// @{
-class CDasherButtons : public CInputFilter
+class CDasherButtons : public CInputFilter, protected CSettingsUser
 {
  public:
-  CDasherButtons(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface, bool bMenu, ModuleID_t iID, const char *szName);
+  CDasherButtons(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, bool bMenu, ModuleID_t iID, const char *szName);
 
   ~CDasherButtons();
 
diff --git a/Src/DasherCore/DasherCore_vc80.vcproj b/Src/DasherCore/DasherCore_vc80.vcproj
index b010947..497d2c0 100644
--- a/Src/DasherCore/DasherCore_vc80.vcproj
+++ b/Src/DasherCore/DasherCore_vc80.vcproj
@@ -1791,14 +1791,6 @@
 			>
 		</File>
 		<File
-			RelativePath=".\DasherComponent.cpp"
-			>
-		</File>
-		<File
-			RelativePath="DasherComponent.h"
-			>
-		</File>
-		<File
 			RelativePath=".\DasherGameMode.cpp"
 			>
 		</File>
@@ -1879,6 +1871,14 @@
 			>
 		</File>
 		<File
+			RelativePath=".\DashIntfSettings.cpp"
+			>
+		</File>
+		<File
+			RelativePath=".\DashIntfSettings.h"
+			>
+		</File>
+		<File
 			RelativePath=".\DefaultFilter.cpp"
 			>
 		</File>
@@ -1899,10 +1899,6 @@
 			>
 		</File>
 		<File
-			RelativePath="EventHandler.cpp"
-			>
-		</File>
-		<File
 			RelativePath="EventHandler.h"
 			>
 		</File>
@@ -2058,6 +2054,10 @@
 			>
 		</File>
 		<File
+			RelativePath=".\Parameters.cpp"
+			>
+		</File>
+		<File
 			RelativePath="Parameters.h"
 			>
 		</File>
diff --git a/Src/DasherCore/DasherGameMode.cpp b/Src/DasherCore/DasherGameMode.cpp
index 66de33c..8f962f6 100644
--- a/Src/DasherCore/DasherGameMode.cpp
+++ b/Src/DasherCore/DasherGameMode.cpp
@@ -19,19 +19,17 @@
 using Dasher::GameMode::CDasherGameMode;
 using Dasher::GameMode::UTF8Char;
 
-class Dasher::CEventHandler;
 class CSettingsStore;
 
 std::pair<double,double> GaussianRand();
 
 CDasherGameMode* CDasherGameMode::pTeacher = NULL;
 
-CDasherGameMode* CDasherGameMode::CreateTeacher(Dasher::CEventHandler *pEventHandler,
-						CSettingsStore *pSettingsStore,
+CDasherGameMode* CDasherGameMode::CreateTeacher(CSettingsUser *pCreateFrom,
 						Dasher::CDasherInterfaceBase *pDashIface)
 {
   delete pTeacher; //Initialised to NULL, so this line is safe.
-  pTeacher = new CDasherGameMode(pEventHandler, pSettingsStore, pDashIface);
+  pTeacher = new CDasherGameMode(pCreateFrom, pDashIface);
   return pTeacher;
 }
 
@@ -41,10 +39,9 @@ void CDasherGameMode::DestroyTeacher()
   pTeacher = NULL;
 }
 
-CDasherGameMode::CDasherGameMode(Dasher::CEventHandler *pEventHandler,
-				 CSettingsStore *pSettingsStore,
+CDasherGameMode::CDasherGameMode(CSettingsUser *pCreateFrom,
 				 Dasher::CDasherInterfaceBase *pDashIface)
-  :CDasherComponent(pEventHandler, pSettingsStore),
+  : CSettingsUserObserver(pCreateFrom),
    m_pDasherInterface(pDashIface),
    m_pView(NULL), m_pModel(NULL),
    m_pScorer(NULL), m_pDemo(NULL),
@@ -128,8 +125,7 @@ void CDasherGameMode::Message(int message, void* messagedata)
       
 }
 
-void CDasherGameMode::NotifyGameCooperators(bool bGameOn)
-{
+void CDasherGameMode::NotifyGameCooperators(bool bGameOn) {
   SetBoolParameter(BP_GAME_MODE, bGameOn);
   m_pView->SetGameMode(bGameOn);
   m_pDasherInterface->SetBuffer(0);
@@ -170,7 +166,7 @@ void CDasherGameMode::DemoModeStart(bool bFullDemo)
 {
   // Start up internal first...
   if(!m_pDemo)
-    m_pDemo = new Demo(m_pSettingsStore, bFullDemo);
+    m_pDemo = new Demo(this, bFullDemo);
 
   m_iDemoX = m_iUserX;
   m_iDemoY = m_iUserY;
@@ -192,81 +188,64 @@ void CDasherGameMode::DemoModeStop()
 }
 
 
-void CDasherGameMode::HandleEvent(Dasher::CEvent * pEvent) 
+void CDasherGameMode::HandleEvent(int iParameter)
 {
   // If we are not active, return
-  if(!m_bGameModeOn && !m_pDemo)
-    {
-      //      if(pEvent->m_iEventType == EV_PARAM_NOTIFY)
-      //	{
-      //	  if(static_cast<CParameterNotificationEvent*>(pEvent)->m_iParameter == BP_GAME_MODE)
-      //	    {
-      //	      m_bGameModeOn = GetBoolParameter(BP_GAME_MODE);
-      //	      NotifyGameCooperators(m_bGameModeOn);
-      //	      GameModeStart();
-      //	    }
-      //	}
-      return;
+  if(!m_bGameModeOn && !m_pDemo) return;
+
+  // Otherwise listen for all events and deal with them appropriately
+  switch(iParameter) {
+  case BP_GAME_MODE:
+    //	      m_bGameModeOn = GetBoolParameter(BP_GAME_MODE);
+    //	      if(!m_bGameModeOn) // i.e, if we have just been turned off
+    //		GameModeStop();
+    //	      NotifyGameCooperators(m_bGameModeOn);
+    break;	  
+  case SP_GAME_TEXT_FILE: {
+    string output = "Welcome to Dasher Game Mode!";
+    m_strGameTextFile = GetStringParameter(SP_GAME_TEXT_FILE);
+    std::cout << "Change of game file to " << m_strGameTextFile << std::endl;
+    InitializeTargets();
+    m_pDasherInterface->GameMessageOut(GAME_MESSAGE_DISPLAY_TEXT,
+           reinterpret_cast<const void*>(&output));
+    m_bSentenceFinished = true;
+    break;
+  }
+  case LP_MAX_BITRATE: 
+    CalculateDemoParameters();
+    break;
+  case BP_DASHER_PAUSED:
+    if (GetBoolParameter(BP_DASHER_PAUSED)) {
+      //just stopped
+      if(m_pScorer)
+        m_pScorer->Stop();
+    } else {
+      if(m_pDemo)
+        CalculateDemoParameters();
+      if(m_pScorer)
+        m_pScorer->Start();            
     }
-  else
-    {
-      string output;
-
-      // Otherwise listen for all events and deal with them appropriately
-      switch(pEvent->m_iEventType)
-	{
-	case EV_PARAM_NOTIFY:
+  }
+    
+}
 
-	  switch(static_cast<CParameterNotificationEvent*>(pEvent)->m_iParameter)
-	    {
-	    case BP_GAME_MODE:
-	      //	      m_bGameModeOn = GetBoolParameter(BP_GAME_MODE);
-	      //	      if(!m_bGameModeOn) // i.e, if we have just been turned off
-	      //		GameModeStop();
-	      //	      NotifyGameCooperators(m_bGameModeOn);
-	      break;	  
-	    case SP_GAME_TEXT_FILE:
-              output = "Welcome to Dasher Game Mode!";
-	      m_strGameTextFile = GetStringParameter(SP_GAME_TEXT_FILE);
-	      std::cout << "Change of game file to " << m_strGameTextFile << std::endl;
-     	      InitializeTargets();
-	      m_pDasherInterface->GameMessageOut(GAME_MESSAGE_DISPLAY_TEXT,
-						 reinterpret_cast<const void*>(&output));
-	      m_bSentenceFinished = true;
-	      break;
-	    case LP_MAX_BITRATE: 
-	      CalculateDemoParameters();
-	      break;
-      case BP_DASHER_PAUSED:
-          if (GetBoolParameter(BP_DASHER_PAUSED)) {
-            //just stopped
-            if(m_pScorer)
-              m_pScorer->Stop();
-          } else {
-            if(m_pDemo)
-              CalculateDemoParameters();
-            if(m_pScorer)
-              m_pScorer->Start();            
-          }
-	    }
-	  break;
-	case EV_EDIT:
-	  if(m_bSentenceFinished) break;
-	  CEditEvent *pEditEvent(static_cast < CEditEvent * >(pEvent));
-	  
-	  if(pEditEvent->m_iEditType == 1) {
-	    m_pDasherInterface->GameMessageOut(GAME_MESSAGE_EDIT,
-					       reinterpret_cast<const void*>(&(pEditEvent->m_sText)));
-	  }
-	  else if(pEditEvent->m_iEditType == 2) {
-	    int numDeleted = pEditEvent->m_sText.size();
-	    m_pDasherInterface->GameMessageOut(GAME_MESSAGE_EDIT_DELETE,
-					       reinterpret_cast<const void*>(&numDeleted));
-	  }
-	  break;
-	}
-      return;
-    }
+void CDasherGameMode::HandleEvent(const Dasher::CEditEvent * pEditEvent) 
+{
+  // If we are not active, return
+  if(!m_bGameModeOn && !m_pDemo) return;
+  
+  // Otherwise listen for all events and deal with them appropriately
+  if(m_bSentenceFinished) return;
+    
+  if(pEditEvent->m_iEditType == 1) {
+    m_pDasherInterface->GameMessageOut(GAME_MESSAGE_EDIT,
+                                      reinterpret_cast<const void*>(&(pEditEvent->m_sText)));
+  }
+  else if(pEditEvent->m_iEditType == 2) {
+    int numDeleted = pEditEvent->m_sText.size();
+    m_pDasherInterface->GameMessageOut(GAME_MESSAGE_EDIT_DELETE,
+                                       reinterpret_cast<const void*>(&numDeleted));
+  }
 }
 
 void CDasherGameMode::GameNext()
diff --git a/Src/DasherCore/DasherGameMode.h b/Src/DasherCore/DasherGameMode.h
index ff24418..c75bc5f 100644
--- a/Src/DasherCore/DasherGameMode.h
+++ b/Src/DasherCore/DasherGameMode.h
@@ -7,15 +7,13 @@
 
 #include "../Common/NoClones.h"
 
-#include "DasherComponent.h"
 #include "DasherTypes.h"
-
+#include "SettingsStore.h"
+#include "Event.h"
 
 namespace Dasher {
   class CDasherModel;
   class CDasherInterfaceBase;
-  class CEventHandler;
-  class CDasherComponent;
   class CDasherView;
   
   namespace GameMode {
@@ -34,17 +32,14 @@ namespace Dasher {
     typedef std::string UTF8Char;
     typedef std::list< std::pair<unsigned long, GameFncPtr > > CallbackList;
     typedef std::list< std::pair<unsigned long, Zero_aryCallback* > > FunctorCallbackList;
-  }
-}
 
 /// \defgroup GameMode Game mode support
 /// @{
-class Dasher::GameMode::CDasherGameMode:public Dasher::CDasherComponent, private NoClones {
+class CDasherGameMode:public CSettingsUserObserver,Observer<const CEditEvent *>, private NoClones {
 
 public:
   
-  static CDasherGameMode* CreateTeacher(CEventHandler* pEventHandler, CSettingsStore* pSettingsStore,
-					CDasherInterfaceBase* pDashIface);
+  static CDasherGameMode* CreateTeacher(CSettingsUser* pFrom, CDasherInterfaceBase* pDashIface);
   static void DestroyTeacher();
 
   inline static CDasherGameMode* GetTeacher() {return pTeacher;}
@@ -60,19 +55,20 @@ public:
   UTF8Char GetSymbolAtOffset(unsigned int iOffset);
   void SentenceFinished();
 
-  void HandleEvent(Dasher::CEvent *);
+  void HandleEvent(int iParameter);
+  void HandleEvent(const CEditEvent *evt);
   void DrawGameDecorations(CDasherView* pView);
 
   void Message(int message, void* messagedata);
   friend class Level;
   
 private:
-  CDasherGameMode(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase * pDashIface);
+  CDasherGameMode(CSettingsUser *pCreateFrom, CDasherInterfaceBase * pDashIface);
   ~CDasherGameMode();
 
-  class Demo : public CDasherComponent {
+  class Demo : private CSettingsUser {
   public:
-    Demo(CSettingsStore * pSettingsStore, bool fullDemo=false):CDasherComponent(NULL, pSettingsStore),
+    Demo(CSettingsUser *pCreateFrom, bool fullDemo=false) : CSettingsUser(pCreateFrom),
       sp_alphabet_id(GetStringParameter(SP_ALPHABET_ID)),
       bp_draw_mouse(GetBoolParameter(BP_DRAW_MOUSE)),
       bp_auto_speedcontrol(GetBoolParameter(BP_AUTO_SPEEDCONTROL)),
@@ -208,6 +204,8 @@ private:
   const myint m_iCrossX, m_iCrossY, m_iMaxY;
   Score m_Score;  
 };
+  }
+}
 /// @}
 
 
diff --git a/Src/DasherCore/DasherInput.h b/Src/DasherCore/DasherInput.h
index 0d1dec6..a62320b 100644
--- a/Src/DasherCore/DasherInput.h
+++ b/Src/DasherCore/DasherInput.h
@@ -22,8 +22,8 @@ class Dasher::CDasherInput : public CDasherModule {
 
 public:
 
-  CDasherInput(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, const char *szName) 
-    : CDasherModule(pEventHandler, pSettingsStore, iID, InputDevice, szName) {};
+  CDasherInput(ModuleID_t iID, const char *szName) 
+    : CDasherModule(iID, InputDevice, szName) {};
 
   /// Get the position of the input in Dasher coordinates.
   /// \param iDasherX X-coordinate; if only one coordinate (axis) is available, this should be 0.
@@ -62,8 +62,8 @@ public:
 /// via the views Screen2Dasher. (=>Subclasses must implement GetScreenCoords)
 class Dasher::CScreenCoordInput : public CDasherInput {
 public:
-  CScreenCoordInput(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, ModuleID_t iId, const char *szName)
-  : CDasherInput(pEventHandler, pSettingsStore, iId, szName) {
+  CScreenCoordInput(ModuleID_t iId, const char *szName)
+  : CDasherInput(iId, szName) {
   }
   virtual bool GetDasherCoords(myint &iDasherX, myint &iDasherY, CDasherView *pView)  {
     screenint iX, iY;
@@ -78,8 +78,8 @@ public:
 /// via the views Dasher2Screen. (=>Subclasses must implement GetDasherCoords)
 class Dasher::CDasherCoordInput : public CDasherInput {
 public:
-  CDasherCoordInput(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, ModuleID_t iId, const char *szName)
-  : CDasherInput(pEventHandler, pSettingsStore, iId, szName) {
+  CDasherCoordInput(ModuleID_t iId, const char *szName)
+  : CDasherInput(iId, szName) {
   }
   
   virtual bool GetScreenCoords(screenint &iX, screenint &iY, CDasherView *pView) {
diff --git a/Src/DasherCore/DasherInterfaceBase.cpp b/Src/DasherCore/DasherInterfaceBase.cpp
index f8de7ca..3addd6f 100644
--- a/Src/DasherCore/DasherInterfaceBase.cpp
+++ b/Src/DasherCore/DasherInterfaceBase.cpp
@@ -29,7 +29,7 @@
 #include "DasherView.h"
 #include "DasherInput.h"
 #include "DasherModel.h"
-#include "EventHandler.h"
+#include "Observable.h"
 #include "Event.h"
 #include "NodeCreationManager.h"
 #ifndef _WIN32_WCE
@@ -85,8 +85,10 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CDasherInterfaceBase::CDasherInterfaceBase() : m_pLockLabel(NULL) {
-
+CDasherInterfaceBase::CDasherInterfaceBase(CSettingsStore *pSettingsStore) : CSettingsUser(pSettingsStore), m_pSettingsStore(pSettingsStore), m_pLockLabel(NULL) {
+  
+  pSettingsStore->Register(this, true);
+  
   // Ensure that pointers to 'owned' objects are set to NULL.
   m_pDasherModel = NULL;
   m_DasherScreen = NULL;
@@ -98,7 +100,7 @@ CDasherInterfaceBase::CDasherInterfaceBase() : m_pLockLabel(NULL) {
   m_pUserLog = NULL;
   m_pNCManager = NULL;
   m_defaultPolicy = NULL;
-
+  m_pWordSpeaker = NULL;
   // Various state variables
   m_bRedrawScheduled = false;
 
@@ -106,11 +108,6 @@ CDasherInterfaceBase::CDasherInterfaceBase() : m_pLockLabel(NULL) {
 
   //  m_bGlobalLock = false;
 
-  m_strCurrentWord = "";
-
-  // Create an event handler.
-  m_pEventHandler = new CEventHandler(this);
-
 #ifndef _WIN32_WCE
   // Global logging object we can use from anywhere
   g_pLogger = new CFileLogger("dasher.log",
@@ -122,15 +119,12 @@ CDasherInterfaceBase::CDasherInterfaceBase() : m_pLockLabel(NULL) {
 
 void CDasherInterfaceBase::Realize() {
 
-  // TODO: What exactly needs to have happened by the time we call Realize()?
-  CreateSettingsStore();
-  
-  //create a view, if we have a screen...
-  //if(GetLongParameter(LP_VIEW_ID) != -1)
-  ChangeView();
+  //if ChangeScreen has been called, we'll have created a view;
+  // otherwise, we still can't create a view, until we have a screen!
+  DASHER_ASSERT(m_DasherScreen ? m_pDasherView!=NULL : m_pDasherView==NULL);
 
   //create the model... (no nodes just yet)
-  m_pDasherModel = new CDasherModel(m_pEventHandler, m_pSettingsStore, this);
+  m_pDasherModel = new CDasherModel(this, this);
 
   SetupUI();
   SetupPaths();
@@ -145,6 +139,7 @@ void CDasherInterfaceBase::Realize() {
 
   ChangeColours();
 
+  ChangeView();
   // Create the user logging object if we are suppose to.  We wait
   // until now so we have the real value of the parameter and not
   // just the default.
@@ -155,9 +150,9 @@ void CDasherInterfaceBase::Realize() {
   int iUserLogLevel = GetLongParameter(LP_USER_LOG_LEVEL_MASK);
 
   if(iUserLogLevel == 10)
-    m_pUserLog = new CBasicLog(m_pEventHandler, m_pSettingsStore);
+    m_pUserLog = new CBasicLog(this, this);
   else if (iUserLogLevel > 0)
-    m_pUserLog = new CUserLog(m_pEventHandler, m_pSettingsStore, iUserLogLevel);
+    m_pUserLog = new CUserLog(this, this, iUserLogLevel);
 #else
   m_pUserLog = NULL;
 #endif
@@ -175,8 +170,7 @@ void CDasherInterfaceBase::Realize() {
     pTeacher->SetDasherModel(m_pDasherModel);
 
   SetupActionButtons();
-  CParameterNotificationEvent oEvent(LP_NODE_BUDGET);
-  InterfaceEventHandler(&oEvent);
+  HandleEvent(LP_NODE_BUDGET);
 
   // FIXME - need to rationalise this sort of thing.
   // InvalidateContext(true);
@@ -194,7 +188,7 @@ void CDasherInterfaceBase::Realize() {
 
   using GameMode::CDasherGameMode;
   // Create the teacher singleton object.
-  CDasherGameMode::CreateTeacher(m_pEventHandler, m_pSettingsStore, this);
+  CDasherGameMode::CreateTeacher(this, this);
   CDasherGameMode::GetTeacher()->SetDasherView(m_pDasherView);
   CDasherGameMode::GetTeacher()->SetDasherModel(m_pDasherModel);
 }
@@ -234,10 +228,6 @@ CDasherInterfaceBase::~CDasherInterfaceBase() {
 
   for (std::vector<CActionButton *>::iterator it=m_vRightButtons.begin(); it != m_vRightButtons.end(); ++it)
     delete *it;
-
-  // Must delete event handler after all CDasherComponent derived classes
-
-  delete m_pEventHandler;
 }
 
 void CDasherInterfaceBase::PreSetNotify(int iParameter, const std::string &sNewValue) {
@@ -267,96 +257,97 @@ void CDasherInterfaceBase::PreSetNotify(int iParameter, const std::string &sNewV
   }
 }
 
-void CDasherInterfaceBase::InterfaceEventHandler(Dasher::CEvent *pEvent) {
-
-  if(pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-
-    switch (pEvt->m_iParameter) {
+void CDasherInterfaceBase::HandleEvent(int iParameter) {
+  switch (iParameter) {
 
-    case LP_OUTLINE_WIDTH:
-      ScheduleRedraw();
-      break;
-    case BP_DRAW_MOUSE:
-      ScheduleRedraw();
-      break;
-    case BP_CONTROL_MODE:
-        //force rebuilding tree/nodes, to get new probabilities (inc/exc control node).
-        // This may move the canvas around a bit, but at least manages to keep/reuse the
-        // existing AlphabetManager, NCManager, etc. objects...
-        SetOffset(m_pDasherModel->GetOffset(), true);
-      ScheduleRedraw();
-      break;
-    case BP_DRAW_MOUSE_LINE:
-      ScheduleRedraw();
-      break;
-    case LP_REAL_ORIENTATION:
-      ScheduleRedraw();
-      break;
-    case SP_ALPHABET_ID:
-      ChangeAlphabet();
-      ScheduleRedraw();
-      break;
-    case SP_COLOUR_ID:
-      ChangeColours();
-      ScheduleRedraw();
-      break;
-    case SP_DEFAULT_COLOUR_ID: // Delibarate fallthrough
-    case BP_PALETTE_CHANGE:
-      if(GetBoolParameter(BP_PALETTE_CHANGE))
-	 SetStringParameter(SP_COLOUR_ID, GetStringParameter(SP_DEFAULT_COLOUR_ID));
-      break;
-    case LP_LANGUAGE_MODEL_ID:
-      CreateNCManager();
-      break;
-    case LP_LINE_WIDTH:
-      ScheduleRedraw();
-      break;
-    case LP_DASHER_FONTSIZE:
-      ScheduleRedraw();
-      break;
-    case SP_INPUT_DEVICE:
-      CreateInput();
-      break;
-    case SP_INPUT_FILTER:
-      CreateInputFilter();
-      ScheduleRedraw();
-      break;
-    case BP_DASHER_PAUSED:
+  case LP_OUTLINE_WIDTH:
+    ScheduleRedraw();
+    break;
+  case BP_DRAW_MOUSE:
+    ScheduleRedraw();
+    break;
+  case BP_CONTROL_MODE:
+      //force rebuilding tree/nodes, to get new probabilities (inc/exc control node).
+      // This may move the canvas around a bit, but at least manages to keep/reuse the
+      // existing AlphabetManager, NCManager, etc. objects...
+      SetOffset(m_pDasherModel->GetOffset(), true);
+    ScheduleRedraw();
+    break;
+  case BP_DRAW_MOUSE_LINE:
+    ScheduleRedraw();
+    break;
+  case LP_REAL_ORIENTATION:
+    ScheduleRedraw();
+    break;
+  case SP_ALPHABET_ID:
+    ChangeAlphabet();
+    ScheduleRedraw();
+    break;
+  case SP_COLOUR_ID:
+    ChangeColours();
+    ScheduleRedraw();
+    break;
+  case SP_DEFAULT_COLOUR_ID: // Delibarate fallthrough
+  case BP_PALETTE_CHANGE:
+    if(GetBoolParameter(BP_PALETTE_CHANGE))
+ SetStringParameter(SP_COLOUR_ID, GetStringParameter(SP_DEFAULT_COLOUR_ID));
+    break;
+  case LP_LANGUAGE_MODEL_ID:
+    CreateNCManager();
+    break;
+  case LP_LINE_WIDTH:
+    ScheduleRedraw();
+    break;
+  case LP_DASHER_FONTSIZE:
+    ScheduleRedraw();
+    break;
+  case SP_INPUT_DEVICE:
+    CreateInput();
+    break;
+  case SP_INPUT_FILTER:
+    CreateInputFilter();
+    ScheduleRedraw();
+    break;
+  case BP_DASHER_PAUSED:
+    ScheduleRedraw();
+    break;
+  case LP_MARGIN_WIDTH:
+  case BP_NONLINEAR_Y:
+  case LP_NONLINEAR_X:
+  case LP_GEOMETRY:
+  case LP_SHAPE_TYPE: //for platforms which actually have this as a GUI pref!
       ScheduleRedraw();
       break;
-    case LP_MARGIN_WIDTH:
-    case BP_NONLINEAR_Y:
-    case LP_NONLINEAR_X:
-    case LP_GEOMETRY:
-    case LP_SHAPE_TYPE: //for platforms which actually have this as a GUI pref!
-        ScheduleRedraw();
-        break;
-    case LP_NODE_BUDGET:
-      delete m_defaultPolicy;
-      m_defaultPolicy = new AmortizedPolicy(GetLongParameter(LP_NODE_BUDGET));
-    default:
-      break;
-    }
+  case LP_NODE_BUDGET:
+    delete m_defaultPolicy;
+    m_defaultPolicy = new AmortizedPolicy(GetLongParameter(LP_NODE_BUDGET));
+  case BP_SPEAK_WORDS:
+    delete m_pWordSpeaker;
+    m_pWordSpeaker = GetBoolParameter(BP_SPEAK_WORDS) ? new WordSpeaker(this) : NULL;
+  default:
+    break;
   }
-  else if(pEvent->m_iEventType == EV_EDIT && !GetBoolParameter(BP_GAME_MODE)) {
-    CEditEvent *pEditEvent(static_cast < CEditEvent * >(pEvent));
-
-    if(pEditEvent->m_iEditType == 1) {
-      if (GetBoolParameter(BP_SPEAK_WORDS) && SupportsSpeech()) {
-        const CAlphInfo *pAlphabet = m_pNCManager->GetAlphabet();
-        if (pEditEvent->m_sText == pAlphabet->GetText(pAlphabet->GetSpaceSymbol())) {
-          Speak(m_strCurrentWord, false);
-          m_strCurrentWord="";
-        } else
-          m_strCurrentWord+=pEditEvent->m_sText;
-      }
-    }
-    else if(pEditEvent->m_iEditType == 2) {
-      if (GetBoolParameter(BP_SPEAK_WORDS))
-        m_strCurrentWord = m_strCurrentWord.substr(0, max(static_cast<string::size_type>(0), m_strCurrentWord.size()-pEditEvent->m_sText.size()));
+}
+
+CDasherInterfaceBase::WordSpeaker::WordSpeaker(CDasherInterfaceBase *pIntf) : TransientObserver<const CEditEvent *>(pIntf) {
+}
+
+void CDasherInterfaceBase::WordSpeaker::HandleEvent(const CEditEvent *pEditEvent) {
+  CDasherInterfaceBase *pIntf(static_cast<CDasherInterfaceBase *> (m_pEventHandler));
+  if (pIntf->GetBoolParameter(BP_GAME_MODE)) return;
+  if(pEditEvent->m_iEditType == 1) {
+    if (pIntf->SupportsSpeech()) {
+      const CAlphInfo *pAlphabet = pIntf->m_pNCManager->GetAlphabet();
+      if (pEditEvent->m_sText == pAlphabet->GetText(pAlphabet->GetSpaceSymbol())) {
+        pIntf->Speak(m_strCurrentWord, false);
+        m_strCurrentWord="";
+      } else
+        m_strCurrentWord+=pEditEvent->m_sText;
     }
   }
+  else if(pEditEvent->m_iEditType == 2) {
+    m_strCurrentWord = m_strCurrentWord.substr(0, max(static_cast<string::size_type>(0), m_strCurrentWord.size()-pEditEvent->m_sText.size()));
+  }
 }
 
 void CDasherInterfaceBase::SetLockStatus(const string &strText, int iPercent) {
@@ -379,22 +370,22 @@ void CDasherInterfaceBase::SetLockStatus(const string &strText, int iPercent) {
 
 void CDasherInterfaceBase::editOutput(const std::string &strText, CDasherNode *pCause) {
   CEditEvent evt(CEditEvent::EDIT_OUTPUT, strText, pCause);
-  m_pEventHandler->InsertEvent(&evt);
+  DispatchEvent(&evt);
 }
 
 void CDasherInterfaceBase::editDelete(const std::string &strText, CDasherNode *pCause) {
   CEditEvent evt(CEditEvent::EDIT_DELETE, strText, pCause);
-  m_pEventHandler->InsertEvent(&evt);
+  DispatchEvent(&evt);
 }
 
 void CDasherInterfaceBase::editConvert(CDasherNode *pCause) {
   CEditEvent evt(CEditEvent::EDIT_CONVERT, "", pCause);
-  m_pEventHandler->InsertEvent(&evt);
+  DispatchEvent(&evt);
 }
 
 void CDasherInterfaceBase::editProtect(CDasherNode *pCause) {
   CEditEvent evt(CEditEvent::EDIT_PROTECT, "", pCause);
-  m_pEventHandler->InsertEvent(&evt);
+  DispatchEvent(&evt);
 }
 
 void CDasherInterfaceBase::WriteTrainFileFull() {
@@ -410,7 +401,7 @@ void CDasherInterfaceBase::CreateNCManager() {
   CNodeCreationManager *pOldMgr = m_pNCManager;
 
   //now create the new manager...
-  m_pNCManager = new CNodeCreationManager(this, m_pEventHandler, m_pSettingsStore, m_AlphIO);
+  m_pNCManager = new CNodeCreationManager(this, this, m_AlphIO);
 
   if (m_DasherScreen) {
     m_pNCManager->ChangeScreen(m_DasherScreen);
@@ -659,9 +650,8 @@ void CDasherInterfaceBase::ChangeScreen(CDasherScreen *NewScreen) {
   if(m_pDasherView != 0) {
     m_pDasherView->ChangeScreen(NewScreen);
     ScreenResized(NewScreen);
-  } else if (m_pEventHandler && m_pSettingsStore) {
-    //no screen, but other essential components (created in Realize) present.
-    // IOW, (assume) we were delaying creating a View, until we had a screen...
+  } else {
+    //We can create the view as soon as we have a screen...
     ChangeView();
   }
   
@@ -685,11 +675,14 @@ void CDasherInterfaceBase::ScreenResized(CDasherScreen *pScreen) {
 void CDasherInterfaceBase::ChangeView() {
   // TODO: Actually respond to LP_VIEW_ID parameter (although there is only one view at the moment)
 
-  // removed condition that m_pDasherModel != 0. Surely the view can exist without the model?-pconlon
   if(m_DasherScreen != 0 /*&& m_pDasherModel != 0*/) {
+    CDasherView *pNewView = new CDasherViewSquare(this, m_DasherScreen);
+    //the previous sends an event to all listeners registered with it, but there aren't any atm!
+    // so send an event to tell them of the new view object _and_ get them to recompute coords:  
+    if (m_pDasherView) m_pDasherView->TransferObserversTo(pNewView);
     delete m_pDasherView;
 
-    m_pDasherView = new CDasherViewSquare(m_pEventHandler, m_pSettingsStore, m_DasherScreen);
+    m_pDasherView = pNewView;
 
     // Tell the Teacher which view we are using
     if(GameMode::CDasherGameMode* pTeacher = GameMode::CDasherGameMode::GetTeacher())
@@ -736,31 +729,6 @@ void CDasherInterfaceBase::ClearAllContext() {
   SetBuffer(0);
 }
 
-void CDasherInterfaceBase::SetBoolParameter(int iParameter, bool bValue) {
-  m_pSettingsStore->SetBoolParameter(iParameter, bValue);
-}
-
-void CDasherInterfaceBase::SetLongParameter(int iParameter, long lValue) {
-  m_pSettingsStore->SetLongParameter(iParameter, lValue);
-}
-
-void CDasherInterfaceBase::SetStringParameter(int iParameter, const std::string & sValue) {
-  PreSetNotify(iParameter, sValue);
-  m_pSettingsStore->SetStringParameter(iParameter, sValue);
-}
-
-bool CDasherInterfaceBase::GetBoolParameter(int iParameter) {
-  return m_pSettingsStore->GetBoolParameter(iParameter);
-}
-
-long CDasherInterfaceBase::GetLongParameter(int iParameter) {
-  return m_pSettingsStore->GetLongParameter(iParameter);
-}
-
-std::string CDasherInterfaceBase::GetStringParameter(int iParameter) {
-  return m_pSettingsStore->GetStringParameter(iParameter);
-}
-
 void CDasherInterfaceBase::ResetParameter(int iParameter) {
   m_pSettingsStore->ResetParameter(iParameter);
 }
@@ -834,28 +802,28 @@ void CDasherInterfaceBase::SetDefaultInputMethod(CInputFilter *pModule) {
 }
 
 void CDasherInterfaceBase::CreateModules() {
-  CInputFilter *defFil = new CDefaultFilter(m_pEventHandler, m_pSettingsStore, this, 3, _("Normal Control"));
+  CInputFilter *defFil = new CDefaultFilter(this, this, 3, _("Normal Control"));
   RegisterModule(defFil);
   SetDefaultInputMethod(defFil);
-  RegisterModule(new COneDimensionalFilter(m_pEventHandler, m_pSettingsStore, this));
+  RegisterModule(new COneDimensionalFilter(this, this));
 #ifndef _WIN32_WCE
-  RegisterModule(new CClickFilter(m_pEventHandler, m_pSettingsStore, this));
+  RegisterModule(new CClickFilter(this, this));
 #else
   SetDefaultInputMethod(
-    RegisterModule(new CClickFilter(m_pEventHandler, m_pSettingsStore, this));
+    RegisterModule(new CClickFilter(this, this));
   );
 #endif
-  RegisterModule(new COneButtonFilter(m_pEventHandler, m_pSettingsStore, this));
-  RegisterModule(new COneButtonDynamicFilter(m_pEventHandler, m_pSettingsStore, this));
-  RegisterModule(new CTwoButtonDynamicFilter(m_pEventHandler, m_pSettingsStore, this));
-  RegisterModule(new CTwoPushDynamicFilter(m_pEventHandler, m_pSettingsStore, this));
+  RegisterModule(new COneButtonFilter(this, this));
+  RegisterModule(new COneButtonDynamicFilter(this, this));
+  RegisterModule(new CTwoButtonDynamicFilter(this, this));
+  RegisterModule(new CTwoPushDynamicFilter(this, this));
   // TODO: specialist factory for button mode
-  RegisterModule(new CButtonMode(m_pEventHandler, m_pSettingsStore, this, true, 8, _("Menu Mode")));
-  RegisterModule(new CButtonMode(m_pEventHandler, m_pSettingsStore, this, false,10, _("Direct Mode")));
-  //  RegisterModule(new CDasherButtons(m_pEventHandler, m_pSettingsStore, this, 4, 0, false,11, "Buttons 3"));
-  RegisterModule(new CAlternatingDirectMode(m_pEventHandler, m_pSettingsStore, this));
-  RegisterModule(new CCompassMode(m_pEventHandler, m_pSettingsStore, this));
-  RegisterModule(new CStylusFilter(m_pEventHandler, m_pSettingsStore, this, 15, _("Stylus Control")));
+  RegisterModule(new CButtonMode(this, this, true, 8, _("Menu Mode")));
+  RegisterModule(new CButtonMode(this, this, false,10, _("Direct Mode")));
+  //  RegisterModule(new CDasherButtons(this, this, 4, 0, false,11, "Buttons 3"));
+  RegisterModule(new CAlternatingDirectMode(this, this));
+  RegisterModule(new CCompassMode(this, this));
+  RegisterModule(new CStylusFilter(this, this, 15, _("Stylus Control")));
 }
 
 void CDasherInterfaceBase::GetPermittedValues(int iParameter, std::vector<std::string> &vList) {
@@ -1019,9 +987,7 @@ void CDasherInterfaceBase::SetOffset(int iOffset, bool bForce) {
 
 // Returns 0 on success, an error string on failure.
 const char* CDasherInterfaceBase::ClSet(const std::string &strKey, const std::string &strValue) {
-  if(m_pSettingsStore)
-    return m_pSettingsStore->ClSet(strKey, strValue);
-  return 0;
+  return m_pSettingsStore->ClSet(strKey, strValue);
 }
 
 
diff --git a/Src/DasherCore/DasherInterfaceBase.h b/Src/DasherCore/DasherInterfaceBase.h
index 9fb3df1..11bcc3a 100644
--- a/Src/DasherCore/DasherInterfaceBase.h
+++ b/Src/DasherCore/DasherInterfaceBase.h
@@ -50,13 +50,10 @@ namespace Dasher {
   class CDasherInput;
   class CInputFilter;
   class CDasherModel;
-  class CEventHandler;
-  class CEvent;
-
+  class CSettingsStore;
   class CDasherInterfaceBase;
 }
 
-class CSettingsStore;
 class CUserLogBase;
 class CNodeCreationManager;
 
@@ -69,10 +66,10 @@ class CNodeCreationManager;
 /// the UI to use. Note: CMessageDisplay unimplemented; platforms should
 /// provide their own methods using appropriate GUI components, or subclass
 /// CDashIntfScreenMsgs instead.
-class Dasher::CDasherInterfaceBase : public CMessageDisplay, private NoClones
-{
+class Dasher::CDasherInterfaceBase : public CMessageDisplay, public Observable<const CEditEvent *>, protected Observer<int>, protected CSettingsUser, private NoClones {
 public:
-  CDasherInterfaceBase();
+  ///Create a new interface by providing the only-and-only settings store that will be used throughout.
+  CDasherInterfaceBase(CSettingsStore *pSettingsStore);
   virtual ~CDasherInterfaceBase();
 
   /// @name Access to internal member classes
@@ -81,20 +78,6 @@ public:
   /// be replaced by properly encapsulated equivalents.
   /// @{
 
-  ///
-  /// Return a pointer to the current EventHandler (the one
-  /// which the CSettingsStore is using to notify parameter
-  /// changes)
-  ///
-
-  virtual CEventHandler *GetEventHandler() {
-    return m_pEventHandler;
-  };
-
-  virtual CSettingsStore *GetSettingsStore() {
-    return m_pSettingsStore;
-  }
-
   CUserLogBase* GetUserLogPtr();
 
   // @}
@@ -107,48 +90,6 @@ public:
   //@{
 
   ///
-  /// Set a boolean parameter.
-  /// \param iParameter The parameter to set.
-  /// \param bValue The new value.
-  ///
-
-  void SetBoolParameter(int iParameter, bool bValue);
-
-  ///
-  /// Set a long integer parameter.
-  /// \param iParameter The parameter to set.
-  /// \param lValue The new value.
-  ///
-
-  void SetLongParameter(int iParameter, long lValue);
-
-  ///
-  /// Set a string parameter.
-  /// \param iParameter The parameter to set.
-  /// \param sValue The new value.
-  ///
-
-  void SetStringParameter(int iParameter, const std::string & sValue);
-
-  /// Get a boolean parameter
-  /// \param iParameter The parameter to get.
-  /// \retval The current value.
-
-  bool GetBoolParameter(int iParameter);
-
-  /// Get a long integer parameter
-  /// \param iParameter The parameter to get.
-  /// \retval The current value.
-
-  long GetLongParameter(int iParameter);
-
-  /// Get a string parameter
-  /// \param iParameter The parameter to get.
-  /// \retval The current value.
-
-  std::string GetStringParameter(int iParameter);
-
-  ///
   /// Reset a parameter to the default value
   ///
 
@@ -167,24 +108,18 @@ public:
 
   bool GetModuleSettings(const std::string &strName, SModuleSettings **pSettings, int *iCount);
 
-
   //@}
 
-  /// Forward events to listeners in the SettingsUI and Editbox.
-  /// \param pEvent The event to forward.
-  /// \todo Should be protected.
-
-  virtual void ExternalEventHandler(Dasher::CEvent * pEvent) {};
-
-  /// Interface level event handler. For example, responsible for
+  /// Called when a parameter changes - but *after* components have been notified.
+  /// Subsumes previous Interface level event handler, for example, responsible for
   /// restarting the Dasher model whenever parameter changes make it
-  /// invalid.
-  /// \param pEvent The event.
-  /// \todo Should be protected.
-
-  void InterfaceEventHandler(Dasher::CEvent * pEvent);
-
+  /// invalid. Subclasses should override to forward events to SettingsUI, editbox,
+  /// etc., as appropriate, but should _call_through_to_superclass_method_ first.
+  /// \param iParameter The parameter that's just changed.
+  /// \todo Should be protected (??)
 
+  virtual void HandleEvent(int iParameter);
+  
   void PreSetNotify(int iParameter, const std::string &sValue);
 
   ///Locks/unlocks Dasher. The default here stores the lock message and percentage
@@ -452,11 +387,12 @@ protected:
   /// @{
 
   ///
-  /// Allocate resources, create alphabets etc. This is a separate
-  /// routine to the constructor to give us a chance to set up
-  /// parameters before things are created.
+  /// Finish initializing the DasherInterface; we can't do everything in the constructor,
+  /// because some initialization depends on virtual methods provided by subclasses.
+  /// Both Realize and ChangeScreen must be called after construction before other functions
+  /// will work, but they can be called in either order (as the SettingsStore is passed into
+  /// the c'tor).
   ///
-
   void Realize();
 
   ///
@@ -522,11 +458,24 @@ protected:
 
   /// @}
 
-  CEventHandler *m_pEventHandler;
-  CSettingsStore *m_pSettingsStore;
-
   CDasherScreen *m_DasherScreen;
+
+  /// Asynchronous (non-modal) messages to be displayed to the user, longest-ago
+  /// at the front, along with the timestamp of the frame at which each was first
+  /// displayed to the user - 0 if not yet displayed.
+  std::deque<pair<CDasherScreen::Label*, unsigned long> > m_dqAsyncMessages;
+  
+  /// Modal messages being or waiting to be displayed to the user, longest-ago
+  /// at the front, along with the timestamp when each was first displayed to the
+  /// user (0 if not yet displayed).
+  std::deque<pair<CDasherScreen::Label*, unsigned long> > m_dqModalMessages;
+  
  private:
+  
+  ///We keep a reference to the (currently unique/global) SettingsStore with which
+  /// this interface was created, as ClSet and ResetParameter need to access it.
+  /// (TODO _could_ move these into CSettingsUser, but that seems uglier given so few clients?)
+  CSettingsStore * const m_pSettingsStore;
 
   //The default expansion policy to use - an amortized policy depending on the LP_NODE_BUDGET parameter.
   CExpansionPolicy *m_defaultPolicy;
@@ -567,14 +516,6 @@ protected:
   virtual void SetupUI() = 0;
 
   ///
-  /// Create settings store object, which will be platform dependent
-  /// TODO: Can this not be done just by selecting which settings
-  /// store implementation to instantiate?
-  ///
-
-  virtual void CreateSettingsStore() = 0;
-
-  ///
   /// Start the callback timer
   ///
 
@@ -614,6 +555,15 @@ protected:
   std::vector<CActionButton *> m_vRightButtons;
 
 
+  class WordSpeaker : public TransientObserver<const CEditEvent *> {
+  public:
+    WordSpeaker(CDasherInterfaceBase *pIntf);
+    void HandleEvent(const CEditEvent *);
+  private:
+    ///builds up the word currently being entered
+    std::string m_strCurrentWord;
+  } *m_pWordSpeaker;
+  
   /// @name Child components
   /// Various objects which are 'owned' by the core.
   /// @{
@@ -628,9 +578,6 @@ protected:
   CUserLogBase *m_pUserLog;
   /// @}
 
-  ///builds up the word currently being entered for speech.
-  std::string m_strCurrentWord;
-
   ///If non-empty, Dasher is locked, and this is the message that should be displayed.
   std::string m_strLockMessage;
   /// (Cache) renderable version of previous; created only to render
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index faeb1db..f8d6c90 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -50,11 +50,9 @@ static char THIS_FILE[] = __FILE__;
 
 // CDasherModel
 
-CDasherModel::CDasherModel(CEventHandler *pEventHandler,
-			   CSettingsStore *pSettingsStore,
+CDasherModel::CDasherModel(CSettingsUser *pCreateFrom,
 			   CDasherInterfaceBase *pDasherInterface)
-  : CFrameRate(pEventHandler, pSettingsStore) {
-  m_pDasherInterface = pDasherInterface;
+  : CFrameRate(pCreateFrom), m_pDasherInterface(pDasherInterface) {
 
   m_bGameMode = GetBoolParameter(BP_GAME_MODE);
 
@@ -74,8 +72,6 @@ CDasherModel::CDasherModel(CEventHandler *pEventHandler,
   m_bRequireConversion = false;
 #endif
 
-  SetBoolParameter(BP_CONVERSION_MODE, m_bRequireConversion);
-
   m_dAddProb = 0.003;
 
   int iNormalization = GetLongParameter(LP_NORMALIZATION);
@@ -98,31 +94,27 @@ CDasherModel::~CDasherModel() {
   }
 }
 
-void CDasherModel::HandleEvent(Dasher::CEvent *pEvent) {
-  CFrameRate::HandleEvent(pEvent);
-
-  if(pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-
-    switch (pEvt->m_iParameter) {
-    case BP_SMOOTH_OFFSET:
-      if (!GetBoolParameter(BP_SMOOTH_OFFSET))
-        //smoothing has just been turned off. End any transition/jump currently
-        // in progress at it's current point
-        AbortOffset();
-      break;
-    case BP_DASHER_PAUSED:
-      if(GetBoolParameter(BP_SLOW_START))
-	m_iStartTime = 0;
-      //else, leave m_iStartTime as is - will result in no slow start
-      break;
-    case BP_GAME_MODE:
-      m_bGameMode = GetBoolParameter(BP_GAME_MODE);
-      // Maybe reload something here to begin game mode?
-      break;
-    default:
-      break;
-    }
+void CDasherModel::HandleEvent(int iParameter) {
+  CFrameRate::HandleEvent(iParameter);
+
+  switch (iParameter) {
+  case BP_SMOOTH_OFFSET:
+    if (!GetBoolParameter(BP_SMOOTH_OFFSET))
+      //smoothing has just been turned off. End any transition/jump currently
+      // in progress at it's current point
+      AbortOffset();
+    break;
+  case BP_DASHER_PAUSED:
+    if(GetBoolParameter(BP_SLOW_START))
+      m_iStartTime = 0;
+    //else, leave m_iStartTime as is - will result in no slow start
+    break;
+  case BP_GAME_MODE:
+    m_bGameMode = GetBoolParameter(BP_GAME_MODE);
+    // Maybe reload something here to begin game mode?
+    break;
+  default:
+    break;
   }
 }
 
diff --git a/Src/DasherCore/DasherModel.h b/Src/DasherCore/DasherModel.h
index 1612f50..bc03929 100644
--- a/Src/DasherCore/DasherModel.h
+++ b/Src/DasherCore/DasherModel.h
@@ -31,7 +31,6 @@
 #include <vector>
 
 #include "../Common/NoClones.h"
-#include "DasherComponent.h"
 #include "DasherNode.h"
 #include "DasherTypes.h"
 #include "FrameRate.h"
@@ -61,14 +60,14 @@ class Dasher::CDasherModel:public Dasher::CFrameRate, private NoClones
  public:
   /// Constructs a new CDasherModel. Note, must be followed by a call to
   /// SetOffset() before the model can be used.
-  CDasherModel(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pDashIface);
+  CDasherModel(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pDashIface);
   ~CDasherModel();
 
   ///
   /// Event handler
   ///
 
-  void HandleEvent(Dasher::CEvent * pEvent);
+  void HandleEvent(int iParameter);
 
   /// @name Dymanic evolution
   /// Routines detailing the timer dependent evolution of the model
diff --git a/Src/DasherCore/DasherModule.cpp b/Src/DasherCore/DasherModule.cpp
index 9872a4e..6df8597 100644
--- a/Src/DasherCore/DasherModule.cpp
+++ b/Src/DasherCore/DasherModule.cpp
@@ -26,8 +26,7 @@
 // 0 = Input method
 // 1 = Input filter
 
-CDasherModule::CDasherModule(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, int iType, const char *szName) 
-  : CDasherComponent(pEventHandler, pSettingsStore) {
+CDasherModule::CDasherModule(ModuleID_t iID, int iType, const char *szName) {
   m_iID = iID;
   m_iType = iType;
   m_szName = szName;
diff --git a/Src/DasherCore/DasherModule.h b/Src/DasherCore/DasherModule.h
index 9d305a8..3ac3222 100644
--- a/Src/DasherCore/DasherModule.h
+++ b/Src/DasherCore/DasherModule.h
@@ -24,16 +24,15 @@
 #include <vector>
 
 #include "../Common/ModuleSettings.h"
-#include "DasherComponent.h"
 
 class CDasherModule;
 typedef std::vector<CDasherModule*>::size_type ModuleID_t;
 
 /// \ingroup Core
 /// @{
-class CDasherModule : public Dasher::CDasherComponent {
+class CDasherModule {
  public:
-  CDasherModule(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, int iType, const char *szName);
+  CDasherModule(ModuleID_t iID, int iType, const char *szName);
 
   virtual ModuleID_t GetID();
   virtual void SetID(ModuleID_t);
diff --git a/Src/DasherCore/DasherView.cpp b/Src/DasherCore/DasherView.cpp
index 3e8dc0f..577bf11 100644
--- a/Src/DasherCore/DasherView.cpp
+++ b/Src/DasherCore/DasherView.cpp
@@ -23,9 +23,6 @@
 #include "DasherGameMode.h"
 #include "DasherInput.h"
 #include "DasherView.h"
-#include "Event.h"
-#include "EventHandler.h"
-#include "DasherScreen.h"
 
 using namespace Dasher;
 using std::vector;
@@ -42,8 +39,7 @@ static char THIS_FILE[] = __FILE__;
 
 /////////////////////////////////////////////////////////////////////////////
 
-CDasherView::CDasherView(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherScreen *DasherScreen)
-  :CDasherComponent(pEventHandler, pSettingsStore), m_pScreen(DasherScreen),
+CDasherView::CDasherView(CDasherScreen *DasherScreen) : m_pScreen(DasherScreen),
    m_bDemoMode(false), m_bGameMode(false) {
 }
 
diff --git a/Src/DasherCore/DasherView.h b/Src/DasherCore/DasherView.h
index ebc6b10..bbebedd 100644
--- a/Src/DasherCore/DasherView.h
+++ b/Src/DasherCore/DasherView.h
@@ -6,15 +6,14 @@
 #define __DasherView_h_
 
 namespace Dasher {
-  class CDasherComponent;
   class CDasherView;
   class CDasherNode;
 }
 
 #include "DasherTypes.h"
-#include "DasherComponent.h"
 #include "ExpansionPolicy.h"
 #include "DasherScreen.h"
+#include "Observable.h"
 
 /// \defgroup View Visualisation of the model
 /// @{
@@ -39,16 +38,20 @@ namespace Dasher {
 /// mode). We should probably consider creating separate classes for
 /// these.
 
-class Dasher::CDasherView : public Dasher::CDasherComponent
-{
+///Also an Observable: events should be generated whenever the screen
+/// geometry changes: e.g. aspect ratio, size, degree of nonlinearity,
+/// orientation, or generally whenever values returned by Dasher2Screen/Screen2Dasher
+/// might have changed (thus, any code caching such values should recompute/invalidate them).
+/// The "event" is just a pointer to the View itself, but can also be used
+/// to send round a pointer to a new view (i.e. replacing this one).
+
+class Dasher::CDasherView : public Observable<CDasherView *> {
 public:
 
   /// Constructor
   /// 
-  /// \param pEventHandler Pointer to the event handler
-  /// \param pSettingsStore Pointer to the settings store
   /// \param DasherScreen Pointer to the CDasherScreen object used to do rendering
-  CDasherView(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherScreen * DasherScreen);
+  CDasherView(CDasherScreen * DasherScreen);
 
   virtual ~CDasherView() {
   }
@@ -97,6 +100,9 @@ public:
   /// the same one-and-only screen that we are using anyway, so remove parameter?
   virtual void ScreenResized(CDasherScreen *pScreen) {}
 
+  void TransferObserversTo(CDasherView *pNewView) {
+    DispatchEvent(pNewView);
+  }
   /// @name High level drawing
   /// Drawing more complex structures, generally implemented by derived class
   /// @{
diff --git a/Src/DasherCore/DasherViewSquare.cpp b/Src/DasherCore/DasherViewSquare.cpp
index 0cbac99..b85fb0e 100644
--- a/Src/DasherCore/DasherViewSquare.cpp
+++ b/Src/DasherCore/DasherViewSquare.cpp
@@ -30,7 +30,7 @@
 #include "DasherView.h"
 #include "DasherTypes.h"
 #include "Event.h"
-#include "EventHandler.h"
+#include "Observable.h"
 
 #include <algorithm>
 #include <iostream>
@@ -58,8 +58,8 @@ static char THIS_FILE[] = __FILE__;
 
 // FIXME - duplicated 'mode' code throught - needs to be fixed (actually, mode related stuff, Input2Dasher etc should probably be at least partially in some other class)
 
-CDasherViewSquare::CDasherViewSquare(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherScreen *DasherScreen)
-: CDasherView(pEventHandler, pSettingsStore, DasherScreen),   m_Y1(4), m_Y2(0.95 * GetLongParameter(LP_MAX_Y)), m_Y3(0.05 * GetLongParameter((LP_MAX_Y))), m_bVisibleRegionValid(false) {
+CDasherViewSquare::CDasherViewSquare(CSettingsUser *pCreateFrom, CDasherScreen *DasherScreen)
+: CDasherView(DasherScreen), CSettingsUserObserver(pCreateFrom), m_Y1(4), m_Y2(0.95 * GetLongParameter(LP_MAX_Y)), m_Y3(0.05 * GetLongParameter((LP_MAX_Y))), m_bVisibleRegionValid(false) {
 
   //Note, nonlinearity parameters set in SetScaleFactor
   ScreenResized(DasherScreen);
@@ -67,14 +67,8 @@ CDasherViewSquare::CDasherViewSquare(CEventHandler *pEventHandler, CSettingsStor
 
 CDasherViewSquare::~CDasherViewSquare() {}
 
-void CDasherViewSquare::HandleEvent(Dasher::CEvent *pEvent) {
-  // Let the parent class do its stuff
-  CDasherView::HandleEvent(pEvent);
-
-  // And then interpret events for ourself
-  if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-    switch (pEvt->m_iParameter) {
+void CDasherViewSquare::HandleEvent(int iParameter) {
+  switch (iParameter) {
     case LP_REAL_ORIENTATION:
     case LP_MARGIN_WIDTH:
     case BP_NONLINEAR_Y:
@@ -82,10 +76,6 @@ void CDasherViewSquare::HandleEvent(Dasher::CEvent *pEvent) {
     case LP_GEOMETRY:
       m_bVisibleRegionValid = false;
       SetScaleFactor();
-      break;
-    default:
-      break;
-    }
   }
 }
 
@@ -904,8 +894,8 @@ void CDasherViewSquare::SetScaleFactor( void )
   }
 #endif
 
-  CScreenGeomEvent evt;
-  InsertEvent(&evt);
+  //notify listeners that coordinates have changed...
+  DispatchEvent(this);
 }
 
 
diff --git a/Src/DasherCore/DasherViewSquare.h b/Src/DasherCore/DasherViewSquare.h
index db8f693..b3daf32 100644
--- a/Src/DasherCore/DasherViewSquare.h
+++ b/Src/DasherCore/DasherViewSquare.h
@@ -8,8 +8,7 @@
 #include "DasherScreen.h"
 #include <deque>
 #include "Alphabet/GroupInfo.h"
-
-
+#include "SettingsStore.h"
 
 using namespace std;
 
@@ -20,10 +19,6 @@ namespace Dasher {
   class CDasherNode;
 }
 
-class Dasher::CDasherViewSquare;
-class Dasher::CDasherModel;
-class Dasher::CDasherNode;
-
 /// \ingroup View
 /// @{
 
@@ -34,27 +29,25 @@ class Dasher::CDasherNode;
 ///
 /// Horizontal mapping - linear and log
 /// Vertical mapping - linear with different gradient
-class Dasher::CDasherViewSquare:public Dasher::CDasherView
+class Dasher::CDasherViewSquare : public Dasher::CDasherView, public CSettingsUserObserver
 {
 public:
 
   /// Constructor
   ///
-  /// \param pEventHandler Event handler.
-  /// \param pSettingsStore Settings store.
   /// \param DasherScreen Pointer to creen to which the view will render.
   /// \todo Don't cache screen and model locally - screen can be
   /// passed as parameter to the drawing functions, and data structure
   /// can be extracted from the model and passed too.
 
-  CDasherViewSquare(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherScreen *DasherScreen);
+  CDasherViewSquare(CSettingsUser *pCreateFrom, CDasherScreen *DasherScreen);
   ~CDasherViewSquare();
 
   ///
   /// Event handler
   ///
 
-  virtual void HandleEvent(Dasher::CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
 
   /// Resets scale factors etc. that depend on the screen size, to be recomputed when next needed.
   void ScreenResized(CDasherScreen * NewScreen);
diff --git a/Src/DasherCore/DefaultFilter.cpp b/Src/DasherCore/DefaultFilter.cpp
index ee91339..4fb1f79 100644
--- a/Src/DasherCore/DefaultFilter.cpp
+++ b/Src/DasherCore/DefaultFilter.cpp
@@ -24,10 +24,10 @@ bool CDefaultFilter::GetSettings(SModuleSettings **sets, int *iCount) {
   return true;
 }
 
-CDefaultFilter::CDefaultFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
-  : CInputFilter(pEventHandler, pSettingsStore, pInterface, iID, szName) {
+CDefaultFilter::CDefaultFilter(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
+  : CInputFilter(pInterface, iID, szName), CSettingsUserObserver(pCreateFrom) {
   m_pStartHandler = 0;
-  m_pAutoSpeedControl = new CAutoSpeedControl(pInterface, m_pEventHandler, m_pSettingsStore);
+  m_pAutoSpeedControl = new CAutoSpeedControl(this, pInterface);
 
   // Initialize autocalibration (i.e. seen nothing yet)
   m_iSum = 0;
@@ -165,16 +165,12 @@ void CDefaultFilter::KeyDown(int iTime, int iId, CDasherView *pDasherView, CDash
   }
 }
 
-void CDefaultFilter::HandleEvent(Dasher::CEvent * pEvent) {
-  if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-
-    switch (pEvt->m_iParameter) {
-    case BP_CIRCLE_START:
-    case BP_MOUSEPOS_MODE:
-      CreateStartHandler();
-      break;
-    }
+void CDefaultFilter::HandleEvent(int iParameter) {
+  switch (iParameter) {
+  case BP_CIRCLE_START:
+  case BP_MOUSEPOS_MODE:
+    CreateStartHandler();
+    break;
   }
 }
 
@@ -195,9 +191,9 @@ void CDefaultFilter::Deactivate() {
 
 CStartHandler *CDefaultFilter::MakeStartHandler() {
   if(GetBoolParameter(BP_CIRCLE_START))
-    return new CCircleStartHandler(m_pEventHandler, m_pSettingsStore, m_pInterface);
+    return new CCircleStartHandler(this, m_pInterface);
   if(GetBoolParameter(BP_MOUSEPOS_MODE))
-    return new CTwoBoxStartHandler(m_pEventHandler, m_pSettingsStore, m_pInterface);
+    return new CTwoBoxStartHandler(this, m_pInterface);
   return NULL;
 }
 
diff --git a/Src/DasherCore/DefaultFilter.h b/Src/DasherCore/DefaultFilter.h
index b3670e4..53e06f1 100644
--- a/Src/DasherCore/DefaultFilter.h
+++ b/Src/DasherCore/DefaultFilter.h
@@ -8,13 +8,13 @@
 namespace Dasher {
 /// \ingroup InputFilter
 /// @{
-class CDefaultFilter : public CInputFilter {
+class CDefaultFilter : public CInputFilter, public CSettingsUserObserver {
  public:
-  CDefaultFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
+  CDefaultFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
   ~CDefaultFilter();
   virtual bool supportsPause() {return true;}
 
-  virtual void HandleEvent(Dasher::CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
 
   virtual bool DecorateView(CDasherView *pView, CDasherInput *pInput);
   virtual bool Timer(unsigned long Time, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CExpansionPolicy **pol);
diff --git a/Src/DasherCore/DynamicFilter.cpp b/Src/DasherCore/DynamicFilter.cpp
index 8f5a741..0de03c8 100644
--- a/Src/DasherCore/DynamicFilter.cpp
+++ b/Src/DasherCore/DynamicFilter.cpp
@@ -23,8 +23,8 @@
 
 using namespace Dasher;
 
-CDynamicFilter::CDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
-  : CInputFilter(pEventHandler, pSettingsStore, pInterface, iID, szName) {
+CDynamicFilter::CDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
+  : CInputFilter(pInterface, iID, szName), CSettingsUserObserver(pCreator) {
   m_bDecorationChanged = true;
   m_bKeyDown = false;
   pause();
@@ -127,25 +127,22 @@ void CDynamicFilter::Event(int iTime, int iButton, int iType, CDasherModel *pMod
   }
 }
 
-void CDynamicFilter::HandleEvent(CEvent *pEvent) {
-  if (pEvent->m_iEventType==EV_PARAM_NOTIFY) {
-    if (static_cast<CParameterNotificationEvent *>(pEvent)->m_iParameter==BP_DASHER_PAUSED) {
-      if (GetBoolParameter(BP_DASHER_PAUSED))
-        pause(); //make sure we're in sync
-      else if (m_pInterface->GetActiveInputMethod()==this && isPaused())
-        //if we're active: can't unpause, as we don't know which way to go, run or reverse?
-        SetBoolParameter(BP_DASHER_PAUSED, true);
-    }
+void CDynamicFilter::HandleEvent(int iParameter) {
+  if (iParameter==BP_DASHER_PAUSED) {
+    if (GetBoolParameter(BP_DASHER_PAUSED))
+      pause(); //make sure we're in sync
+    else if (m_pInterface->GetActiveInputMethod()==this && isPaused())
+      //if we're active: can't unpause, as we don't know which way to go, run or reverse?
+      SetBoolParameter(BP_DASHER_PAUSED, true);
   }
 }
 
 void CDynamicFilter::reverse()
 {
   m_iState = 1;
-  if (GetBoolParameter(BP_AUTO_SPEEDCONTROL))
-  {
-	//treat reversing as a sign of distress --> slow down!
-	SetLongParameter(LP_MAX_BITRATE, GetLongParameter(LP_MAX_BITRATE) *
+  if (GetBoolParameter(BP_AUTO_SPEEDCONTROL)) {
+    //treat reversing as a sign of distress --> slow down!
+    SetLongParameter(LP_MAX_BITRATE, GetLongParameter(LP_MAX_BITRATE) *
 					 (1.0 - GetLongParameter(LP_DYNAMIC_SPEED_DEC)/100.0));
   }
 }
diff --git a/Src/DasherCore/DynamicFilter.h b/Src/DasherCore/DynamicFilter.h
index 57e42b5..035afbb 100644
--- a/Src/DasherCore/DynamicFilter.h
+++ b/Src/DasherCore/DynamicFilter.h
@@ -27,9 +27,9 @@
 /// @{
 namespace Dasher {
 ///filter with three states: paused, reversing, running. Hold any button down to reverse.
-class CDynamicFilter : public CInputFilter {
+class CDynamicFilter : public CInputFilter, public CSettingsUserObserver {
  public:
-  CDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
+  CDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
 
   virtual bool supportsPause() {return true;}
 
@@ -40,7 +40,7 @@ class CDynamicFilter : public CInputFilter {
   virtual void KeyUp(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel);
 
   //respond to changes to BP_DASHER_PAUSED to keep m_iState in sync
-  virtual void HandleEvent(CEvent *pEvent);
+  virtual void HandleEvent(int iParameter);
  protected:
   virtual void ActionButton(int iTime, int iButton, int iType, CDasherModel *pModel, CUserLogBase *pUserLog) = 0;
   virtual void Event(int iTime, int iButton, int iType, CDasherModel *pModel, CUserLogBase *pUserLog);
diff --git a/Src/DasherCore/Event.h b/Src/DasherCore/Event.h
index 0e517fb..2ee40a5 100644
--- a/Src/DasherCore/Event.h
+++ b/Src/DasherCore/Event.h
@@ -7,41 +7,20 @@
 #include "DasherTypes.h"
 
 namespace Dasher {
-  class CEvent;
-  class CParameterNotificationEvent;
   class CEditEvent;
-  class CScreenGeomEvent;
   class CDasherNode; //fwd decl, avoid include...we just store ptr
 }
 
-enum {
-  EV_PARAM_NOTIFY = 1, EV_EDIT, EV_SCREEN_GEOM
-};
-
 /// \ingroup Core
 /// @{
 
 /// \defgroup Events Events generated by Dasher modules.
 /// @{
-class Dasher::CEvent {
-protected:
-  CEvent(int iEventType) : m_iEventType(iEventType) {}
-public:
-  const int m_iEventType;
-};
-
-class Dasher::CParameterNotificationEvent:public Dasher::CEvent {
-public:
-  CParameterNotificationEvent(int iParameter) : CEvent(EV_PARAM_NOTIFY), m_iParameter(iParameter) {
-  };
-
-  const int m_iParameter;
-};
 
-class Dasher::CEditEvent:public Dasher::CEvent {
+class Dasher::CEditEvent {
   friend class CDasherInterfaceBase;
   CEditEvent(int iEditType, const std::string & sText, CDasherNode *pNode)
-  : CEvent(EV_EDIT), m_iEditType(iEditType), m_sText(sText), m_pNode(pNode) {
+  : m_iEditType(iEditType), m_sText(sText), m_pNode(pNode) {
   };  
 public:
   static const int EDIT_OUTPUT=1, EDIT_DELETE=2, EDIT_CONVERT=10, EDIT_PROTECT=11;
@@ -52,15 +31,6 @@ public:
   const CDasherNode *m_pNode;
 };
 
-///Generated whenever the screen geometry changes: e.g. aspect ratio,
-/// size, degree of nonlinearity, orientation, or generally whenever
-/// values returned by Dasher2Screen/Screen2Dasher might have changed
-/// (thus, any code caching such values should recompute/invalidate them)
-class Dasher::CScreenGeomEvent : public Dasher::CEvent {
-public:
-  CScreenGeomEvent() : CEvent(EV_SCREEN_GEOM) {
-  }
-};
 /// @}
 /// @}
 
diff --git a/Src/DasherCore/FrameRate.cpp b/Src/DasherCore/FrameRate.cpp
index d5f0f3c..50d78ec 100644
--- a/Src/DasherCore/FrameRate.cpp
+++ b/Src/DasherCore/FrameRate.cpp
@@ -2,8 +2,8 @@
 
 using namespace Dasher;
 
-CFrameRate::CFrameRate(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore) :
-  CDasherComponent(pEventHandler, pSettingsStore) {
+CFrameRate::CFrameRate(CSettingsUser *pCreator) :
+  CSettingsUserObserver(pCreator) {
 
   //Sampling parameters...
   m_iFrames = 0;
@@ -11,8 +11,8 @@ CFrameRate::CFrameRate(CEventHandler *pEventHandler, CSettingsStore *pSettingsSt
   m_iTime = 0;                  // Hmmm, User must reset framerate before starting.
 
   //try and carry on from where we left off at last run
-  {CParameterNotificationEvent evt(LP_FRAMERATE); HandleEvent(&evt);}
-  {CParameterNotificationEvent evt(LP_MAX_BITRATE); HandleEvent(&evt);}
+  HandleEvent(LP_FRAMERATE);
+  HandleEvent(LP_MAX_BITRATE);
   //calls UpdateSteps(), which sets m_dRXMax and m_iSteps
 }
 
@@ -53,20 +53,16 @@ void CFrameRate::RecordFrame(unsigned long Time)
   }
 }
 
-void CFrameRate::HandleEvent(Dasher::CEvent *pEvent) {
+void CFrameRate::HandleEvent(int iParameter) {
 
-  if(pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-
-    switch (pEvt->m_iParameter) {
-    case LP_MAX_BITRATE: // Delibarate fallthrough
-    case LP_BOOSTFACTOR:
-      m_dMaxbitrate=(GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR)) / 10000.0;
-      UpdateSteps(GetLongParameter(LP_FRAMERATE) / 100.0); //use the decaying average as current
-      break;
-    case LP_FRAMERATE:
-      m_dFrDecay = GetLongParameter(LP_FRAMERATE) / 100.0;
-    }
+  switch (iParameter) {
+  case LP_MAX_BITRATE: // Delibarate fallthrough
+  case LP_BOOSTFACTOR:
+    m_dMaxbitrate=(GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR)) / 10000.0;
+    UpdateSteps(GetLongParameter(LP_FRAMERATE) / 100.0); //use the decaying average as current
+    break;
+  case LP_FRAMERATE:
+    m_dFrDecay = GetLongParameter(LP_FRAMERATE) / 100.0;
   }
 }
 
diff --git a/Src/DasherCore/FrameRate.h b/Src/DasherCore/FrameRate.h
index 8e13a80..a8ba27d 100644
--- a/Src/DasherCore/FrameRate.h
+++ b/Src/DasherCore/FrameRate.h
@@ -13,7 +13,7 @@
 #include "../Common/Common.h"
 #include "Event.h"
 #include "Parameters.h"
-#include "DasherComponent.h"
+#include "SettingsStore.h"
 
 namespace Dasher {
 /// \ingroup Model
@@ -22,11 +22,11 @@ namespace Dasher {
 /// keeps the framerate (LP_FRAMERATE / 100.0) up-to-date,
 /// computes the Steps parameter,
 /// computes RXmax - which controls the maximum rate of zooming in
-class CFrameRate : public CDasherComponent {
+class CFrameRate : public CSettingsUserObserver  {
 public:
-  CFrameRate(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore);
+  CFrameRate(CSettingsUser *pCreator);
   
-  virtual void HandleEvent(Dasher::CEvent *pEvent);
+  virtual void HandleEvent(int iParameter);
 
   /// Get the minimum size of the target viewport
   ////// TODO: Eventually fix this so that it uses integer maths internally. 
diff --git a/Src/DasherCore/InputFilter.h b/Src/DasherCore/InputFilter.h
index 3925fa8..fae357d 100644
--- a/Src/DasherCore/InputFilter.h
+++ b/Src/DasherCore/InputFilter.h
@@ -15,9 +15,8 @@ namespace Dasher {
 namespace Dasher {
 class CInputFilter : public CDasherModule {
  public:
-  CInputFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
-    : CDasherModule(pEventHandler, pSettingsStore, iID, InputMethod, szName) {
-    m_pInterface = pInterface;
+  CInputFilter(CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
+    : CDasherModule(iID, InputMethod, szName), m_pInterface(pInterface) {
   };
 
   virtual bool DecorateView(CDasherView *pView, CDasherInput *pInput) { return false; };
diff --git a/Src/DasherCore/LanguageModelling/DictLanguageModel.cpp b/Src/DasherCore/LanguageModelling/DictLanguageModel.cpp
index 9e7077c..10d64fa 100644
--- a/Src/DasherCore/LanguageModelling/DictLanguageModel.cpp
+++ b/Src/DasherCore/LanguageModelling/DictLanguageModel.cpp
@@ -90,8 +90,8 @@ CDictLanguageModel::CDictnode * CDictLanguageModel::AddSymbolToNode(CDictnode *p
 // CDictLanguageModel defs
 /////////////////////////////////////////////////////////////////////
 
-CDictLanguageModel::CDictLanguageModel(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap)
-:CLanguageModel(pAlph->GetNumberTextSymbols()), CDasherComponent(pEventHandler, pSettingsStore), m_pAlphMap(pAlphMap), m_iSpaceSymbol(pAlph->GetSpaceSymbol()), NodesAllocated(0), max_order(0), m_NodeAlloc(8192), m_ContextAlloc(1024) {
+CDictLanguageModel::CDictLanguageModel(CSettingsUser *pCreator, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap)
+:CLanguageModel(pAlph->GetNumberTextSymbols()), CSettingsUser(pCreator), m_pAlphMap(pAlphMap), m_iSpaceSymbol(pAlph->GetSpaceSymbol()), NodesAllocated(0), max_order(0), m_NodeAlloc(8192), m_ContextAlloc(1024) {
   m_pRoot = m_NodeAlloc.Alloc();
   m_pRoot->sbl = -1;
   m_rootcontext = new CDictContext(m_pRoot, 0);
diff --git a/Src/DasherCore/LanguageModelling/DictLanguageModel.h b/Src/DasherCore/LanguageModelling/DictLanguageModel.h
index 8db59c3..573262d 100644
--- a/Src/DasherCore/LanguageModelling/DictLanguageModel.h
+++ b/Src/DasherCore/LanguageModelling/DictLanguageModel.h
@@ -25,9 +25,9 @@
 namespace Dasher {
   /// \ingroup LM
   /// \{
-  class CDictLanguageModel:public CLanguageModel, public CDasherComponent {
+  class CDictLanguageModel:public CLanguageModel, protected CSettingsUser {
   public:
-    CDictLanguageModel(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap);
+    CDictLanguageModel(CSettingsUser *pCreator, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap);
     virtual ~CDictLanguageModel();
 
     Context CreateEmptyContext();
diff --git a/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.cpp b/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.cpp
index cc44e43..ceda181 100644
--- a/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.cpp
+++ b/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.cpp
@@ -38,8 +38,8 @@ static char THIS_FILE[] = __FILE__;
 
 /////////////////////////////////////////////////////////////////////
 
-CJapaneseLanguageModel::CJapaneseLanguageModel(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, const CAlphInfo *pAlph)
-:CLanguageModel(pEventHandler, pSettingsStore, pAlph), m_iMaxOrder(5), NodesAllocated(0), m_NodeAlloc(8192), m_ContextAlloc(1024) {
+CJapaneseLanguageModel::CJapaneseLanguageModel(CSettingsStore *pSettingsStore, const CAlphInfo *pAlph)
+:CLanguageModel(pAlph->GetNumberTextSymbols()), m_pSettingsStore(pSettingsStore), m_iMaxOrder(5), NodesAllocated(0), m_NodeAlloc(8192), m_ContextAlloc(1024) {
   m_pRoot = m_NodeAlloc.Alloc();
   m_pRoot->symbol = -1;
 
@@ -49,7 +49,7 @@ CJapaneseLanguageModel::CJapaneseLanguageModel(Dasher::CEventHandler *pEventHand
 
   // Cache the result of update exclusion - otherwise we have to look up a lot when training, which is slow
 
-  bUpdateExclusion = ( GetLongParameter(LP_LM_UPDATE_EXCLUSION) !=0 );
+  bUpdateExclusion = ( m_pSettingsStore->GetLongParameter(LP_LM_UPDATE_EXCLUSION) !=0 );
   
 }
 
@@ -80,8 +80,8 @@ void CJapaneseLanguageModel::GetProbs(Context context, std::vector<unsigned int>
 
   bool doExclusion = 0; //FIXME
 
-  int alpha = GetLongParameter( LP_LM_ALPHA );
-  int beta = GetLongParameter( LP_LM_BETA );
+  int alpha = m_pSettingsStore->GetLongParameter( LP_LM_ALPHA );
+  int beta = m_pSettingsStore->GetLongParameter( LP_LM_BETA );
 
 
   unsigned int iToSpend = norm;
@@ -341,7 +341,7 @@ void CJapaneseLanguageModel::AddSymbol(CJapaneseLanguageModel::CJaPPMContext &co
   vineptr->vine = m_pRoot;
 
   //  m_iMaxOrder = LanguageModelParams()->GetValue(std::string("LMMaxOrder"));
-  m_iMaxOrder = GetLongParameter( LP_LM_MAX_ORDER );
+  m_iMaxOrder = m_pSettingsStore->GetLongParameter( LP_LM_MAX_ORDER );
 
   while(context.order > m_iMaxOrder) {
     context.head = context.head->vine;
diff --git a/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.h b/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.h
index 5b1f130..af3b9cb 100644
--- a/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.h
+++ b/Src/DasherCore/LanguageModelling/JapaneseLanguageModel.h
@@ -21,7 +21,7 @@ namespace Dasher {
   /// \{
   class CJapaneseLanguageModel:public CLanguageModel, private NoClones {
   public:
-    CJapaneseLanguageModel(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, const CAlphInfo *pAlph);
+    CJapaneseLanguageModel(CSettingsStore * pSettingsStore, const CAlphInfo *pAlph);
 
     virtual ~ CJapaneseLanguageModel();
 
@@ -37,6 +37,7 @@ namespace Dasher {
     void dump();
 
   private:
+    CSettingsStore *m_pSettingsStore;
 
     class CJaPPMnode {
     public:
diff --git a/Src/DasherCore/LanguageModelling/MixtureLanguageModel.h b/Src/DasherCore/LanguageModelling/MixtureLanguageModel.h
index 671992c..129c7d1 100644
--- a/Src/DasherCore/LanguageModelling/MixtureLanguageModel.h
+++ b/Src/DasherCore/LanguageModelling/MixtureLanguageModel.h
@@ -23,19 +23,20 @@ namespace Dasher {
 
   /// \ingroup LM
   /// \{
-  class CMixtureLanguageModel:public CLanguageModel, public CDasherComponent {
+  class CMixtureLanguageModel:public CLanguageModel, protected CSettingsUser {
   public:
 
     /////////////////////////////////////////////////////////////////////////////
 
-    CMixtureLanguageModel(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap):CLanguageModel(pAlph->GetNumberTextSymbols()), CDasherComponent(pEventHandler, pSettingsStore) {
+    CMixtureLanguageModel(CSettingsUser *pCreator, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap)
+    : CLanguageModel(pAlph->GetNumberTextSymbols()), CSettingsUser(pCreator) {
 
       //      std::cout << m_pAlphabet << std::endl;
 
       NextContext = 0;
 
-      lma = new CPPMLanguageModel(m_pEventHandler, m_pSettingsStore, m_iNumSyms);
-      lmb = new CDictLanguageModel(m_pEventHandler, m_pSettingsStore, pAlph, pAlphMap);
+      lma = new CPPMLanguageModel(this, m_iNumSyms);
+      lmb = new CDictLanguageModel(this, pAlph, pAlphMap);
 
     };
 
diff --git a/Src/DasherCore/LanguageModelling/PPMLanguageModel.cpp b/Src/DasherCore/LanguageModelling/PPMLanguageModel.cpp
index b520d04..6435bf0 100644
--- a/Src/DasherCore/LanguageModelling/PPMLanguageModel.cpp
+++ b/Src/DasherCore/LanguageModelling/PPMLanguageModel.cpp
@@ -30,8 +30,8 @@ static char THIS_FILE[] = __FILE__;
 
 /////////////////////////////////////////////////////////////////////
 
-CAbstractPPM::CAbstractPPM(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, int iNumSyms, CPPMnode *pRoot, int iMaxOrder)
-: CLanguageModel(iNumSyms), CDasherComponent(pEventHandler, pSettingsStore), m_pRoot(pRoot), m_iMaxOrder(iMaxOrder), bUpdateExclusion( GetLongParameter(LP_LM_UPDATE_EXCLUSION)!=0 ), m_ContextAlloc(1024) {
+CAbstractPPM::CAbstractPPM(CSettingsUser *pCreator, int iNumSyms, CPPMnode *pRoot, int iMaxOrder)
+: CSettingsUser(pCreator), CLanguageModel(iNumSyms), m_pRoot(pRoot), m_iMaxOrder(iMaxOrder<0 ? GetLongParameter(LP_LM_MAX_ORDER) : iMaxOrder), bUpdateExclusion( GetLongParameter(LP_LM_UPDATE_EXCLUSION)!=0 ), m_ContextAlloc(1024) {
   m_pRootContext = m_ContextAlloc.Alloc();
   m_pRootContext->head = m_pRoot;
   m_pRootContext->order = 0;
@@ -444,8 +444,8 @@ CAbstractPPM::CPPMnode * CAbstractPPM::AddSymbolToNode(CPPMnode *pNode, symbol s
   return pReturn;
 }
 
-CPPMLanguageModel::CPPMLanguageModel(CEventHandler *pEvt, CSettingsStore *sets, int iNumSyms)
-: CAbstractPPM(pEvt, sets, iNumSyms, new CPPMnode(-1), sets->GetLongParameter(LP_LM_MAX_ORDER)), NodesAllocated(0), m_NodeAlloc(8192) {
+CPPMLanguageModel::CPPMLanguageModel(CSettingsUser *pCreator, int iNumSyms)
+: CAbstractPPM(pCreator, iNumSyms, new CPPMnode(-1)), NodesAllocated(0), m_NodeAlloc(8192) {
 }
 
 CAbstractPPM::CPPMnode *CPPMLanguageModel::makeNode(int sym) {
diff --git a/Src/DasherCore/LanguageModelling/PPMLanguageModel.h b/Src/DasherCore/LanguageModelling/PPMLanguageModel.h
index 10d0fcc..f08db06 100644
--- a/Src/DasherCore/LanguageModelling/PPMLanguageModel.h
+++ b/Src/DasherCore/LanguageModelling/PPMLanguageModel.h
@@ -13,7 +13,7 @@
 #include "../../Common/Allocators/PooledAlloc.h"
 
 #include "LanguageModel.h"
-#include "../DasherComponent.h"
+#include "../SettingsStore.h"
 #include "stdlib.h"
 #include <vector>
 #include <fstream>
@@ -34,7 +34,7 @@ namespace Dasher {
   /// Subclasses must implement CLanguageModel::GetProbs and a makeNode() method (perhaps
   /// using a pooled allocator).
   ///
-  class CAbstractPPM :public CLanguageModel, public CDasherComponent, private NoClones {
+  class CAbstractPPM :public CLanguageModel, protected CSettingsUser, private NoClones {
   protected:
     class ChildIterator;
     class CPPMnode {
@@ -100,7 +100,8 @@ namespace Dasher {
     ///Makes a new node, of whatever kind (subclass of CPPMnode, perhaps with extra info)
     /// is required by the subclass, for the specified symbol. (Initial count will be 1.)
     virtual CPPMnode *makeNode(int sym)=0;
-    CAbstractPPM(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, int iNumSyms, CPPMnode *pRoot, int iMaxOrder);
+    /// \param iMaxOrder max order of model; anything <0 means to use LP_LM_MAX_ORDER.
+    CAbstractPPM(CSettingsUser *pCreator, int iNumSyms, CPPMnode *pRoot, int iMaxOrder=-1);
     
     void dumpSymbol(symbol sym);
     void dumpString(char *str, int pos, int len);
@@ -139,7 +140,7 @@ namespace Dasher {
   /// max order from LP_LM_MAX_ORDER.
   class CPPMLanguageModel : public CAbstractPPM {
   public:
-    CPPMLanguageModel(CEventHandler *pEventHandler, CSettingsStore *pSets, int iNumSyms);
+    CPPMLanguageModel(CSettingsUser *pCreator, int iNumSyms);
     virtual void GetProbs(Context context, std::vector < unsigned int >&Probs, int norm, int iUniform) const;
   protected:
     /// Makes a standard CPPMnode, but using a pooled allocator (m_NodeAlloc) - faster!
diff --git a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp
index c401278..56675f2 100644
--- a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp
+++ b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.cpp
@@ -33,8 +33,8 @@ static char THIS_FILE[] = __FILE__;
 
 /////////////////////////////////////////////////////////////////////
 
-CPPMPYLanguageModel::CPPMPYLanguageModel(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, int iNumCHsyms, int iNumPYsyms)
-  :CAbstractPPM(pEventHandler, pSettingsStore, iNumCHsyms, new CPPMPYnode(-1), 2), NodesAllocated(0), m_NodeAlloc(8192), m_iNumPYsyms(iNumPYsyms) {
+CPPMPYLanguageModel::CPPMPYLanguageModel(CSettingsUser *pCreator, int iNumCHsyms, int iNumPYsyms)
+  :CAbstractPPM(pCreator, iNumCHsyms, new CPPMPYnode(-1), 2), NodesAllocated(0), m_NodeAlloc(8192), m_iNumPYsyms(iNumPYsyms) {
 }
 
 /////////////////////////////////////////////////////////////////////
diff --git a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h
index 5252811..6389f53 100644
--- a/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h
+++ b/Src/DasherCore/LanguageModelling/PPMPYLanguageModel.h
@@ -44,7 +44,7 @@ namespace Dasher {
     /// i.e. from which contexts are formed; this is passed to the CAbstractPPM superclass.
     /// \param iNumPYSyms number of pinyin phonemes, i.e. which we generate probabilities for in GetProbs
     /// based (only) on the preceding _Chinese_ symbols.
-    CPPMPYLanguageModel(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, int iNumCHsyms, int iNumPYsyms);
+    CPPMPYLanguageModel(CSettingsUser *pCreator, int iNumCHsyms, int iNumPYsyms);
 
     ///Learns a pinyin symbol in the specified context, but does not move the context on.
     void LearnPYSymbol(Context context, int Symbol);
diff --git a/Src/DasherCore/LanguageModelling/WordLanguageModel.cpp b/Src/DasherCore/LanguageModelling/WordLanguageModel.cpp
index fedf503..32529af 100644
--- a/Src/DasherCore/LanguageModelling/WordLanguageModel.cpp
+++ b/Src/DasherCore/LanguageModelling/WordLanguageModel.cpp
@@ -121,9 +121,9 @@ CWordLanguageModel::CWordnode * CWordLanguageModel::AddSymbolToNode(CWordnode *p
 // CWordLanguageModel defs
 /////////////////////////////////////////////////////////////////////
 
-CWordLanguageModel::CWordLanguageModel(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, 
+CWordLanguageModel::CWordLanguageModel(CSettingsUser *pCreator, 
 				       const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap)
-  :CLanguageModel(pAlph->GetNumberTextSymbols()), CDasherComponent(pEventHandler, pSettingsStore), m_pAlphMap(pAlphMap), m_iSpaceSymbol(pAlph->GetSpaceSymbol()), NodesAllocated(0), 
+  :CLanguageModel(pAlph->GetNumberTextSymbols()), CSettingsUser(pCreator), m_pAlphMap(pAlphMap), m_iSpaceSymbol(pAlph->GetSpaceSymbol()), NodesAllocated(0), 
    max_order(2), m_NodeAlloc(8192), m_ContextAlloc(1024) {
   
   // Construct a root node for the trie
@@ -134,7 +134,7 @@ CWordLanguageModel::CWordLanguageModel(Dasher::CEventHandler *pEventHandler, CSe
 
   // Create a spelling model
 
-  pSpellingModel = new CPPMLanguageModel(m_pEventHandler, m_pSettingsStore, m_iNumSyms);
+  pSpellingModel = new CPPMLanguageModel(this, m_iNumSyms);
 
   // Construct a root context
   
diff --git a/Src/DasherCore/LanguageModelling/WordLanguageModel.h b/Src/DasherCore/LanguageModelling/WordLanguageModel.h
index 9a954a4..df2923f 100644
--- a/Src/DasherCore/LanguageModelling/WordLanguageModel.h
+++ b/Src/DasherCore/LanguageModelling/WordLanguageModel.h
@@ -14,7 +14,7 @@
 #include "../../Common/NoClones.h"
 #include "../../Common/Allocators/PooledAlloc.h"
 #include "PPMLanguageModel.h"
-#include "../DasherComponent.h"
+#include "../SettingsStore.h"
 #include "../Alphabet/AlphInfo.h"
 #include "../Alphabet/AlphabetMap.h"
 
@@ -34,9 +34,9 @@ namespace Dasher {
   ///
   /// Language model using words
   ///
-  class CWordLanguageModel:public CLanguageModel, public CDasherComponent {
+  class CWordLanguageModel:public CLanguageModel, protected CSettingsUser {
   public:
-    CWordLanguageModel(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap);
+    CWordLanguageModel(CSettingsUser *pCreator, const CAlphInfo *pAlph, const CAlphabetMap *pAlphMap);
       virtual ~ CWordLanguageModel();
 
     Context CreateEmptyContext();
@@ -49,7 +49,7 @@ namespace Dasher {
     virtual void LearnSymbol(Context context, int Symbol);
 
   private:
-
+    
       class CWordnode {
     public:
       CWordnode * find_symbol(int sym)const;
diff --git a/Src/DasherCore/Makefile.am b/Src/DasherCore/Makefile.am
index 32e6b18..5ccee47 100644
--- a/Src/DasherCore/Makefile.am
+++ b/Src/DasherCore/Makefile.am
@@ -4,6 +4,7 @@ noinst_LIBRARIES = libdashercore.a libdasherprefs.a
 
 libdasherprefs_a_SOURCES = \
 		Parameters.h \
+		Parameters.cpp \
 		SettingsStore.cpp \
 		SettingsStore.h 
 
@@ -49,13 +50,13 @@ libdashercore_a_SOURCES = \
 		ConvertingAlphMgr.h \
 		DasherButtons.cpp \
 		DasherButtons.h \
-		DasherComponent.cpp \
-		DasherComponent.h \
 		DasherGameMode.cpp \
 		DasherGameMode.h \
 		DasherInput.h \
 		DasherInterfaceBase.cpp \
 		DasherInterfaceBase.h \
+		DashIntfSettings.cpp \
+		DashIntfSettings.h \
 		DashIntfScreenMsgs.h \
 		DashIntfScreenMsgs.cpp \
 		DasherModel.cpp \
@@ -76,8 +77,6 @@ libdashercore_a_SOURCES = \
 		DynamicFilter.h \
 		DynamicFilter.cpp \
 		Event.h \
-		EventHandler.cpp \
-		EventHandler.h \
 		FileLogger.cpp \
 		FileLogger.h \
 		FrameRate.h \
@@ -101,6 +100,7 @@ libdashercore_a_SOURCES = \
 		NodeManager.h \
 		ExpansionPolicy.cpp \
 		ExpansionPolicy.h \
+		Observable.h \
 		OneButtonDynamicFilter.cpp \
 		OneButtonDynamicFilter.h \
 		OneButtonFilter.cpp \
diff --git a/Src/DasherCore/MandarinAlphMgr.cpp b/Src/DasherCore/MandarinAlphMgr.cpp
index ade9e6a..a4c13af 100644
--- a/Src/DasherCore/MandarinAlphMgr.cpp
+++ b/Src/DasherCore/MandarinAlphMgr.cpp
@@ -25,7 +25,7 @@
 #include "DasherInterfaceBase.h"
 #include "DasherNode.h"
 #include "Event.h"
-#include "EventHandler.h"
+#include "Observable.h"
 #include "NodeCreationManager.h"
 
 
@@ -46,8 +46,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CMandarinAlphMgr::CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, const CAlphIO *pAlphIO)
-  : CAlphabetManager(pInterface, pNCManager, pAlphabet),
+CMandarinAlphMgr::CMandarinAlphMgr(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, const CAlphIO *pAlphIO)
+  : CAlphabetManager(pCreator, pInterface, pNCManager, pAlphabet),
     m_pConversionsBySymbol(new set<symbol>[GetAlphabet()->GetNumberTextSymbols()+1]) {
   DASHER_ASSERT(pAlphabet->m_iConversionID==2);
       
@@ -126,10 +126,10 @@ CMandarinAlphMgr::~CMandarinAlphMgr() {
   delete[] m_pConversionsBySymbol;
 }
 
-void CMandarinAlphMgr::CreateLanguageModel(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore) {
+void CMandarinAlphMgr::CreateLanguageModel() {
   //std::cout<<"CHALphabet size "<< pCHAlphabet->GetNumberTextSymbols(); [7603]
   //std::cout<<"Setting PPMPY model"<<std::endl;
-  m_pLanguageModel = new CPPMPYLanguageModel(pEventHandler, pSettingsStore, m_CHtext.size()-1, m_pAlphabet->GetNumberTextSymbols());
+  m_pLanguageModel = new CPPMPYLanguageModel(this, m_CHtext.size()-1, m_pAlphabet->GetNumberTextSymbols());
 }
 
 CTrainer *CMandarinAlphMgr::GetTrainer() {
@@ -261,7 +261,7 @@ bool CMandarinAlphMgr::CConvRoot::isInGroup(const SGroupInfo *pGroup) {
 
 void CMandarinAlphMgr::CConvRoot::SetFlag(int iFlag, bool bValue) {
   if (iFlag==NF_COMMITTED && bValue && !GetFlag(NF_COMMITTED)
-      && !GetFlag(NF_GAME) && mgr()->m_pNCManager->GetBoolParameter(BP_LM_ADAPTIVE)) {
+      && !GetFlag(NF_GAME) && mgr()->GetBoolParameter(BP_LM_ADAPTIVE)) {
     //CConvRoot's context is the same as parent's context (no symbol yet!),
     // i.e. is the context in which the pinyin was predicted.
     static_cast<CPPMPYLanguageModel *>(mgr()->m_pLanguageModel)->LearnPYSymbol(iContext, m_pySym);
@@ -278,8 +278,8 @@ void CMandarinAlphMgr::GetConversions(std::vector<pair<symbol,unsigned int> > &v
   //ACL I think it's a good idea to keep those in a consistent order - symbol order will do nicely
   sort(vChildren.begin(),vChildren.end());
 
-  const uint64 iNorm(m_pNCManager->GetLongParameter(LP_NORMALIZATION));
-  const unsigned int uniform((m_pNCManager->GetLongParameter(LP_UNIFORM)*iNorm)/1000);
+  const uint64 iNorm(GetLongParameter(LP_NORMALIZATION));
+  const unsigned int uniform((GetLongParameter(LP_UNIFORM)*iNorm)/1000);
     
   //ACL pass in iNorm and uniform directly - GetPartProbs distributes the last param between
   // however elements there are in vChildren...
diff --git a/Src/DasherCore/MandarinAlphMgr.h b/Src/DasherCore/MandarinAlphMgr.h
index 28dff2a..7ec9bb1 100644
--- a/Src/DasherCore/MandarinAlphMgr.h
+++ b/Src/DasherCore/MandarinAlphMgr.h
@@ -66,11 +66,11 @@ namespace Dasher {
     /// together (i.e. by hashing on text). Hence, it is not possible to call makeMap() on
     /// the CHAlphabet (this requires the text attributes to be all different), so we rehash here.
     /// \param pAlphabetMap mapping from text to symbol# of the PY alphabet; used for training files.
-    CMandarinAlphMgr(CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, const CAlphIO *pAlphIO);
+    CMandarinAlphMgr(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, CNodeCreationManager *pNCManager, const CAlphInfo *pAlphabet, const CAlphIO *pAlphIO);
     ~CMandarinAlphMgr();
     
     ///WZ: Mandarin Dasher Change. Sets language model to PPMPY.
-    void CreateLanguageModel(CEventHandler *pEventHandler, CSettingsStore *pSets);
+    void CreateLanguageModel();
     ///ACL: returns a MandarinTrainer too.
     CTrainer *GetTrainer();
     
diff --git a/Src/DasherCore/NodeCreationManager.cpp b/Src/DasherCore/NodeCreationManager.cpp
index adf227e..5844e33 100644
--- a/Src/DasherCore/NodeCreationManager.cpp
+++ b/Src/DasherCore/NodeCreationManager.cpp
@@ -4,7 +4,7 @@
 #include "MandarinAlphMgr.h"
 #include "ConvertingAlphMgr.h"
 #include "ControlManager.h"
-#include "EventHandler.h"
+#include "Observable.h"
 
 #include <string.h>
 
@@ -36,17 +36,16 @@ private:
   string m_strDisplay;
 };
 
-CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterface,
-                                           Dasher::CEventHandler *pEventHandler, 
-                                           CSettingsStore *pSettingsStore,
-                                           const Dasher::CAlphIO *pAlphIO) : CDasherComponent(pEventHandler, pSettingsStore),
+CNodeCreationManager::CNodeCreationManager(CSettingsUser *pCreateFrom,
+                                           Dasher::CDasherInterfaceBase *pInterface,
+                                           const Dasher::CAlphIO *pAlphIO) : CSettingsUserObserver(pCreateFrom),
   m_pInterface(pInterface), m_pControlManager(NULL), m_pScreen(NULL) {
 
-  const Dasher::CAlphInfo *pAlphInfo(pAlphIO->GetInfo(pSettingsStore->GetStringParameter(SP_ALPHABET_ID)));
+  const Dasher::CAlphInfo *pAlphInfo(pAlphIO->GetInfo(GetStringParameter(SP_ALPHABET_ID)));
   
-  pSettingsStore->SetStringParameter(SP_GAME_TEXT_FILE, pAlphInfo->GetGameModeFile());
+  SetStringParameter(SP_GAME_TEXT_FILE, pAlphInfo->GetGameModeFile());
   
-  pSettingsStore->SetStringParameter(SP_DEFAULT_COLOUR_ID, pAlphInfo->GetPalette());
+  SetStringParameter(SP_DEFAULT_COLOUR_ID, pAlphInfo->GetPalette());
   
   // --
   
@@ -55,7 +54,7 @@ CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterf
       //TODO: Error reporting here
       //fall through to
     case 0: // No conversion required
-      m_pAlphabetManager = new CAlphabetManager(pInterface, this, pAlphInfo);
+      m_pAlphabetManager = new CAlphabetManager(this, pInterface, this, pAlphInfo);
       break;      
 #ifdef JAPANESE
     case 1: {
@@ -74,12 +73,12 @@ CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterf
     case 2:
       //Mandarin Dasher!
       //(ACL) Modify AlphabetManager for Mandarin Dasher
-      m_pAlphabetManager = new CMandarinAlphMgr(pInterface, this, pAlphInfo, pAlphIO);
+      m_pAlphabetManager = new CMandarinAlphMgr(this, pInterface, this, pAlphInfo, pAlphIO);
       break;
   }
   //all other configuration changes, etc., that might be necessary for a particular conversion mode,
   // are implemented by AlphabetManager subclasses overriding the following two methods:
-  m_pAlphabetManager->CreateLanguageModel(pEventHandler, pSettingsStore);
+  m_pAlphabetManager->CreateLanguageModel();
   m_pTrainer = m_pAlphabetManager->GetTrainer();
     
   if (!pAlphInfo->GetTrainingFile().empty()) {
@@ -123,8 +122,8 @@ CNodeCreationManager::CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterf
   }
 #endif
 
-  HandleEvent(&CParameterNotificationEvent(LP_ORIENTATION));
-  HandleEvent(&CParameterNotificationEvent(BP_CONTROL_MODE));
+  HandleEvent(LP_ORIENTATION);
+  HandleEvent(BP_CONTROL_MODE);
 }
 
 CNodeCreationManager::~CNodeCreationManager() {
@@ -141,34 +140,31 @@ void CNodeCreationManager::ChangeScreen(CDasherScreen *pScreen) {
   if (m_pControlManager) m_pControlManager->MakeLabels(pScreen);
 }
 
-void CNodeCreationManager::HandleEvent(CEvent *pEvent) {
-  if (pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    switch (static_cast<CParameterNotificationEvent *>(pEvent)->m_iParameter) {
-      case BP_CONTROL_MODE: {
-        delete m_pControlManager;
-        const unsigned long iNorm(GetLongParameter(LP_NORMALIZATION));
-        unsigned long iControlSpace;
-        if (GetBoolParameter(BP_CONTROL_MODE)) {
-          m_pControlManager = new CControlManager(m_pEventHandler, m_pSettingsStore, this, m_pInterface);
-          if (m_pScreen) m_pControlManager->MakeLabels(m_pScreen);
-          iControlSpace = iNorm / 20;
-        } else {
-          m_pControlManager = NULL;
-          iControlSpace = 0;
-        }
-        m_iAlphNorm = iNorm-iControlSpace;
-        break;
-      }
-      case LP_ORIENTATION: {
-        const long iOverride(GetLongParameter(LP_ORIENTATION));
-        SetLongParameter(LP_REAL_ORIENTATION,
-                         iOverride == Dasher::Opts::AlphabetDefault ? GetAlphabet()->GetOrientation() : iOverride);
+void CNodeCreationManager::HandleEvent(int iParameter) {
+  switch (iParameter) {
+    case BP_CONTROL_MODE: {
+      delete m_pControlManager;
+      const unsigned long iNorm(GetLongParameter(LP_NORMALIZATION));
+      unsigned long iControlSpace;
+      if (GetBoolParameter(BP_CONTROL_MODE)) {
+        m_pControlManager = new CControlManager(this, this, m_pInterface);
+        if (m_pScreen) m_pControlManager->MakeLabels(m_pScreen);
+        iControlSpace = iNorm / 20;
+      } else {
+        m_pControlManager = NULL;
+        iControlSpace = 0;
       }
+      m_iAlphNorm = iNorm-iControlSpace;
+      break;
+    }
+    case LP_ORIENTATION: {
+      const long iOverride(GetLongParameter(LP_ORIENTATION));
+      SetLongParameter(LP_REAL_ORIENTATION,
+                       iOverride == Dasher::Opts::AlphabetDefault ? GetAlphabet()->GetOrientation() : iOverride);
     }
   }
 }
 
-
 void CNodeCreationManager::AddExtras(CDasherNode *pParent) {
   //control mode:
   DASHER_ASSERT(pParent->GetChildren().back()->Hbnd() == m_iAlphNorm);
diff --git a/Src/DasherCore/NodeCreationManager.h b/Src/DasherCore/NodeCreationManager.h
index ed47cce..597a049 100644
--- a/Src/DasherCore/NodeCreationManager.h
+++ b/Src/DasherCore/NodeCreationManager.h
@@ -6,10 +6,10 @@
 #include "AlphabetManager.h"
 #include "ConversionManager.h"
 #include "ControlManager.h"
-#include "DasherComponent.h"
 #include "LanguageModelling/LanguageModel.h"
 #include "Trainer.h"
 #include "Event.h"
+#include "SettingsStore.h"
 
 #include <string>
 #include <vector>
@@ -23,11 +23,10 @@ namespace Dasher {
 //TODO why is CNodeCreationManager _not_ in namespace Dasher?!?!
 /// \ingroup Model
 /// @{
-class CNodeCreationManager : public Dasher::CDasherComponent {
+class CNodeCreationManager : public Dasher::CSettingsUserObserver {
  public:
-  CNodeCreationManager(Dasher::CDasherInterfaceBase *pInterface,
-                       Dasher::CEventHandler * pEventHandler,
-                       CSettingsStore * pSettingsStore,
+  CNodeCreationManager(Dasher::CSettingsUser *pCreateFrom,
+                       Dasher::CDasherInterfaceBase *pInterface,
                        const Dasher::CAlphIO *pAlphIO);
   ~CNodeCreationManager();
   
@@ -35,7 +34,7 @@ class CNodeCreationManager : public Dasher::CDasherComponent {
   void ChangeScreen(Dasher::CDasherScreen *pScreen);
   
   //we watch for changes to BP_CONTROL_MODE and create the Control Manager lazily
-  void HandleEvent(Dasher::CEvent *pEvent);
+  void HandleEvent(int iParameter);
   ///
   /// Get a root node of a particular type
   ///
diff --git a/Src/DasherCore/Observable.h b/Src/DasherCore/Observable.h
new file mode 100644
index 0000000..d965d19
--- /dev/null
+++ b/Src/DasherCore/Observable.h
@@ -0,0 +1,91 @@
+#ifndef __eventhandler_h__
+#define __eventhandler_h__
+
+#include <deque>
+#include <algorithm>
+
+template <typename  T> class Observable;
+
+///Thing that listens to events - parameterized by the type of event.
+template <typename T> class Observer {
+public:
+  ///Called to indicate an event has occurred! Subclasses must implement.
+  virtual void HandleEvent(T evt)=0;
+};
+
+///An Event handler for a single type of event: maintains a list of listeners,
+/// allows listeners to (un/)register, and allows dispatching of events to all
+/// listeners.
+template <typename T> class Observable {
+public:
+  void Register(Observer<T> *pLstnr, bool bLast=false);
+  void Unregister(Observer<T> *pLstnr);
+protected:
+  void DispatchEvent(T t);
+private:
+  typedef typename std::deque< Observer<T>* > ListenerList;
+  typedef typename ListenerList::iterator L_it;
+  ListenerList m_vListeners;
+  int m_iInHandler;
+};
+
+///Utility class for Observers which register with an Observable at construction
+/// and deregister at destruction. (I.e. which are strictly shorter-lived, than the
+/// Observable they listen to!)
+template <typename T> class TransientObserver : public Observer<T> {
+public:
+  TransientObserver(Observable<T> *pObservable) : m_pEventHandler(pObservable) {
+    m_pEventHandler->Register(this);
+  }
+  virtual ~TransientObserver() {
+    m_pEventHandler->Unregister(this);
+  }
+protected:
+  Observable<T> *m_pEventHandler;
+};
+
+template <typename T> void Observable<T>::Register(Observer<T> *pListener, bool bLast) {
+  L_it it = std::find(m_vListeners.begin(), m_vListeners.end(), pListener);
+  if (it != m_vListeners.end()) {
+    //already in list...in ok place?
+    if (it == (bLast ? m_vListeners.end() : m_vListeners.begin())) return;
+    //put it first or last, these are the only places we can guarantee satisfy the constraint of bLast
+    if (m_iInHandler) *it=NULL; else m_vListeners.erase(it);
+  }
+  if (bLast) m_vListeners.push_back(pListener); else m_vListeners.insert(m_vListeners.begin(),pListener);
+}
+
+template <typename T> void Observable<T>::Unregister(Observer<T> *pListener) {
+  L_it it = std::find(m_vListeners.begin(), m_vListeners.end(), pListener);
+  if (it==m_vListeners.end()) return;
+  if (m_iInHandler) {
+    //remove listener, but leave behind its slot, so as not to upset the in-progress iteration
+    *it=NULL;
+  } else {
+    m_vListeners.erase(it);
+  }
+}
+
+template <typename T> void Observable<T>::DispatchEvent(T evt) {
+  
+  // We may end up here recursively, so keep track of how far down we
+  // are, and only permit new handlers to be registered after all
+  // messages are processed.
+  
+  // An alternative approach would be a message queue - this might actually be a bit more sensible
+  ++m_iInHandler;
+  // Loop through components and notify them of the event
+  for(L_it I=m_vListeners.begin(), E=m_vListeners.end(); I!=E; I++) {
+    if (*I) //don't dispatch to NULLs (slots remaining from listeners removed during iteration)
+      (*I)->HandleEvent(evt);
+  }
+  
+  --m_iInHandler;
+  
+  if(m_iInHandler == 0) {
+    for (L_it it=m_vListeners.begin(); it!=m_vListeners.end(); it++)
+      if (!(*it)) //slot remaining from listener removed during iteration. Shuffle up...
+        m_vListeners.erase(it--);
+  }
+}
+#endif
diff --git a/Src/DasherCore/OneButtonDynamicFilter.cpp b/Src/DasherCore/OneButtonDynamicFilter.cpp
index 348533d..b636e7f 100644
--- a/Src/DasherCore/OneButtonDynamicFilter.cpp
+++ b/Src/DasherCore/OneButtonDynamicFilter.cpp
@@ -40,8 +40,8 @@ static SModuleSettings sSettings[] = {
   {LP_DYNAMIC_SPEED_DEC, T_LONG, 1, 99, 1, 1, _("Percentage by which to decrease speed upon reverse")}
 };
 
-COneButtonDynamicFilter::COneButtonDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface)
-  : CButtonMultiPress(pEventHandler, pSettingsStore, pInterface, 6, _("One Button Dynamic Mode")) {
+COneButtonDynamicFilter::COneButtonDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+  : CButtonMultiPress(pCreator, pInterface, 6, _("One Button Dynamic Mode")) {
   m_iTarget = 0;
 
   m_iTargetX = new int[2];
diff --git a/Src/DasherCore/OneButtonDynamicFilter.h b/Src/DasherCore/OneButtonDynamicFilter.h
index 87c1104..768b4fd 100644
--- a/Src/DasherCore/OneButtonDynamicFilter.h
+++ b/Src/DasherCore/OneButtonDynamicFilter.h
@@ -28,7 +28,7 @@
 namespace Dasher {
 class COneButtonDynamicFilter : public CButtonMultiPress {
  public:
-  COneButtonDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface);
+  COneButtonDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface);
   ~COneButtonDynamicFilter();
 
   virtual bool DecorateView(CDasherView *pView, CDasherInput *pInput);
diff --git a/Src/DasherCore/OneButtonFilter.cpp b/Src/DasherCore/OneButtonFilter.cpp
index 29a7675..a3bde6d 100644
--- a/Src/DasherCore/OneButtonFilter.cpp
+++ b/Src/DasherCore/OneButtonFilter.cpp
@@ -13,8 +13,8 @@ static SModuleSettings sSettings[] = {
   {LP_DYNAMIC_BUTTON_LAG, T_LONG, 0, 1000, 1, 25, _("Lag before user actually pushes button (ms)")},
 };
 
-COneButtonFilter::COneButtonFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface)
-  : CInputFilter(pEventHandler, pSettingsStore, pInterface, 9, "Static One Button Mode") {
+COneButtonFilter::COneButtonFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+  : CInputFilter(pInterface, 9, "Static One Button Mode"), CSettingsUser(pCreator) {
 
   bStarted = 0;
   iLocation = 0;
diff --git a/Src/DasherCore/OneButtonFilter.h b/Src/DasherCore/OneButtonFilter.h
index 4f64964..7fedb79 100644
--- a/Src/DasherCore/OneButtonFilter.h
+++ b/Src/DasherCore/OneButtonFilter.h
@@ -2,13 +2,13 @@
 #define __ONE_BUTTON_FILTER_H__
 
 #include "InputFilter.h"
-
+#include "SettingsStore.h"
 namespace Dasher {
 /// \ingroup InputFilter
 /// @{
-class COneButtonFilter : public CInputFilter {
+class COneButtonFilter : public CInputFilter, private CSettingsUser {
  public:
-  COneButtonFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface);
+  COneButtonFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface);
   ~COneButtonFilter();
 
   virtual bool DecorateView(CDasherView *pView, CDasherInput *pInput);
diff --git a/Src/DasherCore/OneDimensionalFilter.cpp b/Src/DasherCore/OneDimensionalFilter.cpp
index 2085e2d..18f3392 100644
--- a/Src/DasherCore/OneDimensionalFilter.cpp
+++ b/Src/DasherCore/OneDimensionalFilter.cpp
@@ -4,12 +4,12 @@
 
 using namespace Dasher;
 
-/*COneDimensionalFilter::COneDimensionalFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, CDasherModel *m_pDasherModel)
-  : COneDimensionalFilter(pEventHandler, pSettingsStore, pInterface, m_pDasherModel, 4, _("One Dimensional Mode")) {
+/*COneDimensionalFilter::COneDimensionalFilter(CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, CDasherModel *m_pDasherModel)
+  : COneDimensionalFilter(pSettingsStore, pInterface, m_pDasherModel, 4, _("One Dimensional Mode")) {
 }*/
 
-COneDimensionalFilter::COneDimensionalFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
-  : CDefaultFilter(pEventHandler, pSettingsStore, pInterface, iID, szName), forwardmax(GetLongParameter(LP_MAX_Y)/2.5) {
+COneDimensionalFilter::COneDimensionalFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
+  : CDefaultFilter(pCreator, pInterface, iID, szName), forwardmax(GetLongParameter(LP_MAX_Y)/2.5) {
 }
 
 void COneDimensionalFilter::ApplyTransform(myint &iDasherX, myint &iDasherY, CDasherView *pView) {
@@ -78,7 +78,7 @@ CStartHandler *COneDimensionalFilter::MakeStartHandler() {
   if (GetBoolParameter(BP_CIRCLE_START)) {
     class C1DCircleStartHandler : public CCircleStartHandler {
     public:
-      C1DCircleStartHandler(CEventHandler *pEvtH, CSettingsStore *pSets, COneDimensionalFilter *f) : CCircleStartHandler(pEvtH, pSets, f->m_pInterface), filter(f) {
+      C1DCircleStartHandler(COneDimensionalFilter *f) : CCircleStartHandler(f, f->m_pInterface), filter(f) {
       }
       void ComputeScreenLoc(CDasherView *pView) {
         if (m_iScreenRadius!=-1) return;
@@ -90,19 +90,18 @@ CStartHandler *COneDimensionalFilter::MakeStartHandler() {
           pView->Dasher2Screen(GetLongParameter(LP_OX)-filter->forwardmax+rad, GetLongParameter(LP_OY),m_screenCircleCenter.x, m_screenCircleCenter.y);
         } 
       }
-      void HandleEvent(CEvent *pEvent) {
-        if (pEvent->m_iEventType == EV_PARAM_NOTIFY &&
-            ((CParameterNotificationEvent *)pEvent)->m_iParameter==BP_DASHER_PAUSED) {
+      void HandleEvent(int iParameter) {
+        if (iParameter==BP_DASHER_PAUSED) {
           //circle needs to move for pause/unpause; setting radius to -1 causes
           // next call to DecorateView or Timer to re-call ComputeScreenLoc.
           m_iScreenRadius=-1;
         }
-        CCircleStartHandler::HandleEvent(pEvent);
+        CCircleStartHandler::HandleEvent(iParameter);
       }
     private:
       const COneDimensionalFilter *filter;
     };
-    return new C1DCircleStartHandler(m_pEventHandler,m_pSettingsStore,this);
+    return new C1DCircleStartHandler(this);
   }
   return CDefaultFilter::MakeStartHandler();
 }
diff --git a/Src/DasherCore/OneDimensionalFilter.h b/Src/DasherCore/OneDimensionalFilter.h
index dcbdf5b..1567690 100644
--- a/Src/DasherCore/OneDimensionalFilter.h
+++ b/Src/DasherCore/OneDimensionalFilter.h
@@ -8,8 +8,8 @@
 namespace Dasher {
 class COneDimensionalFilter : public CDefaultFilter {
  public:
-//  COneDimensionalFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, CDasherModel *m_pDasherModel);
-  COneDimensionalFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface,  ModuleID_t iID = 4, const char *szName = _("One Dimensional Mode"));
+//  COneDimensionalFilter(CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, CDasherModel *m_pDasherModel);
+  COneDimensionalFilter(CSettingsUser *pCreateFrom, CDasherInterfaceBase *pInterface,  ModuleID_t iID = 4, const char *szName = _("One Dimensional Mode"));
   ///Override to remove DefaultFilters BP_REMAP_XTREME, BP_AUTOCALIBRATE, LP_OFFSET
   bool GetSettings(SModuleSettings **pSettings, int *iCount);
  protected:
diff --git a/Src/DasherCore/Parameters.cpp b/Src/DasherCore/Parameters.cpp
new file mode 100644
index 0000000..227c990
--- /dev/null
+++ b/Src/DasherCore/Parameters.cpp
@@ -0,0 +1,221 @@
+#include "Parameters.h"
+
+namespace Dasher{
+  namespace Settings {
+    
+// The important thing here is that these are in the same order
+// as the enum declarations (could add check in class that enforces this instead)
+const bp_table boolparamtable[] = {
+  {BP_DRAW_MOUSE_LINE, "DrawMouseLine", PERS, true, "Draw Mouse Line"},
+  {BP_DRAW_MOUSE, "DrawMouse", PERS, false, "Draw Mouse Position"},
+  {BP_CURVE_MOUSE_LINE, "CurveMouseLine", PERS, false, "Curve mouse line according to screen nonlinearity"},
+#ifdef WITH_MAEMO
+  {BP_SHOW_SLIDER, "ShowSpeedSlider", PERS, false, "ShowSpeedSlider"},
+#else
+  {BP_SHOW_SLIDER, "ShowSpeedSlider", PERS, true, "ShowSpeedSlider"},
+#endif
+  {BP_START_MOUSE, "StartOnLeft", PERS, true, "StartOnLeft"},
+  {BP_START_SPACE, "StartOnSpace", PERS, false, "StartOnSpace"},
+  {BP_STOP_IDLE, "StopOnIdle", PERS, false, "StopOnIdle"},
+  {BP_CONTROL_MODE, "ControlMode", PERS, false, "ControlMode"},
+  {BP_COLOUR_MODE, "ColourMode", PERS, true, "ColourMode"},
+  {BP_MOUSEPOS_MODE, "StartOnMousePosition", PERS, false, "StartOnMousePosition"},
+  {BP_PALETTE_CHANGE, "PaletteChange", PERS, true, "PaletteChange"},
+  {BP_AUTOCALIBRATE, "Autocalibrate", PERS, true, "Automatically learn TargetOffset e.g. gazetracking"},
+  {BP_REMAP_XTREME, "RemapXtreme", PERS, false, "Pointer at extreme Y translates more and zooms less"},
+  {BP_DASHER_PAUSED, "DasherPaused", !PERS, true, "Dasher Paused"},
+  {BP_GAME_MODE, "GameMode", !PERS, false, "Dasher Game Mode"},
+  {BP_LM_DICTIONARY, "Dictionary", PERS, true, "Whether the word-based language model uses a dictionary"},
+  {BP_LM_LETTER_EXCLUSION, "LetterExclusion", PERS, true, "Whether to do letter exclusion in the word-based model"},
+  {BP_AUTO_SPEEDCONTROL, "AutoSpeedControl", PERS, true, "AutoSpeedControl"},
+  {BP_LM_ADAPTIVE, "LMAdaptive", PERS, true, "Whether language model should learn as you enter text"},
+  {BP_SOCKET_INPUT_ENABLE, "SocketInputEnable", PERS, false, "Read pointer coordinates from network socket instead of mouse"},
+  {BP_SOCKET_DEBUG, "SocketInputDebug", PERS, false, "Print information about socket input processing to console"},
+  {BP_CIRCLE_START, "CircleStart", PERS, false, "Start on circle mode"},
+  {BP_GLOBAL_KEYBOARD, "GlobalKeyboard", PERS, false, "Whether to assume global control of the keyboard"},
+#ifdef WITH_MAEMO
+  {BP_NONLINEAR_Y, "NonlinearY", PERS, false, "Apply nonlinearities to Y axis (i.e. compress top &amp; bottom)"},
+#else
+  {BP_NONLINEAR_Y, "NonlinearY", PERS, true, "Apply nonlinearities to Y axis (i.e. compress top &amp; bottom)"},
+#endif
+  {BP_SMOOTH_OFFSET, "DelayView", !PERS, false, "Smooth dynamic-button-mode jumps over several frames"},
+  {BP_STOP_OUTSIDE, "PauseOutside", PERS, false, "Whether to stop when pointer leaves canvas area"},
+#ifdef TARGET_OS_IPHONE
+  {BP_BACKOFF_BUTTON, "BackoffButton", PERS, false, "Whether to enable the extra backoff button in dynamic mode"},
+#else
+  {BP_BACKOFF_BUTTON, "BackoffButton", PERS, true, "Whether to enable the extra backoff button in dynamic mode"},
+#endif
+  {BP_TWOBUTTON_REVERSE, "TwoButtonReverse", PERS, false, "Reverse the up/down buttons in two button mode"},
+  {BP_2B_INVERT_DOUBLE, "TwoButtonInvertDouble", PERS, false, "Double-press acts as opposite button in two-button mode"},
+  {BP_SLOW_START, "SlowStart", PERS, false, "Start at low speed and increase"},
+  {BP_COPY_ALL_ON_STOP, "CopyOnStop", PERS, false, "Copy all text to clipboard whenever we stop"},
+  {BP_SPEAK_ALL_ON_STOP, "SpeakOnStop", PERS, false, "Speak all text whenever we stop"},
+  {BP_SPEAK_WORDS, "SpeakWords", PERS, false, "Speak words as they are written"},
+  {BP_CONTROL_MODE_HAS_HALT, "ControlHasHalt", PERS, false, "Force Control Mode to provide a stop action (triggering clipboard/speech)"},
+#ifdef TARGET_OS_MAC
+  {BP_CONTROL_MODE_HAS_EDIT, "ControlHasEdit", PERS, false, "Provide editing functions in control mode (forward &amp; backward movement &amp; deletion)"},
+#else
+  {BP_CONTROL_MODE_HAS_EDIT, "ControlHasEdit", PERS, true, "Provide editing functions in control mode (forward &amp; backward movement &amp; deletion)"},
+#endif
+  {BP_CONTROL_MODE_HAS_COPY, "ControlHasCopy", PERS, true, "Provide copy-to-clipboard actions in Control Mode (if platforms supports)"},
+  {BP_CONTROL_MODE_HAS_SPEECH, "ControlHasSpeech", PERS, true, "Provide speech actions in Control Mode (if platform supports)"},
+#ifdef TARGET_OS_IPHONE
+  {BP_CUSTOM_TILT, "CustomTilt", PERS, false, "Use custom tilt axes"},
+  {BP_DOUBLE_X, "DoubleXCoords", PERS, false, "Double X-coordinate of touch"},
+#endif
+};
+
+const lp_table longparamtable[] = {
+  {LP_ORIENTATION, "ScreenOrientation", PERS, -2, "Screen Orientation"},
+  {LP_REAL_ORIENTATION, "RealOrientation", !PERS, 0, "Actual screen orientation (allowing for alphabet default)"},
+  {LP_MAX_BITRATE, "MaxBitRateTimes100", PERS, 80, "Max Bit Rate Times 100"},
+  {LP_FRAMERATE, "FrameRate", PERS, 3200, "Decaying average of last known frame rates, *100"},
+  {LP_VIEW_ID, "ViewID", PERS, 1, "ViewID"},
+  {LP_LANGUAGE_MODEL_ID, "LanguageModelID", PERS, 0, "LanguageModelID"},
+  {LP_DASHER_FONTSIZE, "DasherFontSize", PERS, 2, "DasherFontSize"},
+  {LP_MESSAGE_FONTSIZE, "MessageFontSize", PERS, 14, "Size of font for messages (in points)"},
+  {LP_SHAPE_TYPE, "RenderStyle", PERS, 1, "Shapes to render in (0/1=disjoint/overlapping rects, 2/3=triangles/truncated, 4=quadrics, 5=circles)"},
+  {LP_UNIFORM, "UniformTimes1000", PERS, 50, "UniformTimes1000"},
+  {LP_YSCALE, "YScaling", PERS, 0, "YScaling"},
+  {LP_MOUSEPOSDIST, "MousePositionBoxDistance", PERS, 50, "MousePositionBoxDistance"},
+  {LP_STOP_IDLETIME, "StopIdleTime", PERS, 1000, "StopIdleTime" },
+  {LP_MESSAGE_TIME, "MessageTime", PERS, 2500, "Time for which non-modal messages are displayed, in ms"},
+  {LP_LM_MAX_ORDER, "LMMaxOrder", PERS, 5, "LMMaxOrder"},
+  {LP_LM_EXCLUSION, "LMExclusion", PERS, 0, "LMExclusion"},
+  {LP_LM_UPDATE_EXCLUSION, "LMUpdateExclusion", PERS, 1, "LMUpdateExclusion"},
+  {LP_LM_ALPHA, "LMAlpha", PERS, 49, "LMAlpha"},
+  {LP_LM_BETA, "LMBeta", PERS, 77, "LMBeta"},
+  {LP_LM_MIXTURE, "LMMixture", PERS, 50, "LMMixture"},
+  {LP_NORMALIZATION, "Normalization", !PERS, 1 << 16, "Interval for child nodes"},
+  {LP_LINE_WIDTH, "LineWidth", PERS, 1, "Width to draw crosshair and mouse line"},
+  {LP_GEOMETRY, "Geometry", PERS, 0, "Screen geometry (mostly for tall thin screens) - 0=old-style, 1=square no-xhair, 2=squish, 3=squish+log"},
+  {LP_LM_WORD_ALPHA, "WordAlpha", PERS, 50, "Alpha value for word-based model"},
+  {LP_USER_LOG_LEVEL_MASK, "UserLogLevelMask", PERS, 0, "Controls level of user logging, 0 = none, 1 = short, 2 = detailed, 3 = both"},
+  {LP_ZOOMSTEPS, "Zoomsteps", PERS, 32, "Integerised ratio of zoom size for click/button mode, denom 64."},
+  {LP_B, "ButtonMenuBoxes", PERS, 4, "Number of boxes for button menu mode"},
+  {LP_S, "ButtonMenuSafety", PERS, 25, "Safety parameter for button mode, in percent."},
+#ifdef TARGET_OS_IPHONE
+  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", PERS, 600, "Scanning time in menu mode (0 = don't scan), in ms"},
+#else
+  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", PERS, 0, "Scanning time in menu mode (0 = don't scan), in ms"},
+#endif
+  {LP_R, "ButtonModeNonuniformity", PERS, 0, "Button mode box non-uniformity"},
+  {LP_RIGHTZOOM, "ButtonCompassModeRightZoom", PERS, 5120, "Zoomfactor (*1024) for compass mode"},
+#if defined(WITH_MAEMO) || defined (TARGET_OS_IPHONE)
+  {LP_NODE_BUDGET, "NodeBudget", PERS, 1000, "Target (min) number of node objects to maintain"},
+#else
+  {LP_NODE_BUDGET, "NodeBudget", PERS, 3000, "Target (min) number of node objects to maintain"},
+#endif
+  {LP_OUTLINE_WIDTH, "OutlineWidth", PERS, 0, "Absolute value is line width to draw boxes (fill iff >=0)" },
+  {LP_MIN_NODE_SIZE, "MinNodeSize", PERS, 50, "Minimum size of node (in dasher coords) to draw" }, 
+#ifdef WITH_MAEMO
+  {LP_NONLINEAR_X, "NonLinearX", PERS, 0, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
+#else
+  {LP_NONLINEAR_X, "NonLinearX", PERS, 5, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
+#endif
+  {LP_BOOSTFACTOR, "BoostFactor", !PERS, 100, "Boost/brake factor (multiplied by 100)"},
+  {LP_AUTOSPEED_SENSITIVITY, "AutospeedSensitivity", PERS, 100, "Sensitivity of automatic speed control (percent)"},
+  {LP_SOCKET_PORT, "SocketPort", PERS, 20320, "UDP/TCP socket to use for network socket input"},
+  {LP_SOCKET_INPUT_X_MIN, "SocketInputXMinTimes1000", PERS, 0, "Bottom of range of X values expected from network input"},
+  {LP_SOCKET_INPUT_X_MAX, "SocketInputXMaxTimes1000", PERS, 1000, "Top of range of X values expected from network input"},
+  {LP_SOCKET_INPUT_Y_MIN, "SocketInputYMinTimes1000", PERS, 0, "Bottom of range of Y values expected from network input"},
+  {LP_SOCKET_INPUT_Y_MAX, "SocketInputYMaxTimes1000", PERS, 1000, "Top of range of Y values expected from network input"},
+  {LP_OX, "OX", PERS, 2048, "X coordinate of crosshair"},
+  {LP_OY, "OY", PERS, 2048, "Y coordinate of crosshair"},
+  {LP_MAX_Y, "MaxY", PERS, 4096, "Maximum Y coordinate"},
+  {LP_INPUT_FILTER, "InputFilterID", PERS, 3, "Module ID of input filter"},
+  {LP_CIRCLE_PERCENT, "CirclePercent", PERS, 10, "Percentage of nominal vertical range to use for radius of start circle"},
+  {LP_TWO_BUTTON_OFFSET, "TwoButtonOffset", PERS, 1638, "Offset for two button dynamic mode"},
+  {LP_HOLD_TIME, "HoldTime", PERS, 1000, "Time for which buttons must be held to count as long presses, in ms"},
+  {LP_MULTIPRESS_TIME, "MultipressTime", PERS, 1000, "Time in which multiple presses must occur, in ms"},
+  {LP_SLOW_START_TIME, "SlowStartTime", PERS, 1000, "Time over which slow start occurs"},
+  {LP_CONVERSION_ORDER, "ConversionOrder", PERS, 0, "Conversion ordering"},
+  {LP_CONVERSION_TYPE, "ConversionType", PERS, 0, "Conversion type"},
+  {LP_TWO_PUSH_OUTER, "TwoPushOuter", PERS, 1792, "Offset for one button dynamic mode outer marker"},
+  {LP_TWO_PUSH_UP, "TwoPushUp", PERS, 1536, "Offset to up marker in one button dynamic"},
+  {LP_TWO_PUSH_DOWN, "TwoPushDown", PERS, 1280, "Offset to down marker in one button dynamic"},
+  {LP_TWO_PUSH_TOLERANCE, "TwoPushTolerance", PERS, 100, "Tolerance of two-push-mode pushes, in ms"},
+  {LP_DYNAMIC_BUTTON_LAG, "DynamicButtonLag", PERS, 50, "Lag of pushes in dynamic button mode (ms)"},
+  {LP_STATIC1B_TIME, "Static1BTime", PERS, 2000, "Time for static-1B mode to scan from top to bottom (ms)"},
+  {LP_STATIC1B_ZOOM, "Static1BZoom", PERS, 8, "Zoom factor for static-1B mode"},
+  {LP_DEMO_SPRING, "DemoSpring", PERS, 100, "Springyness in Demo-mode"},
+  {LP_DEMO_NOISE_MEM, "DemoNoiseMem", PERS, 100, "Memory parameter for noise in Demo-mode"},
+  {LP_DEMO_NOISE_MAG, "DemoNoiseMag", PERS, 325, "Magnitude of noise in Demo-mode"},
+  {LP_MAXZOOM, "ClickMaxZoom", PERS, 200, "Maximum zoom possible in click mode (times 10)"},
+  {LP_DYNAMIC_SPEED_INC, "DynamicSpeedInc", PERS, 3, "%age by which dynamic mode auto speed control increases speed"},
+  {LP_DYNAMIC_SPEED_FREQ, "DynamicSpeedFreq", PERS, 10, "Seconds after which dynamic mode auto speed control increases speed"},
+  {LP_DYNAMIC_SPEED_DEC, "DynamicSpeedDec", PERS, 8, "%age by which dynamic mode auto speed control decreases speed on reverse"},
+  {LP_TAP_TIME, "TapTime", PERS, 200, "Max length of a stylus 'tap' rather than hold (ms)"},
+#ifdef TARGET_OS_IPHONE
+  {LP_MARGIN_WIDTH, "MarginWidth", PERS, 500, "Width of RHS margin (in Dasher co-ords)"},
+#else
+  {LP_MARGIN_WIDTH, "MarginWidth", PERS, 300, "Width of RHS margin (in Dasher co-ords)"},
+#endif
+  {LP_TARGET_OFFSET, "TargetOffset", PERS, 0, "Vertical distance between mouse pointer and target (400=screen height)"},
+};
+
+const sp_table stringparamtable[] = {
+  {SP_ALPHABET_ID, "AlphabetID", PERS, "", "AlphabetID"},
+  {SP_ALPHABET_1, "Alphabet1", PERS, "", "Alphabet History 1"},
+  {SP_ALPHABET_2, "Alphabet2", PERS, "", "Alphabet History 2"},
+  {SP_ALPHABET_3, "Alphabet3", PERS, "", "Alphabet History 3"},
+  {SP_ALPHABET_4, "Alphabet4", PERS, "", "Alphabet History 4"},
+  {SP_COLOUR_ID, "ColourID", PERS, "", "ColourID"}, 
+  {SP_DEFAULT_COLOUR_ID, "DefaultColourID", !PERS, "", "Default Colour ID (Used for auto-colour mode)"},
+  {SP_DASHER_FONT, "DasherFont", PERS, "", "DasherFont"},
+  {SP_SYSTEM_LOC, "SystemLocation", !PERS, "sys_", "System Directory"},
+  {SP_USER_LOC, "UserLocation", !PERS, "usr_", "User Directory"},
+  {SP_GAME_TEXT_FILE, "GameTextFile", !PERS, "", "File with strings to practice writing"},
+  {SP_SOCKET_INPUT_X_LABEL, "SocketInputXLabel", PERS, "x", "Label preceding X values for network input"},
+  {SP_SOCKET_INPUT_Y_LABEL, "SocketInputYLabel", PERS, "y", "Label preceding Y values for network input"},
+#if defined(WITH_MAEMO) || defined(TARGET_OS_IPHONE)
+  {SP_INPUT_FILTER, "InputFilter", PERS, "Stylus Control", "Input filter used to provide the current control mode"},
+#else
+  {SP_INPUT_FILTER, "InputFilter", PERS, "Normal Control", "Input filter used to provide the current control mode"},
+#endif
+  {SP_INPUT_DEVICE, "InputDevice", PERS, "Mouse Input", "Driver for the input device"},
+  {SP_BUTTON_0, "Button0", PERS, "", "Assignment to button 0"},
+  {SP_BUTTON_1, "Button1", PERS, "", "Assignment to button 1"},
+  {SP_BUTTON_2, "Button2", PERS, "", "Assignment to button 2"},
+  {SP_BUTTON_3, "Button3", PERS, "", "Assignment to button 3"},
+  {SP_BUTTON_4, "Button4", PERS, "", "Assignment to button 4"},
+  {SP_BUTTON_10, "Button10", PERS, "", "Assignment to button 10"},
+  {SP_JOYSTICK_DEVICE, "JoystickDevice", PERS, "/dev/input/js0", "Joystick device"},
+#ifdef TARGET_OS_IPHONE
+  {SP_CUSTOM_TILT, "CustomTiltParams", PERS, "(0.0,0.0,0.0) - (0.0,-1.0,0.0) / (-1.0,0.0,0.0)", "Custom tilt axes"},
+  {SP_VERTICAL_TILT, "VerticalTiltParams", PERS, "-0.1 - -0.9 / -0.4 - 0.4", "Limits of vertical tilting"}, 
+#endif
+};
+
+ParameterType GetParameterType(int iParameter) {
+  if ((iParameter >= FIRST_BP) && (iParameter < FIRST_LP))
+    return ParamBool;
+  if ((iParameter >= FIRST_LP) && (iParameter < FIRST_SP))
+    return ParamLong;
+  if ((iParameter >= FIRST_SP) && (iParameter < END_OF_SPS))
+    return ParamString;
+  
+  return ParamInvalid;
+}
+
+std::string GetParameterName(int iParameter) {
+  // Pull the registry name out of the correct table depending on the parameter type
+  switch (GetParameterType(iParameter)) {
+    case (ParamBool):
+      DASHER_ASSERT(iParameter == boolparamtable[iParameter - FIRST_BP].key);
+      return boolparamtable[iParameter - FIRST_BP].regName;
+    case (ParamLong):
+      DASHER_ASSERT(iParameter == longparamtable[iParameter - FIRST_LP].key);
+      return longparamtable[iParameter - FIRST_LP].regName;
+    case (ParamString):
+      DASHER_ASSERT(iParameter == stringparamtable[iParameter - FIRST_SP].key);
+      return stringparamtable[iParameter - FIRST_SP].regName;
+    case ParamInvalid:
+      DASHER_ASSERT(false);
+      break;
+  };
+  return "";
+}
+
+} //end namespace Settings
+} //end namespace Dasher
\ No newline at end of file
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index 231c878..ffbac04 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -21,11 +21,9 @@
 #ifndef __parameters_h__
 #define __parameters_h__
 
-#include <string>
+#include "../Common/Common.h"
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include <string>
 
 // All parameters go into the enums here
 // They are unique across the different types
@@ -40,7 +38,7 @@ enum {
   BP_LM_LETTER_EXCLUSION, BP_AUTO_SPEEDCONTROL,
   BP_LM_ADAPTIVE, BP_SOCKET_INPUT_ENABLE, BP_SOCKET_DEBUG, 
   BP_CIRCLE_START, BP_GLOBAL_KEYBOARD, BP_NONLINEAR_Y,
-  BP_SMOOTH_OFFSET, BP_CONVERSION_MODE, BP_STOP_OUTSIDE, BP_BACKOFF_BUTTON,
+  BP_SMOOTH_OFFSET, BP_STOP_OUTSIDE, BP_BACKOFF_BUTTON,
   BP_TWOBUTTON_REVERSE, BP_2B_INVERT_DOUBLE, BP_SLOW_START,
   BP_COPY_ALL_ON_STOP, BP_SPEAK_ALL_ON_STOP, BP_SPEAK_WORDS,
   BP_CONTROL_MODE_HAS_HALT, BP_CONTROL_MODE_HAS_EDIT, BP_CONTROL_MODE_HAS_COPY, BP_CONTROL_MODE_HAS_SPEECH,
@@ -96,288 +94,71 @@ enum {
 
 #define PERS true
 
-// First level structures with only basic data types because you
-// cannot initialize struct tables with objects
-// These will be turned into std::strings in the ParamTables() object 
-struct bp_table {
-  int key;
-  const char *regName;
-  bool persistent;
-  bool defaultValue;
-  const char *humanReadable;
-};
-struct lp_table {
-  int key;
-  const char *regName;
-  bool persistent;
-  long defaultValue;
-  const char *humanReadable;
-};
-struct sp_table {
-  int key;
-  const char *regName;
-  bool persistent;
-  const char *defaultValue;
-  const char *humanReadable;
-};
-
-// The only important thing here is that these are in the same order
-// as the enum declarations (could add check in class that enforces this instead)
-static bp_table boolparamtable[] = {
-  {BP_DRAW_MOUSE_LINE, "DrawMouseLine", PERS, true, "Draw Mouse Line"},
-  {BP_DRAW_MOUSE, "DrawMouse", PERS, false, "Draw Mouse Position"},
-  {BP_CURVE_MOUSE_LINE, "CurveMouseLine", PERS, false, "Curve mouse line according to screen nonlinearity"},
-#ifdef WITH_MAEMO
-  {BP_SHOW_SLIDER, "ShowSpeedSlider", PERS, false, "ShowSpeedSlider"},
-#else
-  {BP_SHOW_SLIDER, "ShowSpeedSlider", PERS, true, "ShowSpeedSlider"},
-#endif
-  {BP_START_MOUSE, "StartOnLeft", PERS, true, "StartOnLeft"},
-  {BP_START_SPACE, "StartOnSpace", PERS, false, "StartOnSpace"},
-  {BP_STOP_IDLE, "StopOnIdle", PERS, false, "StopOnIdle"},
-  {BP_CONTROL_MODE, "ControlMode", PERS, false, "ControlMode"},
-  {BP_COLOUR_MODE, "ColourMode", PERS, true, "ColourMode"},
-  {BP_MOUSEPOS_MODE, "StartOnMousePosition", PERS, false, "StartOnMousePosition"},
-  {BP_PALETTE_CHANGE, "PaletteChange", PERS, true, "PaletteChange"},
-  {BP_AUTOCALIBRATE, "Autocalibrate", PERS, true, "Automatically learn TargetOffset e.g. gazetracking"},
-  {BP_REMAP_XTREME, "RemapXtreme", PERS, false, "Pointer at extreme Y translates more and zooms less"},
-  {BP_DASHER_PAUSED, "DasherPaused", !PERS, true, "Dasher Paused"},
-  {BP_GAME_MODE, "GameMode", !PERS, false, "Dasher Game Mode"},
-  {BP_LM_DICTIONARY, "Dictionary", PERS, true, "Whether the word-based language model uses a dictionary"},
-  {BP_LM_LETTER_EXCLUSION, "LetterExclusion", PERS, true, "Whether to do letter exclusion in the word-based model"},
-  {BP_AUTO_SPEEDCONTROL, "AutoSpeedControl", PERS, true, "AutoSpeedControl"},
-  {BP_LM_ADAPTIVE, "LMAdaptive", PERS, true, "Whether language model should learn as you enter text"},
-  {BP_SOCKET_INPUT_ENABLE, "SocketInputEnable", PERS, false, "Read pointer coordinates from network socket instead of mouse"},
-  {BP_SOCKET_DEBUG, "SocketInputDebug", PERS, false, "Print information about socket input processing to console"},
-  {BP_CIRCLE_START, "CircleStart", PERS, false, "Start on circle mode"},
-  {BP_GLOBAL_KEYBOARD, "GlobalKeyboard", PERS, false, "Whether to assume global control of the keyboard"},
-#ifdef WITH_MAEMO
-  {BP_NONLINEAR_Y, "NonlinearY", PERS, false, "Apply nonlinearities to Y axis (i.e. compress top &amp; bottom)"},
-#else
-  {BP_NONLINEAR_Y, "NonlinearY", PERS, true, "Apply nonlinearities to Y axis (i.e. compress top &amp; bottom)"},
-#endif
-  {BP_SMOOTH_OFFSET, "DelayView", !PERS, false, "Smooth dynamic-button-mode jumps over several frames"},
-  {BP_CONVERSION_MODE, "ConversionMode", !PERS, false, "Whether Dasher is operating in conversion (eg Japanese) mode"},
-  {BP_STOP_OUTSIDE, "PauseOutside", PERS, false, "Whether to stop when pointer leaves canvas area"},
-#ifdef TARGET_OS_IPHONE
-  {BP_BACKOFF_BUTTON, "BackoffButton", PERS, false, "Whether to enable the extra backoff button in dynamic mode"},
-#else
-  {BP_BACKOFF_BUTTON, "BackoffButton", PERS, true, "Whether to enable the extra backoff button in dynamic mode"},
-#endif
-  {BP_TWOBUTTON_REVERSE, "TwoButtonReverse", PERS, false, "Reverse the up/down buttons in two button mode"},
-  {BP_2B_INVERT_DOUBLE, "TwoButtonInvertDouble", PERS, false, "Double-press acts as opposite button in two-button mode"},
-  {BP_SLOW_START, "SlowStart", PERS, false, "Start at low speed and increase"},
-  {BP_COPY_ALL_ON_STOP, "CopyOnStop", PERS, false, "Copy all text to clipboard whenever we stop"},
-  {BP_SPEAK_ALL_ON_STOP, "SpeakOnStop", PERS, false, "Speak all text whenever we stop"},
-  {BP_SPEAK_WORDS, "SpeakWords", PERS, false, "Speak words as they are written"},
-  {BP_CONTROL_MODE_HAS_HALT, "ControlHasHalt", PERS, false, "Force Control Mode to provide a stop action (triggering clipboard/speech)"},
-#ifdef TARGET_OS_MAC
-  {BP_CONTROL_MODE_HAS_EDIT, "ControlHasEdit", PERS, false, "Provide editing functions in control mode (forward &amp; backward movement &amp; deletion)"},
-#else
-  {BP_CONTROL_MODE_HAS_EDIT, "ControlHasEdit", PERS, true, "Provide editing functions in control mode (forward &amp; backward movement &amp; deletion)"},
-#endif
-  {BP_CONTROL_MODE_HAS_COPY, "ControlHasCopy", PERS, true, "Provide copy-to-clipboard actions in Control Mode (if platforms supports)"},
-  {BP_CONTROL_MODE_HAS_SPEECH, "ControlHasSpeech", PERS, true, "Provide speech actions in Control Mode (if platform supports)"},
-#ifdef TARGET_OS_IPHONE
-  {BP_CUSTOM_TILT, "CustomTilt", PERS, false, "Use custom tilt axes"},
-  {BP_DOUBLE_X, "DoubleXCoords", PERS, false, "Double X-coordinate of touch"},
-#endif
-};
-
-static lp_table longparamtable[] = {
-  {LP_ORIENTATION, "ScreenOrientation", PERS, -2, "Screen Orientation"},
-  {LP_REAL_ORIENTATION, "RealOrientation", !PERS, 0, "Actual screen orientation (allowing for alphabet default)"},
-  {LP_MAX_BITRATE, "MaxBitRateTimes100", PERS, 80, "Max Bit Rate Times 100"},
-  {LP_FRAMERATE, "FrameRate", PERS, 3200, "Decaying average of last known frame rates, *100"},
-  {LP_VIEW_ID, "ViewID", PERS, 1, "ViewID"},
-  {LP_LANGUAGE_MODEL_ID, "LanguageModelID", PERS, 0, "LanguageModelID"},
-  {LP_DASHER_FONTSIZE, "DasherFontSize", PERS, 2, "DasherFontSize"},
-  {LP_MESSAGE_FONTSIZE, "MessageFontSize", PERS, 14, "Size of font for messages (in points)"},
-  {LP_SHAPE_TYPE, "RenderStyle", PERS, 1, "Shapes to render in (0/1=disjoint/overlapping rects, 2/3=triangles/truncated, 4=quadrics, 5=circles)"},
-  {LP_UNIFORM, "UniformTimes1000", PERS, 50, "UniformTimes1000"},
-  {LP_YSCALE, "YScaling", PERS, 0, "YScaling"},
-  {LP_MOUSEPOSDIST, "MousePositionBoxDistance", PERS, 50, "MousePositionBoxDistance"},
-  {LP_STOP_IDLETIME, "StopIdleTime", PERS, 1000, "StopIdleTime" },
-  {LP_MESSAGE_TIME, "MessageTime", PERS, 2500, "Time for which non-modal messages are displayed, in ms"},
-  {LP_LM_MAX_ORDER, "LMMaxOrder", PERS, 5, "LMMaxOrder"},
-  {LP_LM_EXCLUSION, "LMExclusion", PERS, 0, "LMExclusion"},
-  {LP_LM_UPDATE_EXCLUSION, "LMUpdateExclusion", PERS, 1, "LMUpdateExclusion"},
-  {LP_LM_ALPHA, "LMAlpha", PERS, 49, "LMAlpha"},
-  {LP_LM_BETA, "LMBeta", PERS, 77, "LMBeta"},
-  {LP_LM_MIXTURE, "LMMixture", PERS, 50, "LMMixture"},
-  {LP_NORMALIZATION, "Normalization", !PERS, 1 << 16, "Interval for child nodes"},
-  {LP_LINE_WIDTH, "LineWidth", PERS, 1, "Width to draw crosshair and mouse line"},
-  {LP_GEOMETRY, "Geometry", PERS, 0, "Screen geometry (mostly for tall thin screens) - 0=old-style, 1=square no-xhair, 2=squish, 3=squish+log"},
-  {LP_LM_WORD_ALPHA, "WordAlpha", PERS, 50, "Alpha value for word-based model"},
-  {LP_USER_LOG_LEVEL_MASK, "UserLogLevelMask", PERS, 0, "Controls level of user logging, 0 = none, 1 = short, 2 = detailed, 3 = both"},
-  {LP_ZOOMSTEPS, "Zoomsteps", PERS, 32, "Integerised ratio of zoom size for click/button mode, denom 64."},
-  {LP_B, "ButtonMenuBoxes", PERS, 4, "Number of boxes for button menu mode"},
-  {LP_S, "ButtonMenuSafety", PERS, 25, "Safety parameter for button mode, in percent."},
-#ifdef TARGET_OS_IPHONE
-  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", PERS, 600, "Scanning time in menu mode (0 = don't scan), in ms"},
-#else
-  {LP_BUTTON_SCAN_TIME, "ButtonMenuScanTime", PERS, 0, "Scanning time in menu mode (0 = don't scan), in ms"},
-#endif
-  {LP_R, "ButtonModeNonuniformity", PERS, 0, "Button mode box non-uniformity"},
-  {LP_RIGHTZOOM, "ButtonCompassModeRightZoom", PERS, 5120, "Zoomfactor (*1024) for compass mode"},
-#if defined(WITH_MAEMO) || defined (TARGET_OS_IPHONE)
-  {LP_NODE_BUDGET, "NodeBudget", PERS, 1000, "Target (min) number of node objects to maintain"},
-#else
-  {LP_NODE_BUDGET, "NodeBudget", PERS, 3000, "Target (min) number of node objects to maintain"},
-#endif
-  {LP_OUTLINE_WIDTH, "OutlineWidth", PERS, 0, "Absolute value is line width to draw boxes (fill iff >=0)" },
-  {LP_MIN_NODE_SIZE, "MinNodeSize", PERS, 50, "Minimum size of node (in dasher coords) to draw" }, 
-#ifdef WITH_MAEMO
-  {LP_NONLINEAR_X, "NonLinearX", PERS, 0, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
-#else
-  {LP_NONLINEAR_X, "NonLinearX", PERS, 5, "Nonlinear compression of X-axis (0 = none, higher = more extreme)"},
-#endif
-  {LP_BOOSTFACTOR, "BoostFactor", !PERS, 100, "Boost/brake factor (multiplied by 100)"},
-  {LP_AUTOSPEED_SENSITIVITY, "AutospeedSensitivity", PERS, 100, "Sensitivity of automatic speed control (percent)"},
-  {LP_SOCKET_PORT, "SocketPort", PERS, 20320, "UDP/TCP socket to use for network socket input"},
-  {LP_SOCKET_INPUT_X_MIN, "SocketInputXMinTimes1000", PERS, 0, "Bottom of range of X values expected from network input"},
-  {LP_SOCKET_INPUT_X_MAX, "SocketInputXMaxTimes1000", PERS, 1000, "Top of range of X values expected from network input"},
-  {LP_SOCKET_INPUT_Y_MIN, "SocketInputYMinTimes1000", PERS, 0, "Bottom of range of Y values expected from network input"},
-  {LP_SOCKET_INPUT_Y_MAX, "SocketInputYMaxTimes1000", PERS, 1000, "Top of range of Y values expected from network input"},
-  {LP_OX, "OX", PERS, 2048, "X coordinate of crosshair"},
-  {LP_OY, "OY", PERS, 2048, "Y coordinate of crosshair"},
-  {LP_MAX_Y, "MaxY", PERS, 4096, "Maximum Y coordinate"},
-  {LP_INPUT_FILTER, "InputFilterID", PERS, 3, "Module ID of input filter"},
-  {LP_CIRCLE_PERCENT, "CirclePercent", PERS, 10, "Percentage of nominal vertical range to use for radius of start circle"},
-  {LP_TWO_BUTTON_OFFSET, "TwoButtonOffset", PERS, 1638, "Offset for two button dynamic mode"},
-  {LP_HOLD_TIME, "HoldTime", PERS, 1000, "Time for which buttons must be held to count as long presses, in ms"},
-  {LP_MULTIPRESS_TIME, "MultipressTime", PERS, 1000, "Time in which multiple presses must occur, in ms"},
-  {LP_SLOW_START_TIME, "SlowStartTime", PERS, 1000, "Time over which slow start occurs"},
-  {LP_CONVERSION_ORDER, "ConversionOrder", PERS, 0, "Conversion ordering"},
-  {LP_CONVERSION_TYPE, "ConversionType", PERS, 0, "Conversion type"},
-  {LP_TWO_PUSH_OUTER, "TwoPushOuter", PERS, 1792, "Offset for one button dynamic mode outer marker"},
-  {LP_TWO_PUSH_UP, "TwoPushUp", PERS, 1536, "Offset to up marker in one button dynamic"},
-  {LP_TWO_PUSH_DOWN, "TwoPushDown", PERS, 1280, "Offset to down marker in one button dynamic"},
-  {LP_TWO_PUSH_TOLERANCE, "TwoPushTolerance", PERS, 100, "Tolerance of two-push-mode pushes, in ms"},
-  {LP_DYNAMIC_BUTTON_LAG, "DynamicButtonLag", PERS, 50, "Lag of pushes in dynamic button mode (ms)"},
-  {LP_STATIC1B_TIME, "Static1BTime", PERS, 2000, "Time for static-1B mode to scan from top to bottom (ms)"},
-  {LP_STATIC1B_ZOOM, "Static1BZoom", PERS, 8, "Zoom factor for static-1B mode"},
-  {LP_DEMO_SPRING, "DemoSpring", PERS, 100, "Springyness in Demo-mode"},
-  {LP_DEMO_NOISE_MEM, "DemoNoiseMem", PERS, 100, "Memory parameter for noise in Demo-mode"},
-  {LP_DEMO_NOISE_MAG, "DemoNoiseMag", PERS, 325, "Magnitude of noise in Demo-mode"},
-  {LP_MAXZOOM, "ClickMaxZoom", PERS, 200, "Maximum zoom possible in click mode (times 10)"},
-  {LP_DYNAMIC_SPEED_INC, "DynamicSpeedInc", PERS, 3, "%age by which dynamic mode auto speed control increases speed"},
-  {LP_DYNAMIC_SPEED_FREQ, "DynamicSpeedFreq", PERS, 10, "Seconds after which dynamic mode auto speed control increases speed"},
-  {LP_DYNAMIC_SPEED_DEC, "DynamicSpeedDec", PERS, 8, "%age by which dynamic mode auto speed control decreases speed on reverse"},
-  {LP_TAP_TIME, "TapTime", PERS, 200, "Max length of a stylus 'tap' rather than hold (ms)"},
-#ifdef TARGET_OS_IPHONE
-  {LP_MARGIN_WIDTH, "MarginWidth", PERS, 500, "Width of RHS margin (in Dasher co-ords)"},
-#else
-  {LP_MARGIN_WIDTH, "MarginWidth", PERS, 300, "Width of RHS margin (in Dasher co-ords)"},
-#endif
-  {LP_TARGET_OFFSET, "TargetOffset", PERS, 0, "Vertical distance between mouse pointer and target (400=screen height)"},
-};
-
-static sp_table stringparamtable[] = {
-  {SP_ALPHABET_ID, "AlphabetID", PERS, "", "AlphabetID"},
-  {SP_ALPHABET_1, "Alphabet1", PERS, "", "Alphabet History 1"},
-  {SP_ALPHABET_2, "Alphabet2", PERS, "", "Alphabet History 2"},
-  {SP_ALPHABET_3, "Alphabet3", PERS, "", "Alphabet History 3"},
-  {SP_ALPHABET_4, "Alphabet4", PERS, "", "Alphabet History 4"},
-  {SP_COLOUR_ID, "ColourID", PERS, "", "ColourID"}, 
-  {SP_DEFAULT_COLOUR_ID, "DefaultColourID", !PERS, "", "Default Colour ID (Used for auto-colour mode)"},
-  {SP_DASHER_FONT, "DasherFont", PERS, "", "DasherFont"},
-  {SP_SYSTEM_LOC, "SystemLocation", !PERS, "sys_", "System Directory"},
-  {SP_USER_LOC, "UserLocation", !PERS, "usr_", "User Directory"},
-  {SP_GAME_TEXT_FILE, "GameTextFile", !PERS, "", "File with strings to practice writing"},
-  {SP_SOCKET_INPUT_X_LABEL, "SocketInputXLabel", PERS, "x", "Label preceding X values for network input"},
-  {SP_SOCKET_INPUT_Y_LABEL, "SocketInputYLabel", PERS, "y", "Label preceding Y values for network input"},
-#if defined(WITH_MAEMO) || defined(TARGET_OS_IPHONE)
-  {SP_INPUT_FILTER, "InputFilter", PERS, "Stylus Control", "Input filter used to provide the current control mode"},
-#else
-  {SP_INPUT_FILTER, "InputFilter", PERS, "Normal Control", "Input filter used to provide the current control mode"},
-#endif
-  {SP_INPUT_DEVICE, "InputDevice", PERS, "Mouse Input", "Driver for the input device"},
-  {SP_BUTTON_0, "Button0", PERS, "", "Assignment to button 0"},
-  {SP_BUTTON_1, "Button1", PERS, "", "Assignment to button 1"},
-  {SP_BUTTON_2, "Button2", PERS, "", "Assignment to button 2"},
-  {SP_BUTTON_3, "Button3", PERS, "", "Assignment to button 3"},
-  {SP_BUTTON_4, "Button4", PERS, "", "Assignment to button 4"},
-  {SP_BUTTON_10, "Button10", PERS, "", "Assignment to button 10"},
-  {SP_JOYSTICK_DEVICE, "JoystickDevice", PERS, "/dev/input/js0", "Joystick device"},
-#ifdef TARGET_OS_IPHONE
-  {SP_CUSTOM_TILT, "CustomTiltParams", PERS, "(0.0,0.0,0.0) - (0.0,-1.0,0.0) / (-1.0,0.0,0.0)", "Custom tilt axes"},
-  {SP_VERTICAL_TILT, "VerticalTiltParams", PERS, "-0.1 - -0.9 / -0.4 - 0.4", "Limits of vertical tilting"}, 
-#endif
-};
-
-// This is the structure of each table that the settings will access
-// Everything is const except the current value of the setting
-struct bp_info {
-  int key;
-  std::string regName;
-  bool persistent;
-  bool value;
-  bool defaultVal;
-  std::string humanReadable;
-};
-struct lp_info {
-  int key;
-  std::string regName;
-  bool persistent;
-  long value;
-  long defaultVal;
-  std::string humanReadable;
-};
-struct sp_info {
-  int key;
-  std::string regName;
-  bool persistent;
-  std::string value;
-  std::string defaultVal;
-  std::string humanReadable;
-};
-
 namespace Dasher {
-  class CParamTables;
-} 
-/// \ingroup Core
-/// \{
-class Dasher::CParamTables {
-
-// These are the parameter tables that store everything
-public:
-  bp_info BoolParamTable[NUM_OF_BPS];
-  lp_info LongParamTable[NUM_OF_LPS];
-  sp_info StringParamTable[NUM_OF_SPS];
-
-public:
-  CParamTables() {
-    // Initialize all the tables with default values
-    // and convert the char* to std::string in the object
-    for(int ii = 0; ii < NUM_OF_BPS; ii++) {
-      BoolParamTable[ii].key = boolparamtable[ii].key;
-      BoolParamTable[ii].value = boolparamtable[ii].defaultValue;
-      BoolParamTable[ii].defaultVal = boolparamtable[ii].defaultValue;
-      BoolParamTable[ii].humanReadable = boolparamtable[ii].humanReadable;
-      BoolParamTable[ii].persistent = boolparamtable[ii].persistent;
-      BoolParamTable[ii].regName = boolparamtable[ii].regName;
-    } 
+  ///Namespace containing all static (i.e. fixed/constant) data about
+  /// settings, that is _not_ dependent on the storage mechanism,
+  /// the SettingsStore in use, or platform-specific details.
+  /// (Except, some defaults are #ifdef'd according to platform).
+  /// This data does NOT change at runtime.
+  namespace Settings {
+    ///Structure storing fixed data about bool settings...
+    struct bp_table {
+      int key;
+      const char *regName;
+      bool persistent;
+      bool defaultValue;
+      const char *humanReadable;
+    };
+    ///One bp_table per bool param, in the same order as the enum declarations
+    /// (i.e.: boolparamtable[x]->key == x-FIRST_BP)
+    extern const bp_table boolparamtable[NUM_OF_BPS];
+
+    ///Structure storing fixed data about long settings...
+    struct lp_table {
+      int key;
+      const char *regName;
+      bool persistent;
+      long defaultValue;
+      const char *humanReadable;
+    };
+    ///One lp_table per long param, in the same order as the enum declarations
+    /// (i.e.: longparamtable[x]->key == x-FIRST_LP)
+    extern const lp_table longparamtable[NUM_OF_LPS];
     
-    for(int ij = 0; ij < NUM_OF_LPS; ij++) {
-      LongParamTable[ij].key = longparamtable[ij].key;
-      LongParamTable[ij].value = longparamtable[ij].defaultValue;
-      LongParamTable[ij].defaultVal = longparamtable[ij].defaultValue;
-      LongParamTable[ij].humanReadable = longparamtable[ij].humanReadable;
-      LongParamTable[ij].persistent = longparamtable[ij].persistent;
-      LongParamTable[ij].regName = longparamtable[ij].regName;
-    }
-
-    for(int ik = 0; ik < NUM_OF_SPS; ik++) {
-      StringParamTable[ik].key = stringparamtable[ik].key;
-      StringParamTable[ik].value = stringparamtable[ik].defaultValue;
-      StringParamTable[ik].defaultVal = stringparamtable[ik].defaultValue;
-      StringParamTable[ik].humanReadable = stringparamtable[ik].humanReadable;
-      StringParamTable[ik].persistent = stringparamtable[ik].persistent;
-      StringParamTable[ik].regName = stringparamtable[ik].regName;
-    }
-  };
-  /// \}
-};
-
+    ///Structure storing fixed data about string settings...
+    struct sp_table {
+      int key;
+      const char *regName;
+      bool persistent;
+      const char *defaultValue;
+      const char *humanReadable;
+    };
+    
+    ///One sp_table per string param, in the same order as the enum declarations
+    /// (i.e.: stringparamtable[x]->key == x-FIRST_SP)
+    extern const sp_table stringparamtable[NUM_OF_SPS];
+    
+    // Types that are parameters can be
+    enum ParameterType {
+      ParamBool,
+      ParamLong,
+      ParamString,
+      ParamInvalid
+    };
+    
+    ///Get the type of a parameter by its key.
+    /// \param iParameter one of the BP_*, LP_* or SP_* enum constants
+    /// \return ParamBool, ParamLong or ParamString, respectively; or
+    /// ParamInvalid if iParameter is not in the range of those enums.
+    ParameterType GetParameterType(int iParameter);
+    
+    ///Gets the regName member of the struct for a parameter (of any of the 3 types).
+    /// This is appropriate for use as a key for storing the setting value into e.g. a registry.
+    /// Note - returns a string not a reference to one, because the table stores only a char*.
+    /// \param iParameter one of the BP_*, LP_* or SP_* enum constants
+    /// \return the regName member of the corresponding bp_table, lp_table,
+    /// or sp_table struct.
+    std::string GetParameterName(int iParameter);
+  }
+}
 #endif
diff --git a/Src/DasherCore/SettingsStore.cpp b/Src/DasherCore/SettingsStore.cpp
index 78c8d5b..a1b5972 100644
--- a/Src/DasherCore/SettingsStore.cpp
+++ b/Src/DasherCore/SettingsStore.cpp
@@ -10,13 +10,15 @@
 
 #include "SettingsStore.h"
 #include "Event.h"
-#include "EventHandler.h"
+#include "Observable.h"
 
 #include <cstring>
 #include <cstdlib>
 #include <iostream>
 
 using namespace std;
+using namespace Dasher;
+using namespace Dasher::Settings;
 
 // Track memory leaks on Windows to the line that new'd the memory
 #ifdef _WIN32
@@ -28,11 +30,9 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-Dasher::CParamTables CSettingsStore::s_oParamTables;
+static CSettingsStore *s_pSettingsStore = NULL;
 
-// TODO: Don't propagate changes which don't affect anything.
-
-CSettingsStore::CSettingsStore(Dasher::CEventHandler *pEventHandler):m_pEventHandler(pEventHandler) {
+CSettingsStore::CSettingsStore() {
 }
 
 void CSettingsStore::LoadPersistent() {
@@ -41,30 +41,36 @@ void CSettingsStore::LoadPersistent() {
   // we'll save the settings with the default value that comes from Parameters.h
 
   for(int i(0); i < NUM_OF_BPS; ++i) {
-    bool bValue;
-    if(s_oParamTables.BoolParamTable[i].persistent)
-      if(LoadSetting(s_oParamTables.BoolParamTable[i].regName, &bValue))
-        s_oParamTables.BoolParamTable[i].value = bValue;
+    boolParamValues[i] = boolparamtable[i].defaultValue;
+    if(boolparamtable[i].persistent) {
+      bool bValue;
+      if(LoadSetting(boolparamtable[i].regName, &bValue))
+        boolParamValues[i] = bValue;
       else
-        SaveSetting(s_oParamTables.BoolParamTable[i].regName, s_oParamTables.BoolParamTable[i].value);            
+        SaveSetting(boolparamtable[i].regName, boolParamValues[i]);
+    }
   }
 
   for(int j(0); j < NUM_OF_LPS; ++j) {
-    long lValue;
-    if(s_oParamTables.LongParamTable[j].persistent)
-      if(LoadSetting(s_oParamTables.LongParamTable[j].regName, &lValue)) 
-        s_oParamTables.LongParamTable[j].value = lValue;
+    longParamValues[j] = longparamtable[j].defaultValue;
+    if(longparamtable[j].persistent) {
+      long lValue;
+      if(LoadSetting(longparamtable[j].regName, &lValue)) 
+        longParamValues[j] = lValue;
       else
-        SaveSetting(s_oParamTables.LongParamTable[j].regName, s_oParamTables.LongParamTable[j].value);            
+        SaveSetting(longparamtable[j].regName, longParamValues[j]);            
+    }
   }
 
   for(int k(0); k < NUM_OF_SPS; ++k) {
-    std::string strValue;
-    if(s_oParamTables.StringParamTable[k].persistent)
-      if(LoadSetting(s_oParamTables.StringParamTable[k].regName, &strValue))
-        s_oParamTables.StringParamTable[k].value = strValue;
+    stringParamValues[k] = stringparamtable[k].defaultValue;
+    if(stringparamtable[k].persistent) {
+      std::string strValue;
+      if(LoadSetting(stringparamtable[k].regName, &strValue))
+        stringParamValues[k] = strValue;
       else
-        SaveSetting(s_oParamTables.StringParamTable[k].regName, s_oParamTables.StringParamTable[k].value);            
+        SaveSetting(stringparamtable[k].regName, stringParamValues[k]);            
+    }
   }
 }
 
@@ -72,11 +78,11 @@ void CSettingsStore::LoadPersistent() {
 // Return 0 on success, an error string on failure.
 const char * CSettingsStore::ClSet(const std::string &strKey, const std::string &strValue) {
   for(int i(0); i < NUM_OF_BPS; ++i) {
-    if(strKey == s_oParamTables.BoolParamTable[i].regName) {
+    if(strKey == boolparamtable[i].regName) {
       if ((strValue == "0") || (strValue == _("true")))
-	SetBoolParameter(s_oParamTables.BoolParamTable[i].key, false);
+	SetBoolParameter(boolparamtable[i].key, false);
       else if((strValue == "1") || (strValue == _("false")))
-	SetBoolParameter(s_oParamTables.BoolParamTable[i].key, true);
+	SetBoolParameter(boolparamtable[i].key, true);
       else
         // Note to translators: This message will be output for a command line
         // with "--options foo=VAL" and foo is a boolean valued parameter, but
@@ -87,15 +93,15 @@ const char * CSettingsStore::ClSet(const std::string &strKey, const std::string
   }
 
   for(int i(0); i < NUM_OF_LPS; ++i) {
-    if(strKey == s_oParamTables.LongParamTable[i].regName) {
-      SetLongParameter(s_oParamTables.LongParamTable[i].key, atoi(strValue.c_str()));
+    if(strKey == longparamtable[i].regName) {
+      SetLongParameter(longparamtable[i].key, atoi(strValue.c_str()));
       return 0;
     }
   }
 
   for(int i(0); i < NUM_OF_SPS; ++i) {
-    if(strKey == s_oParamTables.StringParamTable[i].regName) {
-      SetStringParameter(s_oParamTables.StringParamTable[i].key, strValue);
+    if(strKey == stringparamtable[i].regName) {
+      SetStringParameter(stringparamtable[i].key, strValue);
       return 0;
     }
   }
@@ -110,87 +116,82 @@ const char * CSettingsStore::ClSet(const std::string &strKey, const std::string
 void CSettingsStore::SetBoolParameter(int iParameter, bool bValue) {
 
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == s_oParamTables.BoolParamTable[iParameter - FIRST_BP].key);
+  DASHER_ASSERT(iParameter == boolparamtable[iParameter - FIRST_BP].key);
 
   if(bValue == GetBoolParameter(iParameter))
     return;
 
   // Set the value
-  s_oParamTables.BoolParamTable[iParameter - FIRST_BP].value = bValue;
+  boolParamValues[iParameter - FIRST_BP] = bValue;
 
   // Initiate events for changed parameter
-  Dasher::CParameterNotificationEvent* oEvent = new Dasher::CParameterNotificationEvent(iParameter);
-
-  m_pEventHandler->InsertEvent(oEvent);
-  delete oEvent;
+  DispatchEvent(iParameter);
 
   // Write out to permanent storage
-  if(s_oParamTables.BoolParamTable[iParameter - FIRST_BP].persistent)
-    SaveSetting(s_oParamTables.BoolParamTable[iParameter - FIRST_BP].regName, bValue);
+  if(boolparamtable[iParameter - FIRST_BP].persistent)
+    SaveSetting(boolparamtable[iParameter - FIRST_BP].regName, bValue);
 }
 
 void CSettingsStore::SetLongParameter(int iParameter, long lValue) {
 
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == s_oParamTables.LongParamTable[iParameter - FIRST_LP].key);
+  DASHER_ASSERT(iParameter == longparamtable[iParameter - FIRST_LP].key);
 
   if(lValue == GetLongParameter(iParameter))
     return;
 
   // Set the value
-  s_oParamTables.LongParamTable[iParameter - FIRST_LP].value = lValue;
+  longParamValues[iParameter - FIRST_LP] = lValue;
 
   // Initiate events for changed parameter
-  Dasher::CParameterNotificationEvent oEvent(iParameter);
-  m_pEventHandler->InsertEvent(&oEvent);
+  DispatchEvent(iParameter);
 
   // Write out to permanent storage
-  if(s_oParamTables.LongParamTable[iParameter - FIRST_LP].persistent)
-    SaveSetting(s_oParamTables.LongParamTable[iParameter - FIRST_LP].regName, lValue);
+  if(longparamtable[iParameter - FIRST_LP].persistent)
+    SaveSetting(longparamtable[iParameter - FIRST_LP].regName, lValue);
 }
 
 void CSettingsStore::SetStringParameter(int iParameter, const std::string sValue) {
 
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == s_oParamTables.StringParamTable[iParameter - FIRST_SP].key);
+  DASHER_ASSERT(iParameter == stringparamtable[iParameter - FIRST_SP].key);
 
   if(sValue == GetStringParameter(iParameter))
     return;
 
   // Set the value
-  s_oParamTables.StringParamTable[iParameter - FIRST_SP].value = sValue;
+  stringParamValues[iParameter - FIRST_SP] = sValue;
 
   // Initiate events for changed parameter
-  Dasher::CParameterNotificationEvent oEvent(iParameter);
-  m_pEventHandler->InsertEvent(&oEvent);
+  DispatchEvent(iParameter);
 
   // Write out to permanent storage
-  if(s_oParamTables.StringParamTable[iParameter - FIRST_SP].persistent)
-    SaveSetting(s_oParamTables.StringParamTable[iParameter - FIRST_SP].regName, sValue);
+  if(stringparamtable[iParameter - FIRST_SP].persistent)
+    SaveSetting(stringparamtable[iParameter - FIRST_SP].regName, sValue);
 }
 
-bool CSettingsStore::GetBoolParameter(int iParameter) {
+bool CSettingsStore::GetBoolParameter(int iParameter) const {
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == s_oParamTables.BoolParamTable[iParameter - FIRST_BP].key);
+  DASHER_ASSERT(iParameter == boolparamtable[iParameter - FIRST_BP].key);
 
   // Return the value
-  return s_oParamTables.BoolParamTable[iParameter - FIRST_BP].value;
+  return boolParamValues[iParameter - FIRST_BP];
 }
 
-long CSettingsStore::GetLongParameter(int iParameter) {
+long CSettingsStore::GetLongParameter(int iParameter) const {
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == s_oParamTables.LongParamTable[iParameter - FIRST_LP].key);
+  DASHER_ASSERT(iParameter == longparamtable[iParameter - FIRST_LP].key);
 
   // Return the value
-  return s_oParamTables.LongParamTable[iParameter - FIRST_LP].value;
+  return longParamValues[iParameter - FIRST_LP];
 }
 
-std::string CSettingsStore::GetStringParameter(int iParameter) {
+const std::string &CSettingsStore::GetStringParameter(int iParameter) const {
   // Check that the parameter is in fact in the right spot in the table
-  DASHER_ASSERT(iParameter == s_oParamTables.StringParamTable[iParameter - FIRST_SP].key);
+  DASHER_ASSERT(iParameter == stringparamtable[iParameter - FIRST_SP].key);
 
   // Return the value
-  return s_oParamTables.StringParamTable[iParameter - FIRST_SP].value;
+  return stringParamValues[iParameter - FIRST_SP];
 }
 
 void CSettingsStore::ResetParameter(int iParameter) {
@@ -210,54 +211,6 @@ void CSettingsStore::ResetParameter(int iParameter) {
   }
 }
 
-// Used to determine what data type a given parameter ID is.
-ParameterType CSettingsStore::GetParameterType(int iParameter)
-{
-  if ((iParameter >= FIRST_BP) && (iParameter < FIRST_LP))
-    return ParamBool;
-  if ((iParameter >= FIRST_LP) && (iParameter < FIRST_SP))
-    return ParamLong;
-  if ((iParameter >= FIRST_SP) && (iParameter < END_OF_SPS))
-    return ParamString;
-
-  return ParamInvalid;
-}
-
-// Gets the string name for the given parameter
-std::string CSettingsStore::GetParameterName(int iParameter)
-{
-  // Pull the registry name out of the correct table depending on the parameter type
-  switch (GetParameterType(iParameter))
-  {
-  case (ParamBool):
-    {
-      DASHER_ASSERT(iParameter == s_oParamTables.BoolParamTable[iParameter - FIRST_BP].key);
-      return s_oParamTables.BoolParamTable[iParameter - FIRST_BP].regName;
-      break;
-    }
-  case (ParamLong):
-    {
-      DASHER_ASSERT(iParameter == s_oParamTables.LongParamTable[iParameter - FIRST_LP].key);
-      return s_oParamTables.LongParamTable[iParameter - FIRST_LP].regName;
-      break;
-    }
-  case (ParamString):
-    {
-      DASHER_ASSERT(iParameter == s_oParamTables.StringParamTable[iParameter - FIRST_SP].key);
-      return s_oParamTables.StringParamTable[iParameter - FIRST_SP].regName;
-      break;
-    }
-  case ParamInvalid:
-    // TODO: Error handling?
-    break;
-  };
-
-
-  return "";
-}
-
-
-
 /* Private functions -- Settings are not saved between sessions unless these
 functions are over-ridden.
 --------------------------------------------------------------------------*/
@@ -282,3 +235,42 @@ void CSettingsStore::SaveSetting(const std::string &Key, long Value) {
 
 void CSettingsStore::SaveSetting(const std::string &Key, const std::string &Value) {
 }
+
+/* SettingsUser and SettingsObserver definitions... */
+
+CSettingsUser::CSettingsUser(CSettingsStore *pSettingsStore) {
+  //ATM, we only allow one settings store, total...
+  DASHER_ASSERT(s_pSettingsStore==NULL);
+  //but in future, remove that if we're allowing multiple settings stores to exist
+  // concurrently.
+  s_pSettingsStore = pSettingsStore;
+}
+
+CSettingsUser::CSettingsUser(CSettingsUser *pCreateFrom) {
+  //No need to do anything atm; but in future, copy CSettingsStore pointer
+  // from argument.
+  DASHER_ASSERT(pCreateFrom);
+}
+
+CSettingsUser::~CSettingsUser() {
+}
+
+bool CSettingsUser::GetBoolParameter(int iParameter) const {return s_pSettingsStore->GetBoolParameter(iParameter);}
+long CSettingsUser::GetLongParameter(int iParameter) const {return s_pSettingsStore->GetLongParameter(iParameter);}
+const std::string &CSettingsUser::GetStringParameter(int iParameter) const {return s_pSettingsStore->GetStringParameter(iParameter);}
+void CSettingsUser::SetBoolParameter(int iParameter, bool bValue) {s_pSettingsStore->SetBoolParameter(iParameter, bValue);}
+void CSettingsUser::SetLongParameter(int iParameter, long lValue) {s_pSettingsStore->SetLongParameter(iParameter, lValue);}
+void CSettingsUser::SetStringParameter(int iParameter, const std::string &strValue) {s_pSettingsStore->SetStringParameter(iParameter, strValue);}
+
+CSettingsObserver::CSettingsObserver(CSettingsUser *pCreateFrom) {
+  DASHER_ASSERT(pCreateFrom);
+  s_pSettingsStore->Register(this);
+}
+
+CSettingsObserver::~CSettingsObserver() {
+  s_pSettingsStore->Unregister(this);
+}
+
+CSettingsUserObserver::CSettingsUserObserver(CSettingsUser *pCreateFrom)
+: CSettingsUser(pCreateFrom), CSettingsObserver(pCreateFrom) {
+}
diff --git a/Src/DasherCore/SettingsStore.h b/Src/DasherCore/SettingsStore.h
index 32d319f..08d5e5d 100644
--- a/Src/DasherCore/SettingsStore.h
+++ b/Src/DasherCore/SettingsStore.h
@@ -10,40 +10,36 @@
 #define __SettingsStore_h__
 
 #include <string>
-#include <map>
+#include "Observable.h"
 #include "Parameters.h"
 
 namespace Dasher {
-  class CEventHandler;
-  class CParameterNotificationEvent;
-}
-
-class Dasher::CEventHandler;
-class Dasher::CParameterNotificationEvent;
-
-// Types that are parameters can be
-enum ParameterType
-{
-  ParamBool,
-  ParamLong,
-  ParamString,
-  ParamInvalid
-};
-
 /// \ingroup Core
 /// @{
 
 /// \brief Abstract representation of persistant storage.
 ///
+/// Stores current runtime _values_ of all BP_, LP_, and SP_ preferences;
+/// subclasses may load these from and persist them to disk;
+/// is also an Observable for things that want to be notified when prefs change.
+///
+/// At present we allow for only one global SettingsStore across the whole of Dasher,
+/// but the framework should allow for multiple SettingsStores with only minor changes.
+/// (The exact use case for multiple SettingsStore's is not clear, and one suggestion is
+/// that they should all share the same runtime data - perhaps persisting to different
+/// locations. This requires only (a) defining SettingsObservers which persist changes
+/// to arbitrary locations, or (b) make the actual pref-value data static i.e. shared
+/// between instances.)
+///
 /// The public interface uses UTF-8 strings. All Keys should be
 /// in American English and encodable in ASCII. However,
 /// string Values may contain special characters where appropriate.
-class CSettingsStore {
+  class CSettingsStore : public Observable<int> {
 public:
 
-  CSettingsStore(Dasher::CEventHandler * pEventHandler);
+  CSettingsStore();
 
-  virtual ~ CSettingsStore() {
+  virtual ~CSettingsStore() {
   };
 
   // New functions for event driven interface
@@ -52,19 +48,19 @@ public:
   void SetLongParameter(int iParameter, long lValue);
   void SetStringParameter(int iParameter, const std::string sValue);
 
-  bool GetBoolParameter(int iParameter);
-  long GetLongParameter(int iParameter);
-  std::string GetStringParameter(int iParameter);
+  bool GetBoolParameter(int iParameter) const;
+  long GetLongParameter(int iParameter) const;
+  const std::string &GetStringParameter(int iParameter) const;
 
   void ResetParameter(int iParameter);
 
-  ParameterType   GetParameterType(int iParameter);
-  std::string     GetParameterName(int iParameter);
-
-  void LoadPersistent();
-
   const char *ClSet(const std::string &strKey, const std::string &strValue);
-
+    
+protected:
+    ///Loads all (persistent) prefs from disk, using+storing default values when no
+    /// existing value stored; non-persistent prefs are reinitialized from defaults.
+    void LoadPersistent();
+    
 private:
   // Platform Specific settings file management
 
@@ -109,14 +105,59 @@ private:
   //! \param Value Value of the setting, UTF8 encoded
   virtual void SaveSetting(const std::string & Key, const std::string & Value);
 
-protected:
-  Dasher::CEventHandler * m_pEventHandler;
-
-  // This is where the settings are, should only be one in existance
-  // derived classes should share this reference
-
-  static Dasher::CParamTables s_oParamTables;
+  //actually store the settings data...
+  bool boolParamValues[NUM_OF_BPS];
+  long longParamValues[NUM_OF_LPS];
+  std::string stringParamValues[NUM_OF_SPS];
 };
+  /// Superclass for anything that wants to use/access/store persistent settings.
+  /// (The nearest thing remaining to the old CDasherComponent,
+  /// but more of a mixin rather than a universal superclass.)
+  /// At the moment, _all_ clients share a single SettingsStore (static),
+  /// but for future-proofing in case we ever want more than one SettingsStore
+  /// (this has been suggested), SettingsUsers can only be created from other
+  /// SettingsUsers (i.e. in a tree), so _could_ be modified to copy a SettingsStore
+  /// pointer from the creator to inherit settings.
+  class CSettingsUser {
+  private:
+    friend class CDasherInterfaceBase;
+    ///Create the root of the SettingsUser hierarchy from a SettingsStore.
+    /// ATM we allow only one SettingsStore, so this c'tor is private and 
+    /// used only by the DasherInterface; if/when multiple SettingsStores
+    /// are used, could be made public.
+    CSettingsUser(CSettingsStore *pSettingsStore);
+  public:
+    virtual ~CSettingsUser();
+  protected:
+    ///Create a new SettingsUser, inheriting+sharing settings from the creator.
+    CSettingsUser(CSettingsUser *pCreateFrom);
+    bool GetBoolParameter(int iParameter) const;
+    long GetLongParameter(int iParameter) const;
+    const std::string &GetStringParameter(int iParameter) const;
+    void SetBoolParameter(int iParameter, bool bValue);
+    void SetLongParameter(int iParameter, long lValue);
+    void SetStringParameter(int iParameter, const std::string &strValue);
+  };
+  ///Superclass for anything that wants to be notified when settings change.
+  /// (Note inherited pure virtual HandleEvent(int) method, called when any pref changes).
+  ///Exists as a distinct class from CSettingsUserObserver (below) to get round C++'s
+  /// multiple inheritance problems, i.e. for indirect subclasses of CSettingsUser
+  /// wanting to introduce settings-listener capabilities.
+  ///Note we don't inherit from TransientObserver as it saves storing the SettingsStore ptr
+  /// in every instance; if we move to multiple settings stores, we could so inherit.
+  class CSettingsObserver : public Observer<int> {
+  public:
+    ///Create a CSettingsObserver listening to changes to the settings values
+    /// used by a particular CSettingsUser.
+    CSettingsObserver(CSettingsUser *pCreateFrom);
+    ~CSettingsObserver();
+  };
+  ///Utility class, for (majority of) cases where a class wants to be both
+  /// a CSettingsUser and CSettingsObserver.
+  class CSettingsUserObserver : public CSettingsUser, public CSettingsObserver {
+  public:
+    CSettingsUserObserver(CSettingsUser *pCreateFrom);
+  };
 /// @}
-
+}
 #endif /* #ifndef __SettingsStore_h__ */
diff --git a/Src/DasherCore/SocketInput.cpp b/Src/DasherCore/SocketInput.cpp
index 3ecee0a..a5e0a01 100644
--- a/Src/DasherCore/SocketInput.cpp
+++ b/Src/DasherCore/SocketInput.cpp
@@ -16,8 +16,8 @@
 
 using namespace Dasher;
 
-CSocketInput::CSocketInput(CMessageDisplay *pMsgs, CEventHandler *pEventHandler, CSettingsStore *pSettingsStore)
-:CSocketInputBase(pMsgs, pEventHandler, pSettingsStore) {
+CSocketInput::CSocketInput(CSettingsUser *pCreator, CMessageDisplay *pMsgs)
+:CSocketInputBase(pCreator, pMsgs) {
 }
 
 CSocketInput::~CSocketInput() {
diff --git a/Src/DasherCore/SocketInput.h b/Src/DasherCore/SocketInput.h
index 9adf5b0..e7e0479 100644
--- a/Src/DasherCore/SocketInput.h
+++ b/Src/DasherCore/SocketInput.h
@@ -8,8 +8,7 @@
 #define __SocketInput_h__
 
 #include "./SocketInputBase.h"
-#include "./DasherComponent.h"
-#include "./EventHandler.h"
+#include "./Observable.h"
 
 #include <iostream>
 #include <pthread.h>
@@ -45,7 +44,7 @@ class CSocketInput:public CSocketInputBase {
 
 public:
 
-  CSocketInput(CMessageDisplay *pMsgs, CEventHandler * pEventHandler, CSettingsStore * pSettingsStore);
+  CSocketInput(CSettingsUser *pCreator, CMessageDisplay *pMsgs);
   ~CSocketInput();
 
 private:
diff --git a/Src/DasherCore/SocketInputBase.cpp b/Src/DasherCore/SocketInputBase.cpp
index d4ff09c..fe59bcb 100644
--- a/Src/DasherCore/SocketInputBase.cpp
+++ b/Src/DasherCore/SocketInputBase.cpp
@@ -34,8 +34,8 @@ static SModuleSettings sSettings[] = {
   {BP_SOCKET_DEBUG, T_BOOL, -1, -1, -1, -1, _("Print socket-related debugging information to console:")}
 };
 
-Dasher::CSocketInputBase::CSocketInputBase(CMessageDisplay *pMsgs, CEventHandler * pEventHandler, CSettingsStore * pSettingsStore) 
-  : CScreenCoordInput(pEventHandler, pSettingsStore, 1, _("Socket Input")), m_pMsgs(pMsgs) {
+Dasher::CSocketInputBase::CSocketInputBase(CSettingsUser *pCreator, CMessageDisplay *pMsgs)
+  : CScreenCoordInput(1, _("Socket Input")), CSettingsUserObserver(pCreator), m_pMsgs(pMsgs) {
   port = -1;
   debug_socket_input = false;
   readerRunning = false;
@@ -65,33 +65,30 @@ Dasher::CSocketInputBase::~CSocketInputBase() {
   // Instead, you should call StopListening in the derived class's destructor.
 }
 
-void Dasher::CSocketInputBase::HandleEvent(Dasher::CEvent *pEvent) {
-  if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-    switch (pEvt->m_iParameter) {
-    case LP_SOCKET_PORT:
-      SetReaderPort(GetLongParameter(LP_SOCKET_PORT));
-      break;
-    case SP_SOCKET_INPUT_X_LABEL:
-      SetCoordinateLabel(0, GetStringParameter(SP_SOCKET_INPUT_X_LABEL).c_str());
-      break;
-    case SP_SOCKET_INPUT_Y_LABEL:
-      SetCoordinateLabel(1, GetStringParameter(SP_SOCKET_INPUT_Y_LABEL).c_str());
-      break;
-    case LP_SOCKET_INPUT_X_MIN:
-    case LP_SOCKET_INPUT_X_MAX:
-      SetRawRange(0, ((double)GetLongParameter(LP_SOCKET_INPUT_X_MIN)) / 1000.0, ((double)GetLongParameter(LP_SOCKET_INPUT_X_MAX)) / 1000.0);
-      break;
-    case LP_SOCKET_INPUT_Y_MIN:
-    case LP_SOCKET_INPUT_Y_MAX:
-      SetRawRange(1, ((double)GetLongParameter(LP_SOCKET_INPUT_Y_MIN)) / 1000.0, ((double)GetLongParameter(LP_SOCKET_INPUT_Y_MAX)) / 1000.0);
-      break;
-    case BP_SOCKET_DEBUG:
-      SetDebug(GetBoolParameter(BP_SOCKET_DEBUG));
-      break;
-    default:
-      break;
-    }
+void Dasher::CSocketInputBase::HandleEvent(int iParameter) {
+  switch (iParameter) {
+  case LP_SOCKET_PORT:
+    SetReaderPort(GetLongParameter(LP_SOCKET_PORT));
+    break;
+  case SP_SOCKET_INPUT_X_LABEL:
+    SetCoordinateLabel(0, GetStringParameter(SP_SOCKET_INPUT_X_LABEL).c_str());
+    break;
+  case SP_SOCKET_INPUT_Y_LABEL:
+    SetCoordinateLabel(1, GetStringParameter(SP_SOCKET_INPUT_Y_LABEL).c_str());
+    break;
+  case LP_SOCKET_INPUT_X_MIN:
+  case LP_SOCKET_INPUT_X_MAX:
+    SetRawRange(0, ((double)GetLongParameter(LP_SOCKET_INPUT_X_MIN)) / 1000.0, ((double)GetLongParameter(LP_SOCKET_INPUT_X_MAX)) / 1000.0);
+    break;
+  case LP_SOCKET_INPUT_Y_MIN:
+  case LP_SOCKET_INPUT_Y_MAX:
+    SetRawRange(1, ((double)GetLongParameter(LP_SOCKET_INPUT_Y_MIN)) / 1000.0, ((double)GetLongParameter(LP_SOCKET_INPUT_Y_MAX)) / 1000.0);
+    break;
+  case BP_SOCKET_DEBUG:
+    SetDebug(GetBoolParameter(BP_SOCKET_DEBUG));
+    break;
+  default:
+    break;
   }
 }
 
diff --git a/Src/DasherCore/SocketInputBase.h b/Src/DasherCore/SocketInputBase.h
index 2da884f..3c6d97b 100644
--- a/Src/DasherCore/SocketInputBase.h
+++ b/Src/DasherCore/SocketInputBase.h
@@ -7,9 +7,8 @@
 #ifndef __socketinputbase_h__
 #define __socketinputbase_h__
 
-#include "../DasherCore/DasherInput.h"
-#include "../DasherCore/DasherComponent.h"
-#include "../DasherCore/EventHandler.h"
+#include "DasherInput.h"
+#include "SettingsStore.h"
 #include "Messages.h"
 
 #include <iostream>
@@ -23,15 +22,15 @@ namespace Dasher {
 using namespace std;
 /// \ingroup Input 
 /// \{
-class CSocketInputBase : public CScreenCoordInput {
+class CSocketInputBase : public CScreenCoordInput, public CSettingsUserObserver {
 
 public:
 
-  CSocketInputBase(CMessageDisplay *pMsgs, CEventHandler * pEventHandler, CSettingsStore * pSettingsStore);
+  CSocketInputBase(CSettingsUser *pCreator, CMessageDisplay *pMsgs);
 
   virtual ~CSocketInputBase();
 
-  virtual void HandleEvent(CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
 
   virtual void SetDebug(bool _debug);
 
diff --git a/Src/DasherCore/StartHandler.h b/Src/DasherCore/StartHandler.h
index e3d7d0e..e309bac 100644
--- a/Src/DasherCore/StartHandler.h
+++ b/Src/DasherCore/StartHandler.h
@@ -2,17 +2,17 @@
 #define __START_HANDLER_H__
 
 #include "DasherInterfaceBase.h"
-#include "DasherComponent.h"
+
 namespace Dasher {
 /// \defgroup Start Start handlers
 /// @{
-class CStartHandler : public CDasherComponent {
+class CStartHandler {
 public:
-  CStartHandler(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface) 
-    : CDasherComponent(pEventHandler, pSettingsStore) {
-    m_pInterface = pInterface;
+  CStartHandler(CDasherInterfaceBase *pInterface) : m_pInterface(pInterface) {
   };
-
+  virtual ~CStartHandler() {
+  }
+  
   virtual bool DecorateView(CDasherView *pView) = 0;
   virtual void Timer(int iTime, dasherint iX, dasherint iY, CDasherView *pView) = 0;
 
diff --git a/Src/DasherCore/StylusFilter.cpp b/Src/DasherCore/StylusFilter.cpp
index 436ca46..9f5d9e7 100644
--- a/Src/DasherCore/StylusFilter.cpp
+++ b/Src/DasherCore/StylusFilter.cpp
@@ -6,8 +6,8 @@
 
 using namespace Dasher;
 
-CStylusFilter::CStylusFilter(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
-  : CDefaultFilter(pEventHandler, pSettingsStore, pInterface, iID, szName) {
+CStylusFilter::CStylusFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
+  : CDefaultFilter(pCreator, pInterface, iID, szName) {
 }
 
 bool CStylusFilter::Timer(unsigned long iTime, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CExpansionPolicy **pol)
@@ -43,7 +43,7 @@ void CStylusFilter::KeyUp(int iTime, int iId, CDasherView *pView, CDasherInput *
 }
 
 void CStylusFilter::ApplyClickTransform(myint &iDasherX, myint &iDasherY, CDasherView *pView) {
-  CClickFilter::AdjustZoomCoords(iDasherX, iDasherY, pView);
+  CZoomAdjuster(this).AdjustZoomCoords(iDasherX, iDasherY, pView);
 }
 
 CStartHandler *CStylusFilter::MakeStartHandler() {
diff --git a/Src/DasherCore/StylusFilter.h b/Src/DasherCore/StylusFilter.h
index 6c6394c..adb7f6e 100644
--- a/Src/DasherCore/StylusFilter.h
+++ b/Src/DasherCore/StylusFilter.h
@@ -2,13 +2,14 @@
 #define __STYLUS_FILTER_H__
 
 #include "DefaultFilter.h"
+#include "ClickFilter.h"
 
 /// \ingroup InputFilter
 /// @{
 namespace Dasher {
 class CStylusFilter : public CDefaultFilter {
  public:
-  CStylusFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
+  CStylusFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName);
   ///Override DefaultFilter (which supports pause), as we don't
   /// - motion requires continually holding stylus against screen
   virtual bool supportsPause() {return false;}
@@ -17,9 +18,7 @@ class CStylusFilter : public CDefaultFilter {
   virtual void KeyUp(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel);
  protected:
   ///Transform coordinates of a click, to get location to zoom into.
-  /// Default is to call CClickFilter::AdjustZoomCoords, which adds
-  /// a safety margin according to LP_S, checks we don't exceed the
-  /// zoom factor given by LP_MAXZOOM, and ensures x>=2.
+  /// Default is to call the same CZoomAdjuster::AdjustZoomCoords as CClickFilter
   virtual void ApplyClickTransform(myint &iDasherX, myint &iDasherY, CDasherView *pView);
   ///Do not make a start handler when in stylus mode
   virtual CStartHandler *MakeStartHandler();
diff --git a/Src/DasherCore/TwoBoxStartHandler.cpp b/Src/DasherCore/TwoBoxStartHandler.cpp
index af83286..21f9d9a 100644
--- a/Src/DasherCore/TwoBoxStartHandler.cpp
+++ b/Src/DasherCore/TwoBoxStartHandler.cpp
@@ -3,8 +3,8 @@
 
 using namespace Dasher;
 
-CTwoBoxStartHandler::CTwoBoxStartHandler(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface)
-: CStartHandler(pEventHandler, pSettingsStore, pInterface), m_bFirstBox(true), m_iBoxEntered(std::numeric_limits<long>::max()) {
+CTwoBoxStartHandler::CTwoBoxStartHandler(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+: CStartHandler(pInterface), CSettingsUserObserver(pCreator), m_bFirstBox(true), m_iBoxEntered(std::numeric_limits<long>::max()) {
 }
 
 bool CTwoBoxStartHandler::DecorateView(CDasherView *pView) {
@@ -63,11 +63,7 @@ void CTwoBoxStartHandler::Timer(int iTime, dasherint iDasherX, dasherint iDasher
   }
 }
 
-void CTwoBoxStartHandler::HandleEvent(Dasher::CEvent * pEvent) {
-    if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-   
-    if (pEvt->m_iParameter==BP_DASHER_PAUSED)
-      m_bFirstBox = true;
-  }
+void CTwoBoxStartHandler::HandleEvent(int iParameter) {
+  if (iParameter==BP_DASHER_PAUSED)
+    m_bFirstBox = true;
 }
diff --git a/Src/DasherCore/TwoBoxStartHandler.h b/Src/DasherCore/TwoBoxStartHandler.h
index 34c483a..ae04886 100644
--- a/Src/DasherCore/TwoBoxStartHandler.h
+++ b/Src/DasherCore/TwoBoxStartHandler.h
@@ -6,13 +6,13 @@
 namespace Dasher {
 /// \ingroup Start
 /// @{
-class CTwoBoxStartHandler : public CStartHandler {
+class CTwoBoxStartHandler : public CStartHandler, public CSettingsUserObserver {
 public:
-  CTwoBoxStartHandler(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, CDasherInterfaceBase *pInterface);
+  CTwoBoxStartHandler(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface);
 
   virtual bool DecorateView(CDasherView *pView);
   virtual void Timer(int iTime, dasherint iX, dasherint iY, CDasherView *pView);
-  virtual void HandleEvent(Dasher::CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
 
  private:
   ///Box currently being displayed, _iff_ BP_DASHER_PAUSED is set
diff --git a/Src/DasherCore/TwoButtonDynamicFilter.cpp b/Src/DasherCore/TwoButtonDynamicFilter.cpp
index 0c26c1b..1fc830d 100644
--- a/Src/DasherCore/TwoButtonDynamicFilter.cpp
+++ b/Src/DasherCore/TwoButtonDynamicFilter.cpp
@@ -48,12 +48,11 @@ static SModuleSettings sSettings[] = {
   {LP_DYNAMIC_SPEED_DEC, T_LONG, 1, 99, 1, 1, _("Percentage by which to decrease speed upon reverse")}
 };
 
-CTwoButtonDynamicFilter::CTwoButtonDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface)
-  : CButtonMultiPress(pEventHandler, pSettingsStore, pInterface, 14, _("Two Button Dynamic Mode"))
+CTwoButtonDynamicFilter::CTwoButtonDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+  : CButtonMultiPress(pCreator, pInterface, 14, _("Two Button Dynamic Mode"))
 {
   //ensure that m_dLagMul is properly initialised
-  Dasher::CParameterNotificationEvent oEvent(LP_DYNAMIC_BUTTON_LAG);
-  HandleEvent(&oEvent);
+  HandleEvent(LP_DYNAMIC_BUTTON_LAG);
 }
 
 bool CTwoButtonDynamicFilter::DecorateView(CDasherView *pView, CDasherInput *pInput) {
@@ -192,24 +191,19 @@ bool CTwoButtonDynamicFilter::GetMinWidth(int &iMinWidth) {
   return true;
 }
 
-void CTwoButtonDynamicFilter::HandleEvent(Dasher::CEvent *pEvent)
+void CTwoButtonDynamicFilter::HandleEvent(int iParameter)
 {
-  if (pEvent->m_iEventType == EV_PARAM_NOTIFY)
-  {
-    Dasher::CParameterNotificationEvent *pEvt = static_cast<Dasher::CParameterNotificationEvent *>(pEvent);
-    switch (pEvt->m_iParameter)
+  switch (iParameter) {
+  case LP_MAX_BITRATE:
+  case LP_BOOSTFACTOR: // Deliberate fallthrough
+  case LP_DYNAMIC_BUTTON_LAG:
     {
-    case LP_MAX_BITRATE:
-    case LP_BOOSTFACTOR: // Deliberate fallthrough
-    case LP_DYNAMIC_BUTTON_LAG:
-      {
-        double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
-        m_dLagMul = exp(dMaxRate * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0);
-        //and fallthrough again:
-      }
-    case LP_TWO_BUTTON_OFFSET:
-        m_bDecorationChanged = true;
+      double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
+      m_dLagMul = exp(dMaxRate * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0);
+      //and fallthrough again:
     }
+  case LP_TWO_BUTTON_OFFSET:
+      m_bDecorationChanged = true;
   }
-  CDynamicFilter::HandleEvent(pEvent);
+  CDynamicFilter::HandleEvent(iParameter);
 }
diff --git a/Src/DasherCore/TwoButtonDynamicFilter.h b/Src/DasherCore/TwoButtonDynamicFilter.h
index 6fd3445..b16762e 100644
--- a/Src/DasherCore/TwoButtonDynamicFilter.h
+++ b/Src/DasherCore/TwoButtonDynamicFilter.h
@@ -30,7 +30,7 @@ namespace Dasher {
 /// @{
 class CTwoButtonDynamicFilter : public CButtonMultiPress {
  public:
-  CTwoButtonDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface);
+  CTwoButtonDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface);
 
   // Inherited methods
   virtual bool DecorateView(CDasherView *pView, CDasherInput *pInput);
@@ -42,7 +42,7 @@ class CTwoButtonDynamicFilter : public CButtonMultiPress {
 
   virtual bool GetMinWidth(int &iMinWidth);
 
-  virtual void HandleEvent(Dasher::CEvent *pEvent);
+  virtual void HandleEvent(int iParameter);
   
  protected:
   virtual void run();
diff --git a/Src/DasherCore/TwoPushDynamicFilter.cpp b/Src/DasherCore/TwoPushDynamicFilter.cpp
index 8f09f59..d0de1de 100644
--- a/Src/DasherCore/TwoPushDynamicFilter.cpp
+++ b/Src/DasherCore/TwoPushDynamicFilter.cpp
@@ -43,11 +43,10 @@ static SModuleSettings sSettings[] = {
   {LP_DYNAMIC_BUTTON_LAG, T_LONG, 0, 1000, 1, 25, _("Lag before user actually pushes button (ms)")}, 
 };
 
-CTwoPushDynamicFilter::CTwoPushDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface)
-  : CDynamicFilter(pEventHandler, pSettingsStore, pInterface, 14, _("Two-push Dynamic Mode (New One Button)")), m_dNatsSinceFirstPush(-std::numeric_limits<double>::infinity()) {
+CTwoPushDynamicFilter::CTwoPushDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface)
+  : CDynamicFilter(pCreator, pInterface, 14, _("Two-push Dynamic Mode (New One Button)")), m_dNatsSinceFirstPush(-std::numeric_limits<double>::infinity()) {
   
-  Dasher::CParameterNotificationEvent oEvent(LP_TWO_PUSH_OUTER);//and all the others too!
-  HandleEvent(&oEvent);
+  HandleEvent(LP_TWO_PUSH_OUTER);//and all the others too!
 }
 
 void GuideLine(CDasherView *pView, const myint iDasherY, const int iColour)
@@ -100,75 +99,71 @@ bool CTwoPushDynamicFilter::DecorateView(CDasherView *pView, CDasherInput *pInpu
   return bRV;
 }
 
-void CTwoPushDynamicFilter::HandleEvent(Dasher::CEvent * pEvent)
+void CTwoPushDynamicFilter::HandleEvent(int iParameter)
 {
-  CDynamicFilter::HandleEvent(pEvent);
-  if(pEvent->m_iEventType == EV_PARAM_NOTIFY)
+  CDynamicFilter::HandleEvent(iParameter);
+  switch (iParameter)
   {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-    switch (pEvt->m_iParameter)
+    case LP_TWO_PUSH_OUTER:
+      if (GetLongParameter(LP_TWO_PUSH_OUTER)<=GetLongParameter(LP_TWO_PUSH_UP)) {
+        //two_push_outer being moved down; force two_push_up down too
+        SetLongParameter(LP_TWO_PUSH_UP, GetLongParameter(LP_TWO_PUSH_OUTER)-1);
+        return; // as HandleEvent on latter will execute same code (below)
+      }
+      //deliberate fallthrough
+    case LP_TWO_PUSH_UP:
+      if (GetLongParameter(LP_TWO_PUSH_UP)>=GetLongParameter(LP_TWO_PUSH_OUTER)) {
+        //two_push_up must have changed, or we'd have caught this in previous check for two_push_outer
+        SetLongParameter(LP_TWO_PUSH_OUTER, GetLongParameter(LP_TWO_PUSH_UP)+1);
+        return;
+      }
+      if (GetLongParameter(LP_TWO_PUSH_UP)<=GetLongParameter(LP_TWO_PUSH_DOWN)) {
+        SetLongParameter(LP_TWO_PUSH_DOWN, GetLongParameter(LP_TWO_PUSH_UP)-1);
+        return;
+      }
+      //deliberate fallthrough
+    case LP_TWO_PUSH_DOWN:
+      if (GetLongParameter(LP_TWO_PUSH_DOWN)>=GetLongParameter(LP_TWO_PUSH_UP)) {
+        SetLongParameter(LP_TWO_PUSH_UP, GetLongParameter(LP_TWO_PUSH_DOWN)+1);
+        return;
+      }
     {
-      case LP_TWO_PUSH_OUTER:
-        if (GetLongParameter(LP_TWO_PUSH_OUTER)<=GetLongParameter(LP_TWO_PUSH_UP)) {
-          //two_push_outer being moved down; force two_push_up down too
-          SetLongParameter(LP_TWO_PUSH_UP, GetLongParameter(LP_TWO_PUSH_OUTER)-1);
-          return; // as HandleEvent on latter will execute same code (below)
-        }
-        //deliberate fallthrough
-      case LP_TWO_PUSH_UP:
-        if (GetLongParameter(LP_TWO_PUSH_UP)>=GetLongParameter(LP_TWO_PUSH_OUTER)) {
-          //two_push_up must have changed, or we'd have caught this in previous check for two_push_outer
-          SetLongParameter(LP_TWO_PUSH_OUTER, GetLongParameter(LP_TWO_PUSH_UP)+1);
-          return;
-        }
-        if (GetLongParameter(LP_TWO_PUSH_UP)<=GetLongParameter(LP_TWO_PUSH_DOWN)) {
-          SetLongParameter(LP_TWO_PUSH_DOWN, GetLongParameter(LP_TWO_PUSH_UP)-1);
-          return;
-        }
-        //deliberate fallthrough
-      case LP_TWO_PUSH_DOWN:
-        if (GetLongParameter(LP_TWO_PUSH_DOWN)>=GetLongParameter(LP_TWO_PUSH_UP)) {
-          SetLongParameter(LP_TWO_PUSH_UP, GetLongParameter(LP_TWO_PUSH_DOWN)+1);
-          return;
-        }
-      {
-		//TODO, that means short gap at the top - allow other way around also?
+  //TODO, that means short gap at the top - allow other way around also?
 
-	double dOuter = GetLongParameter(LP_TWO_PUSH_OUTER);
-	m_dLogUpMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_UP));
-	m_dLogDownMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_DOWN));
+double dOuter = GetLongParameter(LP_TWO_PUSH_OUTER);
+m_dLogUpMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_UP));
+m_dLogDownMul = log(dOuter / (double)GetLongParameter(LP_TWO_PUSH_DOWN));
 //cout << "bitsUp " << m_dLogUpMul << " bitsDown " << m_dLogDownMul << "\n";
-      } //and fallthrough
-      case LP_TWO_PUSH_TOLERANCE:
-      case LP_MAX_BITRATE:
-      case LP_BOOSTFACTOR: // Deliberate fallthrough
-      {
-	double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
-	double dPressBits = dMaxRate * (double) GetLongParameter(LP_TWO_PUSH_TOLERANCE) / 1000.0;
+    } //and fallthrough
+    case LP_TWO_PUSH_TOLERANCE:
+    case LP_MAX_BITRATE:
+    case LP_BOOSTFACTOR: // Deliberate fallthrough
+    {
+double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
+double dPressBits = dMaxRate * (double) GetLongParameter(LP_TWO_PUSH_TOLERANCE) / 1000.0;
 //cout << "Max Bitrate changed - now " << dMaxRate << " user accuracy " << dPressBits;
-	m_dMinShortTwoPushTime = m_dLogUpMul - dPressBits;
+m_dMinShortTwoPushTime = m_dLogUpMul - dPressBits;
 //cout << "bits; minShort " << m_dMinShortTwoPushTime;
-	m_dMaxShortTwoPushTime = m_dLogUpMul + dPressBits;
-	m_dMinLongTwoPushTime = m_dLogDownMul - dPressBits;
-	if (m_dMaxShortTwoPushTime > m_dMinLongTwoPushTime)
-          m_dMaxShortTwoPushTime = m_dMinLongTwoPushTime = (m_dLogUpMul + m_dLogDownMul)/2.0;
-	m_dMaxLongTwoPushTime = m_dLogDownMul + dPressBits;
+m_dMaxShortTwoPushTime = m_dLogUpMul + dPressBits;
+m_dMinLongTwoPushTime = m_dLogDownMul - dPressBits;
+if (m_dMaxShortTwoPushTime > m_dMinLongTwoPushTime)
+        m_dMaxShortTwoPushTime = m_dMinLongTwoPushTime = (m_dLogUpMul + m_dLogDownMul)/2.0;
+m_dMaxLongTwoPushTime = m_dLogDownMul + dPressBits;
 //TODO, what requirements do we actually need to make to ensure sanity (specifically, that computed m_aiTarget's are in range)?
 //cout << " maxShort " << m_dMaxShortTwoPushTime << " minLong " << m_dMinLongTwoPushTime << " maxLong " << m_dMaxLongTwoPushTime << "\n";
-	m_bDecorationChanged = true;
-     }  //and fallthrough again
-     case LP_DYNAMIC_BUTTON_LAG:
-     {
-       double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
-       m_dLagBits = dMaxRate * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0;
-  //cout << " lag (" << m_dLagBits[0] << ", " << m_dLagBits[1] << ", " << m_dLagBits[2] << ", " << m_dLagBits[3] << ")";
-       m_aaiGuideAreas[0][0] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMaxShortTwoPushTime);
-       m_aaiGuideAreas[0][1] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMinShortTwoPushTime);
-       m_aaiGuideAreas[1][0] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMinLongTwoPushTime);
-       m_aaiGuideAreas[1][1] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMaxLongTwoPushTime);
-	     break;
-     }
-    }
+m_bDecorationChanged = true;
+   }  //and fallthrough again
+   case LP_DYNAMIC_BUTTON_LAG:
+   {
+     double dMaxRate = GetLongParameter(LP_MAX_BITRATE) * GetLongParameter(LP_BOOSTFACTOR) / 10000.0;
+     m_dLagBits = dMaxRate * GetLongParameter(LP_DYNAMIC_BUTTON_LAG)/1000.0;
+//cout << " lag (" << m_dLagBits[0] << ", " << m_dLagBits[1] << ", " << m_dLagBits[2] << ", " << m_dLagBits[3] << ")";
+     m_aaiGuideAreas[0][0] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMaxShortTwoPushTime);
+     m_aaiGuideAreas[0][1] = 2048 - GetLongParameter(LP_TWO_PUSH_UP)*exp(m_dMinShortTwoPushTime);
+     m_aaiGuideAreas[1][0] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMinLongTwoPushTime);
+     m_aaiGuideAreas[1][1] = 2048 + GetLongParameter(LP_TWO_PUSH_DOWN)*exp(m_dMaxLongTwoPushTime);
+     break;
+   }
   }
 }
 
@@ -267,32 +262,11 @@ bool CTwoPushDynamicFilter::TimerImpl(unsigned long iTime, CDasherView *m_pDashe
   return true;
 }
 
-void CTwoPushDynamicFilter::Activate() {
-  SetBoolParameter(BP_SMOOTH_OFFSET, true);
-}
-
-void CTwoPushDynamicFilter::Deactivate() {
-  SetBoolParameter(BP_SMOOTH_OFFSET, false);
-}
-
 void CTwoPushDynamicFilter::run() {
   m_dNatsSinceFirstPush = -std::numeric_limits<double>::infinity();
-  SetBoolParameter(BP_SMOOTH_OFFSET, true);
   CDynamicFilter::run();
 }
 
-void CTwoPushDynamicFilter::pause() {
-  SetBoolParameter(BP_SMOOTH_OFFSET, false);
-  CDynamicFilter::pause();
-}
-
-void CTwoPushDynamicFilter::reverse() {
-  //hmmmm. If we ever actually did Offset() while reversing,
-  // we might want BP_SMOOTH_OFFSET on....
-  SetBoolParameter(BP_SMOOTH_OFFSET, false);
-  CDynamicFilter::reverse();
-}
-
 bool CTwoPushDynamicFilter::GetSettings(SModuleSettings **pSettings, int *iCount) {
   *pSettings = sSettings;
   *iCount = sizeof(sSettings) / sizeof(SModuleSettings);
diff --git a/Src/DasherCore/TwoPushDynamicFilter.h b/Src/DasherCore/TwoPushDynamicFilter.h
index bfb7321..31f6545 100644
--- a/Src/DasherCore/TwoPushDynamicFilter.h
+++ b/Src/DasherCore/TwoPushDynamicFilter.h
@@ -27,13 +27,11 @@ namespace Dasher {
 /// @{
 class CTwoPushDynamicFilter : public CDynamicFilter /*long push, but do our own "multi-push" detection*/ {
  public:
-  CTwoPushDynamicFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface);
+  CTwoPushDynamicFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface);
   
   // Inherited methods
   virtual bool DecorateView(CDasherView *pView, CDasherInput *pInput);
  
-  virtual void Activate();
-  virtual void Deactivate();
   virtual bool GetMinWidth(int &iMinWidth);
   virtual bool GetSettings(SModuleSettings **pSettings, int *iCount);
 
@@ -45,11 +43,9 @@ class CTwoPushDynamicFilter : public CDynamicFilter /*long push, but do our own
   virtual bool TimerImpl(unsigned long Time, CDasherView *m_pDasherView, CDasherModel *m_pDasherModel, CExpansionPolicy **pol);
   virtual void ActionButton(int iTime, int iButton, int iType, CDasherModel *pModel, CUserLogBase *pUserLog);
 
-  virtual void HandleEvent(Dasher::CEvent * pEvent);
+  virtual void HandleEvent(int iParameter);
 
   virtual void run();
-  virtual void pause();
-  virtual void reverse();
 
  private:
   double m_dLogUpMul, m_dLogDownMul, m_dLagBits;
diff --git a/Src/DasherCore/UserLog.cpp b/Src/DasherCore/UserLog.cpp
index e49507e..fdc5861 100644
--- a/Src/DasherCore/UserLog.cpp
+++ b/Src/DasherCore/UserLog.cpp
@@ -20,6 +20,9 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
+using namespace Dasher;
+using namespace Dasher::Settings;
+
 static UserLogParamMask s_UserLogParamMaskTable [] = {
   {SP_ALPHABET_ID,          userLogParamOutputToSimple},
   {SP_COLOUR_ID,            userLogParamOutputToSimple},
@@ -42,10 +45,9 @@ static UserLogParamMask s_UserLogParamMaskTable [] = {
   {-1, -1}  // Flag value that should always be at the end
 };
 
-CUserLog::CUserLog(Dasher::CEventHandler *pEventHandler, 
-                   CSettingsStore *pSettingsStore, 
-                   int iLogTypeMask) : CUserLogBase(pEventHandler, pSettingsStore)
-{
+CUserLog::CUserLog(CSettingsUser *pCreateFrom,
+                   Observable<const CEditEvent *> *pObsv,
+                   int iLogTypeMask) : CUserLogBase(pCreateFrom, pObsv), CSettingsObserver(pCreateFrom) {
   //CFunctionLogger f1("CUserLog::CUserLog", g_pLogger);
 
   InitMemberVars();
@@ -63,11 +65,10 @@ CUserLog::CUserLog(Dasher::CEventHandler *pEventHandler,
   if (m_pApplicationSpan == NULL)
     g_pLogger->Log("CUserLog::CUserLog, failed to create m_pApplicationSpan!", logNORMAL);
 
-  // From the load test harness, we create object directly without a settings store
-  // and event handler.  In this case, we don't want to try and push the intial
-  // parameters.
-  if ((pEventHandler != NULL) && (pSettingsStore != NULL))
-    AddInitialParam();
+  // TODO: for the load test harness, we apparently need to create the object directly
+  // without a settings store (which will break CSettingsObserver, etc.); and then,
+  // don't call the following:
+  AddInitialParam();
 }
 
 CUserLog::~CUserLog()
@@ -670,34 +671,26 @@ void CUserLog::KeyDown(int iId, int iType, int iEffect) {
 }
   
 // This gets called whenever parameters get changed that we are tracking
-void CUserLog::HandleEvent(Dasher::CEvent* pEvent)
+void CUserLog::HandleEvent(int iParameter)
 {  
-  if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent* pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-
-    int i = 0;
+  int i = 0;
 
-    // Go through each of the parameters in our lookup table from UserLogParam.h.
-    // If the key matches the notification event, then we want to push the
-    // parameter change to the logging object.
-    while (s_UserLogParamMaskTable[i].key != -1)
+  // Go through each of the parameters in our lookup table from UserLogParam.h.
+  // If the key matches the notification event, then we want to push the
+  // parameter change to the logging object.
+  while (s_UserLogParamMaskTable[i].key != -1)
+  {
+    if (s_UserLogParamMaskTable[i].key == iParameter)
     {
-      int iParameter = pEvt->m_iParameter;
-
-      if (s_UserLogParamMaskTable[i].key == iParameter)
-      {
-        int iOptionMask = s_UserLogParamMaskTable[i].mask;
-
-        UpdateParam(iParameter, iOptionMask);
-        return;
-      }
+      int iOptionMask = s_UserLogParamMaskTable[i].mask;
 
-      i++;
+      UpdateParam(iParameter, iOptionMask);
+      return;
+    }
 
-    } // end while (s_UserLogParamMaskTable[i].key != -1)
+    i++;
 
-  } // end if (pEvent->m_iEventType == 1)
-  CUserLogBase::HandleEvent(pEvent);
+  } // end while (s_UserLogParamMaskTable[i].key != -1)
 }
 
 ////////////////////////////////////////// private methods ////////////////////////////////////////////////
@@ -1138,9 +1131,10 @@ void CUserLog::UpdateParam(int iParameter, int iOptionMask)
 ///////////////////////////////////////////////////////////////////////////////////////
 // Below here are methods that are just used in the standalone tool that reads in 
 // UserLog XML files and does cool things to them.  
+// TODO these are broken by settings rewrite. Fix???
 
 // Load the object from an XML file
-CUserLog::CUserLog(string strXMLFilename) : CUserLogBase(NULL, NULL)
+CUserLog::CUserLog(string strXMLFilename) : CUserLogBase(NULL, NULL), CSettingsObserver(NULL)
 {
   //CFunctionLogger f1("CUserLog::CUserLog(XML)", g_pLogger);
 
diff --git a/Src/DasherCore/UserLog.h b/Src/DasherCore/UserLog.h
index f3f07cf..a859417 100644
--- a/Src/DasherCore/UserLog.h
+++ b/Src/DasherCore/UserLog.h
@@ -36,6 +36,7 @@
 #include "UserLogBase.h"
 #include "Event.h"
 #include "XMLUtil.h"
+#include "SettingsStore.h"
 
 using namespace std;
 
@@ -72,11 +73,10 @@ typedef vector<VECTOR_STRING>::iterator     VECTOR_VECTOR_STRING_ITER;
 /// @{
 
 // We need to be notified when parameters we are logging get changed, so we'll
-// subclass CDasherComponent and implement the HandleEvent() method.
-class CUserLog : public CUserLogBase
-{
+// watch for <int> events from the SettingsStore too.
+class CUserLog : public CUserLogBase, public Dasher::CSettingsObserver {
 public:
-  CUserLog(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, int iLogTypeMask);
+  CUserLog(Dasher::CSettingsUser *pCreateFrom, Observable<const Dasher::CEditEvent *> *pHandler, int iLogTypeMask);
 
   ~CUserLog();
 
@@ -101,7 +101,7 @@ public:
   void                        SetOuputFilename(const string& strFilename = "");
   int                         GetLogLevelMask();
   void KeyDown(int iId, int iType, int iEffect);
-  void                        HandleEvent(Dasher::CEvent* pEvent);
+  void                        HandleEvent(int iParameter);
 
   // Methods used by utility that can post-process the log files:
   CUserLog(string strXMLFilename);
diff --git a/Src/DasherCore/UserLogBase.cpp b/Src/DasherCore/UserLogBase.cpp
index 23f5c99..5a1c170 100644
--- a/Src/DasherCore/UserLogBase.cpp
+++ b/Src/DasherCore/UserLogBase.cpp
@@ -10,19 +10,20 @@
 #include "UserLogBase.h"
 #include "Event.h"
 #include "DasherNode.h"
+#include "DasherInterfaceBase.h"
 
 using namespace Dasher;
 
-void CUserLogBase::HandleEvent(CEvent *pEvent) {
-  if (pEvent->m_iEventType == EV_EDIT) {
-    Dasher::CEditEvent *evt(static_cast<Dasher::CEditEvent *>(pEvent));
-    if (evt->m_iEditType == 1) {
-      m_vAdded.push_back(evt->m_pNode->GetSymbolProb(GetLongParameter(LP_NORMALIZATION)));
-      //output
-    } else if (evt->m_iEditType == 2) {
-      //delete
-      m_iNumDeleted++;
-    }
+CUserLogBase::CUserLogBase(CSettingsUser *pCreateFrom, Observable<const CEditEvent *> *pHandler) : CSettingsUser(pCreateFrom), TransientObserver<const CEditEvent *>(pHandler), m_iNumDeleted(0) {
+};
+
+void CUserLogBase::HandleEvent(const CEditEvent *evt) {
+  if (evt->m_iEditType == 1) {
+    m_vAdded.push_back(evt->m_pNode->GetSymbolProb(GetLongParameter(LP_NORMALIZATION)));
+    //output
+  } else if (evt->m_iEditType == 2) {
+    //delete
+    m_iNumDeleted++;
   }
 }
 
diff --git a/Src/DasherCore/UserLogBase.h b/Src/DasherCore/UserLogBase.h
index 6c7c5be..c63e82c 100644
--- a/Src/DasherCore/UserLogBase.h
+++ b/Src/DasherCore/UserLogBase.h
@@ -2,18 +2,23 @@
 #define __UserLogBase_h__
 
 #include "DasherTypes.h"
-#include "DasherComponent.h"
 #include "UserLogTrial.h" // Don't want to include this, but needed for event type enum
+#include "Observable.h"
 #include "Event.h"
+#include "SettingsStore.h"
 
 #include <string>
 #include <vector>
+
+namespace Dasher {
+  class CDasherInterfaceBase;
+}
+
 /// \defgroup Logging Logging routines
 /// @{
-class CUserLogBase : public Dasher::CDasherComponent {
+class CUserLogBase : protected Dasher::CSettingsUser, protected TransientObserver<const Dasher::CEditEvent *> {
  public:
-  CUserLogBase(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore)
-  : Dasher::CDasherComponent(pEventHandler, pSettingsStore), m_iNumDeleted(0) {};
+  CUserLogBase(Dasher::CSettingsUser *pCreateFrom, Observable<const Dasher::CEditEvent*> *pHandler);
 
   virtual void AddParam(const std::string& strName, const std::string& strValue, int iOptionMask = 0) = 0;
   virtual void AddParam(const std::string& strName, double dValue, int iOptionMask = 0) = 0;
@@ -32,7 +37,7 @@ class CUserLogBase : public Dasher::CDasherComponent {
   virtual int GetLogLevelMask() = 0;
   virtual void KeyDown(int iId, int iType, int iEffect) = 0;
   ///Watches output events to record symbols added/deleted
-  virtual void HandleEvent(Dasher::CEvent *pEvent);
+  virtual void HandleEvent(const Dasher::CEditEvent *pEvent);
   ///Passes record of symbols added/deleted to AddSymbols/DeleteSymbols
   void FrameEnded();
 protected:
diff --git a/Src/Gtk2/DasherAppSettings.cpp b/Src/Gtk2/DasherAppSettings.cpp
index 1318e48..b7ec74c 100644
--- a/Src/Gtk2/DasherAppSettings.cpp
+++ b/Src/Gtk2/DasherAppSettings.cpp
@@ -27,6 +27,8 @@
 
 // TODO: Rename this file to fit in with naming conventions
 
+using namespace Dasher::Settings;
+
 struct _DasherAppSettingsPrivate {
 #ifdef WITH_GCONF
   GConfClient *pGConfClient;
diff --git a/Src/Gtk2/DasherControl.cpp b/Src/Gtk2/DasherControl.cpp
index f58eb6d..df710b1 100644
--- a/Src/Gtk2/DasherControl.cpp
+++ b/Src/Gtk2/DasherControl.cpp
@@ -36,7 +36,8 @@ extern "C" gint canvas_expose_event(GtkWidget *widget, GdkEventExpose *event, gp
 static bool g_iTimeoutID = 0;
 
 // CDasherControl class definitions
-CDasherControl::CDasherControl(GtkVBox *pVBox, GtkDasherControl *pDasherControl) {
+CDasherControl::CDasherControl(GtkVBox *pVBox, GtkDasherControl *pDasherControl)
+ : CDashIntfScreenMsgs(new CGnomeSettingsStore()) {
   m_pScreen = NULL;
 
   m_pDasherControl = pDasherControl;
@@ -91,19 +92,19 @@ void CDasherControl::CreateModules() {
   // Create locally cached copies of the mouse input objects, as we
   // need to pass coordinates to them from the timer callback
   m_pMouseInput =
-    (CDasherMouseInput *)  RegisterModule(new CDasherMouseInput(m_pEventHandler, m_pSettingsStore));
+    (CDasherMouseInput *)  RegisterModule(new CDasherMouseInput());
   SetDefaultInputDevice(m_pMouseInput);
   m_p1DMouseInput =
-    (CDasher1DMouseInput *)RegisterModule(new CDasher1DMouseInput(m_pEventHandler, m_pSettingsStore));
-  RegisterModule(new CSocketInput(this, m_pEventHandler, m_pSettingsStore));
+    (CDasher1DMouseInput *)RegisterModule(new CDasher1DMouseInput());
+  RegisterModule(new CSocketInput(this, this));
 
 #ifdef JOYSTICK
-  RegisterModule(new CDasherJoystickInput(m_pEventHandler, m_pSettingsStore, this));
-  RegisterModule(new CDasherJoystickInputDiscrete(m_pEventHandler, m_pSettingsStore, this));
+  RegisterModule(new CDasherJoystickInput(this));
+  RegisterModule(new CDasherJoystickInputDiscrete(this));
 #endif
   
 #ifdef TILT
-  RegisterModule(new CDasherTiltInput(m_pEventHandler, m_pSettingsStore, this));
+  RegisterModule(new CDasherTiltInput(this));
 #endif
 }
 
@@ -135,10 +136,6 @@ void CDasherControl::SetupPaths() {
   delete[] user_data_dir;
 }
 
-void CDasherControl::CreateSettingsStore() {
-  m_pSettingsStore = new CGnomeSettingsStore(m_pEventHandler);
-}
-
 void CDasherControl::ScanAlphabetFiles(std::vector<std::string> &vFileList) {
   GDir *directory;
   G_CONST_RETURN gchar *filename;
@@ -333,14 +330,21 @@ int CDasherControl::CanvasConfigureEvent() {
   return 0;
 }
 
-void CDasherControl::ExternalEventHandler(Dasher::CEvent *pEvent) {
-  // Convert events coming from the core to Glib signals.
-
-  if(pEvent->m_iEventType == EV_PARAM_NOTIFY) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-    HandleParameterNotification(pEvt->m_iParameter);
-    g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_changed", pEvt->m_iParameter);
+void CDasherControl::HandleEvent(int iParameter) {
+  CDashIntfScreenMsgs::HandleEvent(iParameter);
+  switch(iParameter) {
+  case SP_DASHER_FONT:
+      m_pScreen->SetFont(GetStringParameter(SP_DASHER_FONT));
+      ScheduleRedraw();
+    break;
+  case BP_GLOBAL_KEYBOARD:
+    // TODO: reimplement
+//     if(m_pKeyboardHelper)
+//       m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
+    break;
   }
+  // Convert events coming from the core to Glib signals.
+  g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_changed", iParameter);
 }
 
 void CDasherControl::editOutput(const std::string &strText, CDasherNode *pNode) {
@@ -429,20 +433,6 @@ void CDasherControl::ExternalKeyUp(int iKeyVal) {
   KeyUp(get_time(), iKeyVal);
 }
 
-void CDasherControl::HandleParameterNotification(int iParameter) {
-  switch(iParameter) {
-  case SP_DASHER_FONT:
-      m_pScreen->SetFont(GetStringParameter(SP_DASHER_FONT));
-      ScheduleRedraw();
-    break;
-  case BP_GLOBAL_KEYBOARD:
-    // TODO: reimplement
-//     if(m_pKeyboardHelper)
-//       m_pKeyboardHelper->Grab(GetBoolParameter(BP_GLOBAL_KEYBOARD));
-    break;
-  }
-}
-
 int CDasherControl::TimerEvent() {
   int x, y;
   GdkWindow *default_root_window = gdk_get_default_root_window();
diff --git a/Src/Gtk2/DasherControl.h b/Src/Gtk2/DasherControl.h
index e1af50a..44bb424 100644
--- a/Src/Gtk2/DasherControl.h
+++ b/Src/Gtk2/DasherControl.h
@@ -154,7 +154,7 @@ public:
   ///
   /// Pass events coming from the core to the appropriate handler.
   ///
-  virtual void ExternalEventHandler(Dasher::CEvent *pEvent);
+  virtual void HandleEvent(int iParameter);
 
   ///Override to emit Gtk2 signal
   virtual void editOutput(const std::string &strText, CDasherNode *pNode);
@@ -166,13 +166,11 @@ public:
   virtual void SetLockStatus(const string &strText, int iPercent);
 
 private:
-  //  virtual void CreateSettingsStore();
   virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
   virtual void ScanColourFiles(std::vector<std::string> &vFileList);
   virtual void SetupPaths();
   virtual void CreateModules();
   virtual void SetupUI();
-  virtual void CreateSettingsStore();
   virtual void StartTimer();
   virtual void ShutdownTimer();
   
@@ -181,13 +179,6 @@ private:
 
   void GameMessageOut(int message, const void* messagedata);
 
-  ///
-  /// Notification from CDasherInterface that a parameter has changed
-  /// \param iParameter The parameter which has changed
-  ///
-
-  void HandleParameterNotification(int iParameter);
-
   GtkWidget *m_pVBox;
   GtkWidget *m_pCanvas;
 
diff --git a/Src/Gtk2/GConfStore.cpp b/Src/Gtk2/GConfStore.cpp
index 3b7424f..39e66e2 100644
--- a/Src/Gtk2/GConfStore.cpp
+++ b/Src/Gtk2/GConfStore.cpp
@@ -2,7 +2,7 @@
 
 #define GCONF_KEY_ROOT "/apps/dasher4/"
 
-CGnomeSettingsStore::CGnomeSettingsStore(Dasher::CEventHandler *pEventHandler):CSettingsStore(pEventHandler) {
+CGnomeSettingsStore::CGnomeSettingsStore() {
   the_gconf_client = gconf_client_get_default();
 
   gconf_client_add_dir(the_gconf_client, "/apps/dasher4", GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
diff --git a/Src/Gtk2/GSettingsStore.cpp b/Src/Gtk2/GSettingsStore.cpp
index eb07e8b..33c64ee 100644
--- a/Src/Gtk2/GSettingsStore.cpp
+++ b/Src/Gtk2/GSettingsStore.cpp
@@ -2,7 +2,7 @@
 
 #include <iostream>
 
-CGnomeSettingsStore::CGnomeSettingsStore(Dasher::CEventHandler *pEventHandler):CSettingsStore(pEventHandler) {
+CGnomeSettingsStore::CGnomeSettingsStore() {
   settings = g_settings_new("org.gnome.Dasher");
   LoadPersistent();
 }
diff --git a/Src/Gtk2/GenerateSchema.cpp b/Src/Gtk2/GenerateSchema.cpp
index e579888..ab0527c 100644
--- a/Src/Gtk2/GenerateSchema.cpp
+++ b/Src/Gtk2/GenerateSchema.cpp
@@ -9,6 +9,8 @@
 #include <iostream>
 #include <iomanip>
 
+using namespace Dasher::Settings;
+
 enum EValType { TYPE_BOOL, TYPE_LONG, TYPE_STRING };
 enum EOutput { GCONF_OUTPUT, GSETTINGS_OUTPUT, TEXT_OUTPUT };
 
diff --git a/Src/Gtk2/GnomeSettingsStore.h b/Src/Gtk2/GnomeSettingsStore.h
index 6f72e9d..fa5eca9 100644
--- a/Src/Gtk2/GnomeSettingsStore.h
+++ b/Src/Gtk2/GnomeSettingsStore.h
@@ -19,9 +19,9 @@
 
 #include "SettingsStore.h"
 
-class CGnomeSettingsStore:public CSettingsStore {
+class CGnomeSettingsStore:public Dasher::CSettingsStore {
 public:
-  CGnomeSettingsStore(Dasher::CEventHandler * pEventHandler);
+  CGnomeSettingsStore();
   ~CGnomeSettingsStore();
 
 private:
diff --git a/Src/Gtk2/Makefile.am b/Src/Gtk2/Makefile.am
index 985180e..350aa41 100644
--- a/Src/Gtk2/Makefile.am
+++ b/Src/Gtk2/Makefile.am
@@ -3,7 +3,7 @@ LIBS = @INTLLIBS@ @LIBS@
 noinst_LTLIBRARIES = libdashergtk.la libdashercontrol.la
 
 noinst_PROGRAMS = generate-schema
-generate_schema_SOURCES = GenerateSchema.cpp
+generate_schema_SOURCES = GenerateSchema.cpp ../DasherCore/Parameters.cpp
 
 #bin_PROGRAMS = dasher-config
 
diff --git a/Src/Gtk2/mouse_input.h b/Src/Gtk2/mouse_input.h
index d5d8c04..1584cad 100644
--- a/Src/Gtk2/mouse_input.h
+++ b/Src/Gtk2/mouse_input.h
@@ -11,8 +11,7 @@ using namespace Dasher;
 
 class CDasherMouseInput : public CScreenCoordInput {
 public:
-  CDasherMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore) 
-    : CScreenCoordInput(pEventHandler, pSettingsStore, 0, _("Mouse Input")) {
+  CDasherMouseInput() : CScreenCoordInput(0, _("Mouse Input")) {
 
     m_iX = 0;
     m_iY = 0;
@@ -47,9 +46,9 @@ static SModuleSettings sSettings[] = {
 
 class CDasher1DMouseInput : public CDasherCoordInput {
 public:
-  CDasher1DMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore) 
+  CDasher1DMouseInput() 
     /* TRANSLATORS: Only use the vertical mouse coordinate - this is prefered for some disabled users. */
-    : CDasherCoordInput(pEventHandler, pSettingsStore, 2, _("One Dimensional Mouse Input")) {
+    : CDasherCoordInput(2, _("One Dimensional Mouse Input")) {
 
     m_iOffset = 0;
 
diff --git a/Src/MacOSX/COSXDasherControl.h b/Src/MacOSX/COSXDasherControl.h
index b209d20..e93c2a0 100644
--- a/Src/MacOSX/COSXDasherControl.h
+++ b/Src/MacOSX/COSXDasherControl.h
@@ -41,9 +41,13 @@ public:
   void Realize2();
   void TimerFired(NSPoint p);
   void Train(NSString *fileName);
+  
+  ///Wrappers round settings API for use by Objective-C...
   id GetParameter(NSString *aKey);
   void SetParameter(NSString *aKey, id aValue);
+  int GetParameterIndex(const std::string & aKey);
   NSDictionary *ParameterDictionary();
+  
   void goddamn(unsigned long iTime, bool bForceRedraw);
   virtual void WriteTrainFile(const std::string &filename, const std::string &strNewText);
   std::string GetAllContext();
@@ -56,7 +60,6 @@ private:
   virtual void SetupPaths();
   virtual void CreateModules();
   virtual void SetupUI();
-  virtual void CreateSettingsStore();
   virtual void StartTimer();
   virtual void ShutdownTimer();
   virtual bool SupportsSpeech();
@@ -81,11 +84,10 @@ private:
   ///Really this will have to wait for either (a)reinstating an in-Dasher
   /// text edit box, or (b) implementing the MacOSX input method API.
   unsigned int ctrlDelete(bool bForwards, CControlManager::EditDistance dist);
-  ///
-  /// Pass events coming from the core to the appropriate handler.
-  ///
-  
-  void ExternalEventHandler(Dasher::CEvent *pEvent);
+  // No need to HandleEvent: the PreferencesController is observing changes to the 
+  // user defaults controller which is observing the user defaults and will be notified when
+  // the parameter is actually written by COSXSettingsStore.
+  //void HandleEvent(int iParameter);
 
   ///Override to perform output/deletion via DasherEdit
   void editOutput(const std::string &strText, CDasherNode *pSource);
diff --git a/Src/MacOSX/COSXDasherControl.mm b/Src/MacOSX/COSXDasherControl.mm
index 528e6ef..319da4f 100644
--- a/Src/MacOSX/COSXDasherControl.mm
+++ b/Src/MacOSX/COSXDasherControl.mm
@@ -25,9 +25,9 @@
 #import <sys/stat.h>
 
 using namespace std;
+using namespace Dasher::Settings;
 
-
-COSXDasherControl::COSXDasherControl(DasherApp *aDasherApp) {
+COSXDasherControl::COSXDasherControl(DasherApp *aDasherApp) : CDashIntfScreenMsgs(new COSXSettingsStore()){
   
   dasherApp = aDasherApp;
   
@@ -40,9 +40,9 @@ void COSXDasherControl::CreateModules() {
   CDasherInterfaceBase::CreateModules();
   // Create locally cached copies of the mouse input objects, as we
   // need to pass coordinates to them from the timer callback
-  RegisterModule(m_pMouseInput = new COSXMouseInput(m_pEventHandler, m_pSettingsStore));
+  RegisterModule(m_pMouseInput = new COSXMouseInput());
   SetDefaultInputDevice(m_pMouseInput);
-  RegisterModule(m_p1DMouseInput = new COSX1DMouseInput(m_pEventHandler, m_pSettingsStore));
+  RegisterModule(m_p1DMouseInput = new COSX1DMouseInput());
 }
   
 COSXDasherControl::~COSXDasherControl() {
@@ -77,15 +77,10 @@ void COSXDasherControl::SetupPaths() {
   }
     
     // system resources are inside the .app, under the Resources directory
-  m_pSettingsStore->SetStringParameter(SP_SYSTEM_LOC, StdStringFromNSString(systemDir));
-  m_pSettingsStore->SetStringParameter(SP_USER_LOC, StdStringFromNSString(userDir));
-}
-
-void COSXDasherControl::CreateSettingsStore() {
-  m_pSettingsStore = new COSXSettingsStore(m_pEventHandler);
+  SetStringParameter(SP_SYSTEM_LOC, StdStringFromNSString(systemDir));
+  SetStringParameter(SP_USER_LOC, StdStringFromNSString(userDir));
 }
 
-
 void COSXDasherControl::ScanAlphabetFiles(std::vector<std::string> &vFileList) {
   
   NSDirectoryEnumerator *dirEnum;
@@ -149,25 +144,6 @@ void COSXDasherControl::GameMessageOut(int message, const void* messagedata) {
   NSLog(@"GameMessageOut");
 }
 
-void COSXDasherControl::ExternalEventHandler(Dasher::CEvent *pEvent) {
-  
-  switch (pEvent->m_iEventType) {
-    case EV_PARAM_NOTIFY:
-      // don't need to do anything because the PreferencesController is observing changes to the 
-      // user defaults controller which is observing the user defaults and will be notified when
-      // the parameter is actually written by COSXSettingsStore.
-//      CParameterNotificationEvent *parameterEvent(static_cast < CParameterNotificationEvent * >(pEvent));
-//      NSLog(@"CParameterNotificationEvent, m_iParameter: %d", parameterEvent->m_iParameter);
-      break;
-    case EV_SCREEN_GEOM:
-      //no need to do anything, so avoid log message
-      break;
-    default:
-      NSLog(@"ExternalEventHandler, UNKNOWN m_iEventType = %d", pEvent->m_iEventType);
-      break;
-  }
-}
-
 void COSXDasherControl::editOutput(const string &strText, CDasherNode *pNode) {
 //NSLog(@"ExternalEventHandler edit insert");
   [dasherEdit outputCallback:NSStringFromStdString(strText) targetApp:[dasherApp targetAppUIElementRef]];
@@ -245,17 +221,59 @@ void COSXDasherControl::WriteTrainFile(const std::string &filename, const std::s
   close(fd);
 }
 
+
 NSDictionary *COSXDasherControl::ParameterDictionary() {
-  COSXSettingsStore *ss(static_cast < COSXSettingsStore * >(m_pSettingsStore));
-  return ss->ParameterDictionary();
+  static NSMutableDictionary *parameterDictionary = nil;
+  
+  if (parameterDictionary == nil) {
+    parameterDictionary = [[NSMutableDictionary alloc] initWithCapacity:NUM_OF_BPS + NUM_OF_LPS + NUM_OF_SPS];
+    int ii;
+    
+    for(ii = 0; ii < NUM_OF_BPS; ii++) {
+      [parameterDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                      NSStringFromStdString(boolparamtable[ii].regName), @"regName",
+                                      NSStringFromStdString(boolparamtable[ii].humanReadable), @"humanReadable",
+                                      [NSNumber numberWithInt:boolparamtable[ii].key], @"key",
+                                      nil] forKey:NSStringFromStdString(boolparamtable[ii].regName)];
+    }
+    
+    for(ii = 0; ii < NUM_OF_LPS; ii++) {
+      [parameterDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                      NSStringFromStdString(longparamtable[ii].regName), @"regName",
+                                      NSStringFromStdString(longparamtable[ii].humanReadable), @"humanReadable",
+                                      [NSNumber numberWithInt:longparamtable[ii].key], @"key",
+                                      nil] forKey:NSStringFromStdString(longparamtable[ii].regName)];
+    }
+    
+    for(ii = 0; ii < NUM_OF_SPS; ii++) {
+      [parameterDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys:
+                                      NSStringFromStdString(stringparamtable[ii].regName), @"regName",
+                                      NSStringFromStdString(stringparamtable[ii].humanReadable), @"humanReadable",
+                                      [NSNumber numberWithInt:stringparamtable[ii].key], @"key",
+                                      nil] forKey:NSStringFromStdString(stringparamtable[ii].regName)];
+    }
+  }
+  
+  return parameterDictionary;
+}
+
+
+int COSXDasherControl::GetParameterIndex(const std::string & aKey) {
+  NSString *key = NSStringFromStdString(aKey);
+  NSDictionary *parameterEntry = [ParameterDictionary() objectForKey:key];
+  if (parameterEntry == nil) {
+    NSLog(@"COSXDasherControl::GetParameterIndex - unknown key: %@", key);
+    return NSNotFound;
+  }
+  
+  return [[parameterEntry objectForKey:@"key"] intValue];
 }
 
 id COSXDasherControl::GetParameter(NSString *aKey) {
   
-  COSXSettingsStore *ss(static_cast < COSXSettingsStore * >(m_pSettingsStore));
-  int pIndex = ss->GetParameterIndex(StdStringFromNSString(aKey));
+  int pIndex = GetParameterIndex(StdStringFromNSString(aKey));
 
-  switch (ss->GetParameterType(pIndex)) {
+  switch (GetParameterType(pIndex)) {
     case ParamBool:
       return [NSNumber numberWithBool:GetBoolParameter(pIndex)];
       break;
@@ -274,10 +292,9 @@ id COSXDasherControl::GetParameter(NSString *aKey) {
 
 void COSXDasherControl::SetParameter(NSString *aKey, id aValue) {
   
-  COSXSettingsStore *ss(static_cast < COSXSettingsStore * >(m_pSettingsStore));
-  int pIndex = ss->GetParameterIndex(StdStringFromNSString(aKey));
+  int pIndex = GetParameterIndex(StdStringFromNSString(aKey));
   
-  switch (ss->GetParameterType(pIndex)) {
+  switch (GetParameterType(pIndex)) {
     case ParamBool:
       SetBoolParameter(pIndex, [aValue boolValue]);
       break;
diff --git a/Src/MacOSX/COSXMouseInput.h b/Src/MacOSX/COSXMouseInput.h
index 2c02e42..42c0afb 100644
--- a/Src/MacOSX/COSXMouseInput.h
+++ b/Src/MacOSX/COSXMouseInput.h
@@ -16,8 +16,8 @@ using namespace Dasher;
 
 class COSXMouseInput : public CScreenCoordInput {
 public:
-  COSXMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore) 
-  : CScreenCoordInput(pEventHandler, pSettingsStore, 0, "Mouse Input") {
+  COSXMouseInput() 
+  : CScreenCoordInput(0, "Mouse Input") {
   };
   virtual bool GetScreenCoords(screenint &iX, screenint &iY, CDasherView *pView) {
     iX = m_iX;
@@ -42,8 +42,8 @@ static SModuleSettings sSettings[] = {
 
 class COSX1DMouseInput:public CDasherCoordInput {
 public:
-  COSX1DMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore) 
-  : CDasherCoordInput(pEventHandler, pSettingsStore, 2, "One Dimensional Mouse Input") {
+  COSX1DMouseInput() 
+  : CDasherCoordInput(2, "One Dimensional Mouse Input") {
     
     m_iOffset = 0;
   };
diff --git a/Src/MacOSX/COSXSettingsStore.h b/Src/MacOSX/COSXSettingsStore.h
index d186f7e..d68b24f 100644
--- a/Src/MacOSX/COSXSettingsStore.h
+++ b/Src/MacOSX/COSXSettingsStore.h
@@ -15,15 +15,11 @@
 
 @class NSDictionary;
 
-class COSXSettingsStore:public CSettingsStore {
+class COSXSettingsStore:public Dasher::CSettingsStore {
 public:
-  COSXSettingsStore(Dasher::CEventHandler * pEventHandler);
+  COSXSettingsStore();
   ~COSXSettingsStore();
   
-  NSDictionary *ParameterDictionary();
-
-  int GetParameterIndex(const std::string &  Key);
-
 private:
 
   bool LoadSetting(const std::string & Key, bool * Value);
diff --git a/Src/MacOSX/COSXSettingsStore.mm b/Src/MacOSX/COSXSettingsStore.mm
index 2b975e2..d9c9e47 100644
--- a/Src/MacOSX/COSXSettingsStore.mm
+++ b/Src/MacOSX/COSXSettingsStore.mm
@@ -13,60 +13,13 @@
 #import <Cocoa/Cocoa.h>
 #import "DasherUtil.h"
 
-COSXSettingsStore::COSXSettingsStore(Dasher::CEventHandler *pEventHandler):CSettingsStore(pEventHandler) {
+COSXSettingsStore::COSXSettingsStore():CSettingsStore() {
   LoadPersistent();
 };
 
 COSXSettingsStore::~COSXSettingsStore() {
 };
 
-NSDictionary *COSXSettingsStore::ParameterDictionary() {
-  static NSMutableDictionary *parameterDictionary = nil;
-  
-  if (parameterDictionary == nil) {
-    parameterDictionary = [[NSMutableDictionary alloc] initWithCapacity:NUM_OF_BPS + NUM_OF_LPS + NUM_OF_SPS];
-    int ii;
- 
-    for(ii = 0; ii < NUM_OF_BPS; ii++) {
-      [parameterDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys:
-        NSStringFromStdString(s_oParamTables.BoolParamTable[ii].regName), @"regName",
-        NSStringFromStdString(s_oParamTables.BoolParamTable[ii].humanReadable), @"humanReadable",
-        [NSNumber numberWithInt:s_oParamTables.BoolParamTable[ii].key], @"key",
-        nil] forKey:NSStringFromStdString(s_oParamTables.BoolParamTable[ii].regName)];
-    }
-    
-    for(ii = 0; ii < NUM_OF_LPS; ii++) {
-      [parameterDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys:
-        NSStringFromStdString(s_oParamTables.LongParamTable[ii].regName), @"regName",
-        NSStringFromStdString(s_oParamTables.LongParamTable[ii].humanReadable), @"humanReadable",
-        [NSNumber numberWithInt:s_oParamTables.LongParamTable[ii].key], @"key",
-        nil] forKey:NSStringFromStdString(s_oParamTables.LongParamTable[ii].regName)];
-    }
-    
-    for(ii = 0; ii < NUM_OF_SPS; ii++) {
-      [parameterDictionary setObject:[NSDictionary dictionaryWithObjectsAndKeys:
-        NSStringFromStdString(s_oParamTables.StringParamTable[ii].regName), @"regName",
-        NSStringFromStdString(s_oParamTables.StringParamTable[ii].humanReadable), @"humanReadable",
-        [NSNumber numberWithInt:s_oParamTables.StringParamTable[ii].key], @"key",
-        nil] forKey:NSStringFromStdString(s_oParamTables.StringParamTable[ii].regName)];
-    }
-  }
-  
-  return parameterDictionary;
-}
-
-
-int COSXSettingsStore::GetParameterIndex(const std::string & aKey) {
-  NSString *key = NSStringFromStdString(aKey);
-  NSDictionary *parameterEntry = [ParameterDictionary() objectForKey:key];
-  if (parameterEntry == nil) {
-    NSLog(@"COSXSettingsStore::GetParameterIndex - unknown key: %@", key);
-    return NSNotFound;
-  }
-  
-  return [[parameterEntry objectForKey:@"key"] intValue];
-}
-
 /*
  the default values for all the parameters are stored in the core.  Rather than trying to ferret out those values in order to construct a registration domain, I'm just going to get the object for the key and if it is nil, let the core know I failed to read the default and it will supply the correct default value.
  */
diff --git a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
index cae2108..659515e 100755
--- a/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
+++ b/Src/MacOSX/Dasher.xcodeproj/project.pbxproj
@@ -54,8 +54,6 @@
 		1948BEC20C226CFD001DFA32 /* CustomColours.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE1C0C226CFC001DFA32 /* CustomColours.h */; };
 		1948BEC30C226CFD001DFA32 /* DasherButtons.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE1D0C226CFC001DFA32 /* DasherButtons.cpp */; };
 		1948BEC40C226CFD001DFA32 /* DasherButtons.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE1E0C226CFC001DFA32 /* DasherButtons.h */; };
-		1948BEC50C226CFD001DFA32 /* DasherComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE1F0C226CFC001DFA32 /* DasherComponent.cpp */; };
-		1948BEC60C226CFD001DFA32 /* DasherComponent.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE200C226CFC001DFA32 /* DasherComponent.h */; };
 		1948BED00C226CFD001DFA32 /* DasherInput.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE2A0C226CFD001DFA32 /* DasherInput.h */; };
 		1948BED10C226CFD001DFA32 /* DasherInterfaceBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE2B0C226CFD001DFA32 /* DasherInterfaceBase.cpp */; };
 		1948BED20C226CFD001DFA32 /* DasherInterfaceBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE2C0C226CFD001DFA32 /* DasherInterfaceBase.h */; };
@@ -77,8 +75,7 @@
 		1948BEE40C226CFD001DFA32 /* DynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE3E0C226CFD001DFA32 /* DynamicFilter.cpp */; };
 		1948BEE50C226CFD001DFA32 /* DynamicFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE3F0C226CFD001DFA32 /* DynamicFilter.h */; };
 		1948BEE60C226CFD001DFA32 /* Event.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE400C226CFD001DFA32 /* Event.h */; };
-		1948BEE70C226CFD001DFA32 /* EventHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE410C226CFD001DFA32 /* EventHandler.cpp */; };
-		1948BEE80C226CFD001DFA32 /* EventHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE420C226CFD001DFA32 /* EventHandler.h */; };
+		1948BEE80C226CFD001DFA32 /* Observable.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE420C226CFD001DFA32 /* Observable.h */; };
 		1948BEEB0C226CFD001DFA32 /* FileLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1948BE450C226CFD001DFA32 /* FileLogger.cpp */; };
 		1948BEEC0C226CFD001DFA32 /* FileLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE460C226CFD001DFA32 /* FileLogger.h */; };
 		1948BEED0C226CFD001DFA32 /* FrameRate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1948BE470C226CFD001DFA32 /* FrameRate.h */; };
@@ -334,6 +331,8 @@
 		33135354102C6D8E00E28220 /* CompassMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3313534C102C6D8E00E28220 /* CompassMode.h */; };
 		33135355102C6D8E00E28220 /* ButtonMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3313534D102C6D8E00E28220 /* ButtonMode.cpp */; };
 		33135356102C6D8E00E28220 /* ButtonMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 3313534E102C6D8E00E28220 /* ButtonMode.h */; };
+		3335F60013AB50E9004F9371 /* DashIntfSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3335F5FE13AB50E9004F9371 /* DashIntfSettings.cpp */; };
+		3335F60113AB50E9004F9371 /* DashIntfSettings.h in Headers */ = {isa = PBXBuildFile; fileRef = 3335F5FF13AB50E9004F9371 /* DashIntfSettings.h */; };
 		3344F0691341297F001FACAB /* UserLogBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344F0681341297F001FACAB /* UserLogBase.cpp */; };
 		334DE238135E3E68007C8D6D /* control.textlabels.xml in Resources */ = {isa = PBXBuildFile; fileRef = 334DE236135E3E68007C8D6D /* control.textlabels.xml */; };
 		334DE239135E3E68007C8D6D /* control.xml in Resources */ = {isa = PBXBuildFile; fileRef = 334DE237135E3E68007C8D6D /* control.xml */; };
@@ -382,6 +381,7 @@
 		33E91A780F55E60B00B5F513 /* KeyboardHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 33E91A760F55E60B00B5F513 /* KeyboardHelper.h */; };
 		33F6C9EA133241A000745B06 /* AbstractXMLParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 33F6C9E8133241A000745B06 /* AbstractXMLParser.h */; };
 		33F6C9EB133241A000745B06 /* AbstractXMLParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33F6C9E9133241A000745B06 /* AbstractXMLParser.cpp */; };
+		33FC1D3113ACE88F007642CD /* Parameters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33FC1D3013ACE88F007642CD /* Parameters.cpp */; };
 		33FC93390FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33FC93370FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp */; };
 		33FC933A0FEFA2C900A9F08D /* TwoPushDynamicFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 33FC93380FEFA2C900A9F08D /* TwoPushDynamicFilter.h */; };
 		33FC93430FEFA2FB00A9F08D /* FrameRate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 33FC93420FEFA2FB00A9F08D /* FrameRate.cpp */; };
@@ -435,8 +435,6 @@
 		1948BE1C0C226CFC001DFA32 /* CustomColours.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CustomColours.h; sourceTree = "<group>"; };
 		1948BE1D0C226CFC001DFA32 /* DasherButtons.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DasherButtons.cpp; sourceTree = "<group>"; };
 		1948BE1E0C226CFC001DFA32 /* DasherButtons.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DasherButtons.h; sourceTree = "<group>"; };
-		1948BE1F0C226CFC001DFA32 /* DasherComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DasherComponent.cpp; sourceTree = "<group>"; };
-		1948BE200C226CFC001DFA32 /* DasherComponent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DasherComponent.h; sourceTree = "<group>"; };
 		1948BE280C226CFD001DFA32 /* DasherGameMode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DasherGameMode.cpp; sourceTree = "<group>"; };
 		1948BE290C226CFD001DFA32 /* DasherGameMode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DasherGameMode.h; sourceTree = "<group>"; };
 		1948BE2A0C226CFD001DFA32 /* DasherInput.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DasherInput.h; sourceTree = "<group>"; };
@@ -460,8 +458,7 @@
 		1948BE3E0C226CFD001DFA32 /* DynamicFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicFilter.cpp; sourceTree = "<group>"; };
 		1948BE3F0C226CFD001DFA32 /* DynamicFilter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DynamicFilter.h; sourceTree = "<group>"; };
 		1948BE400C226CFD001DFA32 /* Event.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Event.h; sourceTree = "<group>"; };
-		1948BE410C226CFD001DFA32 /* EventHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = EventHandler.cpp; sourceTree = "<group>"; };
-		1948BE420C226CFD001DFA32 /* EventHandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = EventHandler.h; sourceTree = "<group>"; };
+		1948BE420C226CFD001DFA32 /* Observable.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Observable.h; sourceTree = "<group>"; };
 		1948BE450C226CFD001DFA32 /* FileLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FileLogger.cpp; sourceTree = "<group>"; };
 		1948BE460C226CFD001DFA32 /* FileLogger.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FileLogger.h; sourceTree = "<group>"; };
 		1948BE470C226CFD001DFA32 /* FrameRate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FrameRate.h; sourceTree = "<group>"; };
@@ -733,6 +730,8 @@
 		3313534C102C6D8E00E28220 /* CompassMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CompassMode.h; sourceTree = "<group>"; };
 		3313534D102C6D8E00E28220 /* ButtonMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ButtonMode.cpp; sourceTree = "<group>"; };
 		3313534E102C6D8E00E28220 /* ButtonMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButtonMode.h; sourceTree = "<group>"; };
+		3335F5FE13AB50E9004F9371 /* DashIntfSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DashIntfSettings.cpp; sourceTree = "<group>"; };
+		3335F5FF13AB50E9004F9371 /* DashIntfSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DashIntfSettings.h; sourceTree = "<group>"; };
 		3344F0681341297F001FACAB /* UserLogBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserLogBase.cpp; sourceTree = "<group>"; };
 		334DE236135E3E68007C8D6D /* control.textlabels.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = control.textlabels.xml; sourceTree = "<group>"; };
 		334DE237135E3E68007C8D6D /* control.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = control.xml; sourceTree = "<group>"; };
@@ -781,6 +780,7 @@
 		33E91A760F55E60B00B5F513 /* KeyboardHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyboardHelper.h; sourceTree = "<group>"; };
 		33F6C9E8133241A000745B06 /* AbstractXMLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractXMLParser.h; sourceTree = "<group>"; };
 		33F6C9E9133241A000745B06 /* AbstractXMLParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AbstractXMLParser.cpp; sourceTree = "<group>"; };
+		33FC1D3013ACE88F007642CD /* Parameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Parameters.cpp; sourceTree = "<group>"; };
 		33FC93370FEFA2C900A9F08D /* TwoPushDynamicFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TwoPushDynamicFilter.cpp; sourceTree = "<group>"; };
 		33FC93380FEFA2C900A9F08D /* TwoPushDynamicFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TwoPushDynamicFilter.h; sourceTree = "<group>"; };
 		33FC93420FEFA2FB00A9F08D /* FrameRate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameRate.cpp; sourceTree = "<group>"; };
@@ -919,8 +919,6 @@
 				1948BE1C0C226CFC001DFA32 /* CustomColours.h */,
 				1948BE1D0C226CFC001DFA32 /* DasherButtons.cpp */,
 				1948BE1E0C226CFC001DFA32 /* DasherButtons.h */,
-				1948BE1F0C226CFC001DFA32 /* DasherComponent.cpp */,
-				1948BE200C226CFC001DFA32 /* DasherComponent.h */,
 				1948BE280C226CFD001DFA32 /* DasherGameMode.cpp */,
 				1948BE290C226CFD001DFA32 /* DasherGameMode.h */,
 				1948BE2A0C226CFD001DFA32 /* DasherInput.h */,
@@ -928,6 +926,8 @@
 				1948BE2C0C226CFD001DFA32 /* DasherInterfaceBase.h */,
 				33B3431613A8A951009AE0D5 /* DashIntfScreenMsgs.cpp */,
 				33B3431713A8A951009AE0D5 /* DashIntfScreenMsgs.h */,
+				3335F5FE13AB50E9004F9371 /* DashIntfSettings.cpp */,
+				3335F5FF13AB50E9004F9371 /* DashIntfSettings.h */,
 				1948BE2D0C226CFD001DFA32 /* DasherModel.cpp */,
 				1948BE2E0C226CFD001DFA32 /* DasherModel.h */,
 				1948BE2F0C226CFD001DFA32 /* DasherModule.cpp */,
@@ -948,8 +948,7 @@
 				1948BE3E0C226CFD001DFA32 /* DynamicFilter.cpp */,
 				1948BE3F0C226CFD001DFA32 /* DynamicFilter.h */,
 				1948BE400C226CFD001DFA32 /* Event.h */,
-				1948BE410C226CFD001DFA32 /* EventHandler.cpp */,
-				1948BE420C226CFD001DFA32 /* EventHandler.h */,
+				1948BE420C226CFD001DFA32 /* Observable.h */,
 				1948BE450C226CFD001DFA32 /* FileLogger.cpp */,
 				1948BE460C226CFD001DFA32 /* FileLogger.h */,
 				1948BE470C226CFD001DFA32 /* FrameRate.h */,
@@ -973,6 +972,7 @@
 				1948BE730C226CFD001DFA32 /* OneDimensionalFilter.cpp */,
 				1948BE740C226CFD001DFA32 /* OneDimensionalFilter.h */,
 				1948BE750C226CFD001DFA32 /* Parameters.h */,
+				33FC1D3013ACE88F007642CD /* Parameters.cpp */,
 				1948BE780C226CFD001DFA32 /* SCENode.cpp */,
 				1948BE790C226CFD001DFA32 /* SCENode.h */,
 				1948BE7A0C226CFD001DFA32 /* SettingsStore.cpp */,
@@ -1372,7 +1372,6 @@
 				1948BEBE0C226CFD001DFA32 /* ConversionManager.h in Headers */,
 				1948BEC20C226CFD001DFA32 /* CustomColours.h in Headers */,
 				1948BEC40C226CFD001DFA32 /* DasherButtons.h in Headers */,
-				1948BEC60C226CFD001DFA32 /* DasherComponent.h in Headers */,
 				1948BED00C226CFD001DFA32 /* DasherInput.h in Headers */,
 				1948BED20C226CFD001DFA32 /* DasherInterfaceBase.h in Headers */,
 				1948BED40C226CFD001DFA32 /* DasherModel.h in Headers */,
@@ -1385,7 +1384,7 @@
 				1948BEE20C226CFD001DFA32 /* DefaultFilter.h in Headers */,
 				1948BEE50C226CFD001DFA32 /* DynamicFilter.h in Headers */,
 				1948BEE60C226CFD001DFA32 /* Event.h in Headers */,
-				1948BEE80C226CFD001DFA32 /* EventHandler.h in Headers */,
+				1948BEE80C226CFD001DFA32 /* Observable.h in Headers */,
 				1948BEEC0C226CFD001DFA32 /* FileLogger.h in Headers */,
 				1948BEED0C226CFD001DFA32 /* FrameRate.h in Headers */,
 				1948BEF20C226CFD001DFA32 /* InputFilter.h in Headers */,
@@ -1444,6 +1443,7 @@
 				33F6C9EA133241A000745B06 /* AbstractXMLParser.h in Headers */,
 				33B3431913A8A951009AE0D5 /* DashIntfScreenMsgs.h in Headers */,
 				33B3431B13A8A970009AE0D5 /* Messages.h in Headers */,
+				3335F60113AB50E9004F9371 /* DashIntfSettings.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1733,7 +1733,6 @@
 				1948BEBD0C226CFD001DFA32 /* ConversionManager.cpp in Sources */,
 				1948BEC10C226CFD001DFA32 /* CustomColours.cpp in Sources */,
 				1948BEC30C226CFD001DFA32 /* DasherButtons.cpp in Sources */,
-				1948BEC50C226CFD001DFA32 /* DasherComponent.cpp in Sources */,
 				1948BED10C226CFD001DFA32 /* DasherInterfaceBase.cpp in Sources */,
 				1948BED30C226CFD001DFA32 /* DasherModel.cpp in Sources */,
 				1948BED50C226CFD001DFA32 /* DasherModule.cpp in Sources */,
@@ -1742,7 +1741,6 @@
 				1948BEDE0C226CFD001DFA32 /* DasherViewSquare.cpp in Sources */,
 				1948BEE10C226CFD001DFA32 /* DefaultFilter.cpp in Sources */,
 				1948BEE40C226CFD001DFA32 /* DynamicFilter.cpp in Sources */,
-				1948BEE70C226CFD001DFA32 /* EventHandler.cpp in Sources */,
 				1948BEEB0C226CFD001DFA32 /* FileLogger.cpp in Sources */,
 				1948BEF60C226CFD001DFA32 /* CTWLanguageModel.cpp in Sources */,
 				1948BEF80C226CFD001DFA32 /* DictLanguageModel.cpp in Sources */,
@@ -1793,6 +1791,8 @@
 				33F6C9EB133241A000745B06 /* AbstractXMLParser.cpp in Sources */,
 				33B3431813A8A951009AE0D5 /* DashIntfScreenMsgs.cpp in Sources */,
 				3344F0691341297F001FACAB /* UserLogBase.cpp in Sources */,
+				3335F60013AB50E9004F9371 /* DashIntfSettings.cpp in Sources */,
+				33FC1D3113ACE88F007642CD /* Parameters.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
diff --git a/Src/MacOSX/ModuleSettingsController.h b/Src/MacOSX/ModuleSettingsController.h
index 46177a7..afa6130 100644
--- a/Src/MacOSX/ModuleSettingsController.h
+++ b/Src/MacOSX/ModuleSettingsController.h
@@ -10,13 +10,13 @@
 #import "COSXDasherControl.h"
 
 @interface ModuleSettingsController : NSWindowController {
-  CDasherInterfaceBase *intf;
+  COSXDasherControl *intf;
   SModuleSettings *settings;
   int count;
 }
 
 ///Create a parameters controller whose window has the specified title and allows to adjust the provided settings.
--(id)initWithTitle:(NSString *)title Interface:(CDasherInterfaceBase *)intf Settings:(SModuleSettings *)settings Count:(int)count;
+-(id)initWithTitle:(NSString *)title Interface:(COSXDasherControl *)intf Settings:(SModuleSettings *)settings Count:(int)count;
 
 ///Show the window modally. (blocks until window dismissed)
 -(void)showModal;
diff --git a/Src/MacOSX/ModuleSettingsController.mm b/Src/MacOSX/ModuleSettingsController.mm
index 03f6cc6..2573fea 100644
--- a/Src/MacOSX/ModuleSettingsController.mm
+++ b/Src/MacOSX/ModuleSettingsController.mm
@@ -10,6 +10,7 @@
 #import "DasherUtil.h"
 
 using namespace Dasher;
+using Dasher::Settings::GetParameterName;
 
 //private methods we actually need to call directly
 @interface ModuleSettingsController ()
@@ -18,7 +19,7 @@ using namespace Dasher;
 
 @implementation ModuleSettingsController
 
--(id)initWithTitle:(NSString *)title Interface:(CDasherInterfaceBase *)_intf Settings:(SModuleSettings *)_settings Count:(int)_count {
+-(id)initWithTitle:(NSString *)title Interface:(COSXDasherControl *)_intf Settings:(SModuleSettings *)_settings Count:(int)_count {
   int height=0;
   for (int i=0; i<_count; i++)
     if (_settings[i].iType == T_BOOL) height+=25;
@@ -63,7 +64,7 @@ using namespace Dasher;
         ctrl = slider;
         y += 57;
       }
-      NSString *paramName = NSStringFromStdString(intf->GetSettingsStore()->GetParameterName(settings[i].iParameter));
+      NSString *paramName = NSStringFromStdString(GetParameterName(settings[i].iParameter));
       [udc addObserver:self forKeyPath:[NSString stringWithFormat:@"values.%@", paramName] options:0 context:ctrl];
     }
   } //else, window was autoreleased.
@@ -82,7 +83,7 @@ using namespace Dasher;
   [[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowWillCloseNotification object:[self window]];
   NSUserDefaultsController *udc = [NSUserDefaultsController sharedUserDefaultsController];
   for (int i=0; i<count; i++) {
-    NSString *paramName = NSStringFromStdString(intf->GetSettingsStore()->GetParameterName(settings[i].iParameter));
+    NSString *paramName = NSStringFromStdString(GetParameterName(settings[i].iParameter));
     [udc removeObserver:self forKeyPath:[NSString stringWithFormat:@"values.%@",paramName]];
   }
   [[NSApplication sharedApplication] stopModal];
diff --git a/Src/Win32/AppSettings.cpp b/Src/Win32/AppSettings.cpp
index 47946b1..a7de9b0 100644
--- a/Src/Win32/AppSettings.cpp
+++ b/Src/Win32/AppSettings.cpp
@@ -102,8 +102,7 @@ void CAppSettings::SetBoolParameter(int iParameter, bool bValue) {
     m_pBoolTable[iParameter - FIRST_APP_BP].value = bValue;
     SaveSetting(m_pBoolTable[iParameter - FIRST_APP_BP].regName, bValue);
 
-    Dasher::CParameterNotificationEvent oEvent(iParameter);
-    m_pDasher->ExternalEventHandler(&oEvent);
+    m_pDasher->HandleEvent(iParameter);
   }
 }
 
@@ -120,8 +119,7 @@ void CAppSettings::SetLongParameter(int iParameter, long iValue) {
   else {
     m_pLongTable[iParameter - FIRST_APP_LP].value = iValue;
     SaveSetting(m_pLongTable[iParameter - FIRST_APP_LP].regName, iValue); 
-    Dasher::CParameterNotificationEvent oEvent(iParameter);
-    m_pDasher->ExternalEventHandler(&oEvent);
+    m_pDasher->HandleEvent(iParameter);
   }
 }
 
@@ -138,8 +136,7 @@ void CAppSettings::SetStringParameter(int iParameter, const std::string &strValu
   else {
     m_pStringTable[iParameter - FIRST_APP_SP].value = strValue;
     SaveSetting(m_pStringTable[iParameter - FIRST_APP_SP].regName, strValue);
-    Dasher::CParameterNotificationEvent oEvent(iParameter);
-    m_pDasher->ExternalEventHandler(&oEvent);
+    m_pDasher->HandleEvent(iParameter);
   }
 }
 
@@ -154,6 +151,11 @@ void CAppSettings::ResetParamater(int iParameter) {
     SetStringParameter(iParameter, app_stringparamtable[iParameter - FIRST_APP_SP].szDefaultValue);
 }
 
+void CAppSettings::GetPermittedValues(int iParameter, vector<string> &vList) {
+  //Don't think there are any app-specific string parameters with permitted values?
+  DASHER_ASSERT(iParameter>=FIRST_SP && iParameter < END_OF_SPS);
+  m_pDasher->GetPermittedValues(iParameter,vList);
+}
 
 // Functions for accessing persistent storage (stolen from WinOptions)
 
diff --git a/Src/Win32/AppSettings.h b/Src/Win32/AppSettings.h
index 8abd6f7..39268bc 100644
--- a/Src/Win32/AppSettings.h
+++ b/Src/Win32/AppSettings.h
@@ -1,8 +1,10 @@
 #pragma once
 
-#include <string>
 #include "../Common/AppSettingsHeader.h"
 
+#include <vector>
+#include <string>
+
 #include <windows.h>
 
 //#include "WinCommon.h"
@@ -31,39 +33,19 @@ public:
   ~CAppSettings(void);
 
   ///
-  /// Get a boolean parameter
-
-  bool GetBoolParameter(int iParameter);
-
+  /// The following all just wrap corresponding methods in CDasher,
+  /// augmented for dealing with platform-specific parameters (APP_*),
+  /// allowing the AppSettings to be used as a central point-of-access
+  /// to all the settings data necessary for the GUI.
   ///
-  /// Set a boolean parameter
-
+  bool GetBoolParameter(int iParameter);
   void SetBoolParameter(int iParameter, bool bValue);
-
-  ///
-  /// Get a long integer parameter
-
   long GetLongParameter(int iParameter);
-
-  ///
-  /// Set a long integer parameter
-
   void SetLongParameter(int iParameter, long iValue);
-
-  ///
-  /// Get a string parameter
-
   std::string GetStringParameter(int iParameter);
-
-  ///
-  /// Set a string parameter
-
   void SetStringParameter(int iParameter, const std::string &strValue);
-
-  ///
-  /// Reset a parameter to its default value
-
   void ResetParamater(int iParameter);
+  void GetPermittedValues(int iParameter, std::vector<std::string> &vList);
 
   #ifndef DASHER_WINCE
   bool LoadSetting(const std::string & Key, LPWINDOWPLACEMENT pwp);
diff --git a/Src/Win32/BTSocketInput.cpp b/Src/Win32/BTSocketInput.cpp
index 16813cc..671fc8e 100644
--- a/Src/Win32/BTSocketInput.cpp
+++ b/Src/Win32/BTSocketInput.cpp
@@ -31,8 +31,8 @@ static const int ymax = -32;
 // TODO: This doesn't do any error handling at all
 // TODO: Probably incompatable with the socket server module
 
-CBTSocketInput::CBTSocketInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore)
-: CDasherCoordInput(pEventHandler, pSettingsStore, 100, "BT Tilt Socket"){
+CBTSocketInput::CBTSocketInput()
+: CDasherCoordInput(100, "BT Tilt Socket"){
 }
 
 CBTSocketInput::~CBTSocketInput(void) {
diff --git a/Src/Win32/BTSocketInput.h b/Src/Win32/BTSocketInput.h
index 0b69720..f8d698d 100644
--- a/Src/Win32/BTSocketInput.h
+++ b/Src/Win32/BTSocketInput.h
@@ -12,7 +12,7 @@ namespace Dasher {
 
 class Dasher::CBTSocketInput : public CDasherCoordInput {
 public:
-  CBTSocketInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore);
+  CBTSocketInput();
   ~CBTSocketInput(void);
 
   virtual bool GetDasherCoords(myint &iDasherX, myint &iDasherY, CDasherView *pView);
diff --git a/Src/Win32/Common/WinOptions.cpp b/Src/Win32/Common/WinOptions.cpp
index 2807068..f6d15ab 100644
--- a/Src/Win32/Common/WinOptions.cpp
+++ b/Src/Win32/Common/WinOptions.cpp
@@ -24,7 +24,7 @@ static char THIS_FILE[] = __FILE__;
 
 /* TODO: Consider using Template functions to make this neater. */
 
-CWinOptions::CWinOptions(const std::string &Group, const std::string &Product, Dasher::CEventHandler *pEventHandler):CSettingsStore(pEventHandler) {
+CWinOptions::CWinOptions(const std::string &Group, const std::string &Product) {
   // Windows requires strings as Tstring
   Tstring TGroup, TProduct;
   UTF8string_to_wstring(Group, TGroup);
diff --git a/Src/Win32/Common/WinOptions.h b/Src/Win32/Common/WinOptions.h
index dc1c57d..e471ced 100644
--- a/Src/Win32/Common/WinOptions.h
+++ b/Src/Win32/Common/WinOptions.h
@@ -17,11 +17,9 @@
 #include "../../DasherCore/SettingsStore.h"
 #include "../../Common/NoClones.h"
 
-class Dasher::CEventHandler;
-
-class CWinOptions:public CSettingsStore, private NoClones {
+class CWinOptions:public Dasher::CSettingsStore, private NoClones {
 public:
-  CWinOptions(const std::string & Group, const std::string & Product, Dasher::CEventHandler * pEventHandler);
+  CWinOptions(const std::string & Group, const std::string & Product);
    ~CWinOptions();
 
 #ifndef DASHER_WINCE
diff --git a/Src/Win32/Dasher.cpp b/Src/Win32/Dasher.cpp
index 180b18a..6e90a79 100644
--- a/Src/Win32/Dasher.cpp
+++ b/Src/Win32/Dasher.cpp
@@ -37,7 +37,7 @@ CONST UINT WM_DASHER_FOCUS = RegisterWindowMessage(_WM_DASHER_FOCUS);
 CONST UINT WM_DASHER_GAME_MESSAGE = RegisterWindowMessage(_WM_DASHER_GAME_MESSAGE);
 
 CDasher::CDasher(HWND Parent, CDasherWindow *pWindow, CEdit *pEdit)
- : m_hParent(Parent), m_pWindow(pWindow), m_pEdit(pEdit) {
+ : CDashIntfScreenMsgs(new CWinOptions( "Inference Group", "Dasher3")), m_hParent(Parent), m_pWindow(pWindow), m_pEdit(pEdit) {
   // This class will be a wrapper for the Dasher 'control' - think ActiveX
 
 #ifndef _WIN32_WCE
@@ -57,10 +57,10 @@ void CDasher::CreateModules() {
   //create default set first.
   CDasherInterfaceBase::CreateModules();
 #ifndef _WIN32_WCE
-  RegisterModule(new CSocketInput(this, m_pEventHandler, m_pSettingsStore));
-  RegisterModule(new CBTSocketInput(m_pEventHandler, m_pSettingsStore));
+  RegisterModule(new CSocketInput(this,this));
+  RegisterModule(new CBTSocketInput());
 #endif
-  RegisterModule(new CDasherMouseInput(m_pEventHandler, m_pSettingsStore, m_pCanvas->getwindow()));
+  RegisterModule(new CDasherMouseInput(m_pCanvas->getwindow()));
 }
 
 void CDasher::Main() {
@@ -110,12 +110,12 @@ void CDasher::Log() {
 
 }
 
-void Dasher::CDasher::ExternalEventHandler(CEvent* pEvent) {  
-  if (pEvent->m_iEventType==EV_PARAM_NOTIFY) {
-    int iParam(static_cast<CParameterNotificationEvent *> (pEvent)->m_iParameter);
-    m_pWindow->HandleParameterChange(iParam);
-    m_pEdit->HandleParameterChange(iParam);
-  }
+void Dasher::CDasher::HandleEvent(int iParameter) {
+  CDashIntfScreenMsgs::HandleEvent(iParameter);
+  m_pWindow->HandleParameterChange(iParameter);
+  m_pEdit->HandleParameterChange(iParameter);
+  if (iParameter == SP_DASHER_FONT)
+    m_pCanvas->SetFont(GetStringParameter(SP_DASHER_FONT));
 }
 
 void Dasher::CDasher::editOutput(const string &strText, CDasherNode *pSource) {
@@ -279,7 +279,7 @@ void CDasher::SetupPaths() {
 }
 
 void CDasher::SetupUI() {
-  m_pCanvas = new CCanvas(this, m_pEventHandler, m_pSettingsStore);
+  m_pCanvas = new CCanvas(this);
   m_pCanvas->Create(m_hParent); // TODO - check return 
 
   OnUIRealised();
@@ -296,10 +296,6 @@ int CDasher::GetFileSize(const std::string &strFileName) {
 #endif
 }
 
-void CDasher::CreateSettingsStore(void) {
-  m_pSettingsStore = new CWinOptions( "Inference Group", "Dasher3", m_pEventHandler );
-}
-
 void CDasher::StartTimer() {
   // TODO: See MessageLoop, Main in CDasherWindow - should be brought into this class
   // Framerate settings: currently 40fps.
diff --git a/Src/Win32/Dasher.h b/Src/Win32/Dasher.h
index 7b0551d..db7e7ac 100644
--- a/Src/Win32/Dasher.h
+++ b/Src/Win32/Dasher.h
@@ -47,7 +47,7 @@ public:
   void Move(int iX, int iY, int iWidth, int iHeight);
   void TakeFocus();
 
-  void ExternalEventHandler(Dasher::CEvent *pEvent);
+  void HandleEvent(int iParameter);
   void editOutput(const std::string &strText, CDasherNode *pSource);
   void editDelete(const std::string &strText, CDasherNode *pSource);
   unsigned int ctrlMove(bool bForwards, CControlManager::EditDistance iDist);
@@ -78,7 +78,6 @@ private:
   virtual void CreateModules();
   virtual void StartTimer();
   virtual void ShutdownTimer();
-  void CreateSettingsStore();
 
   void ScanDirectory(const Tstring &strMask, std::vector<std::string> &vFileList);
   bool                    GetWindowSize(int* pTop, int* pLeft, int* pBottom, int* pRight);
diff --git a/Src/Win32/DasherMouseInput.cpp b/Src/Win32/DasherMouseInput.cpp
index ccdd392..81cb9ee 100644
--- a/Src/Win32/DasherMouseInput.cpp
+++ b/Src/Win32/DasherMouseInput.cpp
@@ -14,8 +14,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CDasherMouseInput::CDasherMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, HWND _hwnd)
-: CScreenCoordInput(pEventHandler, pSettingsStore, 0, "Mouse Input"), m_hwnd(_hwnd) {
+CDasherMouseInput::CDasherMouseInput(HWND _hwnd)
+: CScreenCoordInput(0, "Mouse Input"), m_hwnd(_hwnd) {
 }
 
 CDasherMouseInput::~CDasherMouseInput(void) {
diff --git a/Src/Win32/DasherMouseInput.h b/Src/Win32/DasherMouseInput.h
index 23203bc..017def9 100644
--- a/Src/Win32/DasherMouseInput.h
+++ b/Src/Win32/DasherMouseInput.h
@@ -7,7 +7,7 @@ namespace Dasher {
 
 class Dasher::CDasherMouseInput : public CScreenCoordInput {
 public:
-  CDasherMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, HWND _hwnd);
+  CDasherMouseInput(HWND _hwnd);
   ~CDasherMouseInput(void);
 
   virtual bool GetScreenCoords(screenint &iX, screenint &iY, CDasherView *pView);
diff --git a/Src/Win32/DasherWindow.cpp b/Src/Win32/DasherWindow.cpp
index 890b499..70b6820 100644
--- a/Src/Win32/DasherWindow.cpp
+++ b/Src/Win32/DasherWindow.cpp
@@ -124,7 +124,7 @@ HWND CDasherWindow::Create() {
 
   m_pEdit->SetInterface(m_pDasher);
 
-  m_pSpeedAlphabetBar = new CStatusControl(m_pDasher);
+  m_pSpeedAlphabetBar = new CStatusControl(m_pAppSettings);
   m_pSpeedAlphabetBar->Create(hWnd);
 
   m_pGameGroup = new CGameGroup(m_pDasher, m_pEdit);
diff --git a/Src/Win32/ModuleControl.h b/Src/Win32/ModuleControl.h
index e3743dc..370dead 100644
--- a/Src/Win32/ModuleControl.h
+++ b/Src/Win32/ModuleControl.h
@@ -2,8 +2,8 @@
 #define __ModuleControl_h__
 
 #include "Common/WinCommon.h"
-#include "../DasherCore/DasherInterfaceBase.h"
-
+#include "AppSettings.h"
+#include "../Common/ModuleSettings.h"
 #include <atlbase.h>
 #include <atlwin.h>
 #include <string>
@@ -34,8 +34,8 @@ public:
 
   // Abstract members to be implemented by descendents
   virtual int GetHeightRequest() = 0;
-  virtual void Initialise(Dasher::CDasherInterfaceBase *pInterface) = 0;
-  virtual void Apply(Dasher::CDasherInterfaceBase *pInterface) = 0;
+  virtual void Initialise(CAppSettings*) = 0;
+  virtual void Apply(CAppSettings*) = 0;
   virtual void CreateChild(HWND hParent) = 0;
   virtual void LayoutChild(RECT &sRect) = 0;
 
diff --git a/Src/Win32/ModuleControlBool.cpp b/Src/Win32/ModuleControlBool.cpp
index c3ab86b..6af684c 100644
--- a/Src/Win32/ModuleControlBool.cpp
+++ b/Src/Win32/ModuleControlBool.cpp
@@ -4,15 +4,15 @@ int CModuleControlBool::GetHeightRequest() {
   return 10;
 }
 
-void CModuleControlBool::Initialise(Dasher::CDasherInterfaceBase *pInterface) {
-  if(pInterface->GetBoolParameter(m_iId))
+void CModuleControlBool::Initialise(CAppSettings *pAppSets) {
+  if(pAppSets->GetBoolParameter(m_iId))
     SendMessage(m_hCheckbox, BM_SETCHECK, BST_CHECKED, 0);
   else
     SendMessage(m_hCheckbox, BM_SETCHECK, BST_UNCHECKED, 0);
 }
 
-void CModuleControlBool::Apply(Dasher::CDasherInterfaceBase *pInterface) {
-  pInterface->SetBoolParameter(m_iId, SendMessage(m_hCheckbox, BM_GETCHECK, 0, 0) == BST_CHECKED);
+void CModuleControlBool::Apply(CAppSettings *pAppSets) {
+  pAppSets->SetBoolParameter(m_iId, SendMessage(m_hCheckbox, BM_GETCHECK, 0, 0) == BST_CHECKED);
 }
 
 void CModuleControlBool::CreateChild(HWND hParent) {
diff --git a/Src/Win32/ModuleControlBool.h b/Src/Win32/ModuleControlBool.h
index eccbe73..5a4e9d6 100644
--- a/Src/Win32/ModuleControlBool.h
+++ b/Src/Win32/ModuleControlBool.h
@@ -8,8 +8,8 @@ public:
   CModuleControlBool(SModuleSettings *pSetting) : CModuleControl(pSetting) {};
 
   virtual int GetHeightRequest();
-  virtual void Initialise(Dasher::CDasherInterfaceBase *pInterface);
-  virtual void Apply(Dasher::CDasherInterfaceBase *pInterface);
+  virtual void Initialise(CAppSettings *pAppSets);
+  virtual void Apply(CAppSettings *pAppSets);
   virtual void CreateChild(HWND hParent);
   virtual void LayoutChild(RECT &sRect);
 
diff --git a/Src/Win32/ModuleControlLong.cpp b/Src/Win32/ModuleControlLong.cpp
index f653b58..4dce4d7 100644
--- a/Src/Win32/ModuleControlLong.cpp
+++ b/Src/Win32/ModuleControlLong.cpp
@@ -17,8 +17,8 @@ int CModuleControlLong::GetHeightRequest() {
   return 12;
 }
 
-void CModuleControlLong::Initialise(Dasher::CDasherInterfaceBase *pInterface) {
-  int iValue(pInterface->GetLongParameter(m_iId));
+void CModuleControlLong::Initialise(CAppSettings *pAppSets) {
+  int iValue(pAppSets->GetLongParameter(m_iId));
   SendMessage(m_hSlider, TBM_SETPOS, (WPARAM)false, (LPARAM)iValue);
 
   WCHAR tcBuffer[256];
@@ -26,9 +26,9 @@ void CModuleControlLong::Initialise(Dasher::CDasherInterfaceBase *pInterface) {
   SendMessage(m_hEntry, WM_SETTEXT, 0, (LPARAM) tcBuffer);
 }
 
-void CModuleControlLong::Apply(Dasher::CDasherInterfaceBase *pInterface) {
+void CModuleControlLong::Apply(CAppSettings *pAppSets) {
   int iValue = SendMessage(m_hSlider, TBM_GETPOS, 0, 0);
-  pInterface->SetLongParameter(m_iId, iValue);
+  pAppSets->SetLongParameter(m_iId, iValue);
 }
 
 void CModuleControlLong::CreateChild(HWND hParent) {
diff --git a/Src/Win32/ModuleControlLong.h b/Src/Win32/ModuleControlLong.h
index b3d15ca..09d3253 100644
--- a/Src/Win32/ModuleControlLong.h
+++ b/Src/Win32/ModuleControlLong.h
@@ -10,8 +10,8 @@ public:
   virtual LRESULT OnScroll(UINT message, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
  
   virtual int GetHeightRequest();
-  virtual void Initialise(Dasher::CDasherInterfaceBase *pInterface);
-  virtual void Apply(Dasher::CDasherInterfaceBase *pInterface);
+  virtual void Initialise(CAppSettings *pAppSets);
+  virtual void Apply(CAppSettings *pAppSets);
   virtual void CreateChild(HWND hParent);
   virtual void LayoutChild(RECT &sRect);
 
diff --git a/Src/Win32/ModuleControlLongSpin.cpp b/Src/Win32/ModuleControlLongSpin.cpp
index 4d39fb7..be7ce60 100644
--- a/Src/Win32/ModuleControlLongSpin.cpp
+++ b/Src/Win32/ModuleControlLongSpin.cpp
@@ -4,15 +4,15 @@ int CModuleControlLongSpin::GetHeightRequest() {
   return 12;
 }
 
-void CModuleControlLongSpin::Initialise(Dasher::CDasherInterfaceBase *pInterface) {
-  int iValue(pInterface->GetLongParameter(m_iId));
+void CModuleControlLongSpin::Initialise(CAppSettings *pAppSets) {
+  int iValue(pAppSets->GetLongParameter(m_iId));
   SendMessage(m_hSpin, UDM_SETPOS, 0, (LPARAM) MAKELONG ((short)iValue, 0));
   UpdateEntry(iValue, 0);
 }
 
-void CModuleControlLongSpin::Apply(Dasher::CDasherInterfaceBase *pInterface) {
+void CModuleControlLongSpin::Apply(CAppSettings *pAppSets) {
   int iValue(SendMessage(m_hSpin, UDM_GETPOS, 0, 0));
-  pInterface->SetLongParameter(m_iId, iValue);
+  pAppSets->SetLongParameter(m_iId, iValue);
 }
 
 void CModuleControlLongSpin::CreateChild(HWND hParent) {
diff --git a/Src/Win32/ModuleControlLongSpin.h b/Src/Win32/ModuleControlLongSpin.h
index 71a4f92..12845fc 100644
--- a/Src/Win32/ModuleControlLongSpin.h
+++ b/Src/Win32/ModuleControlLongSpin.h
@@ -10,8 +10,8 @@ public:
   virtual LRESULT OnNotify(UINT message, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
 
   virtual int GetHeightRequest();
-  virtual void Initialise(Dasher::CDasherInterfaceBase *pInterface);
-  virtual void Apply(Dasher::CDasherInterfaceBase *pInterface);
+  virtual void Initialise(CAppSettings *pAppSets);
+  virtual void Apply(CAppSettings *pAppSets);
   virtual void CreateChild(HWND hParent);
   virtual void LayoutChild(RECT &sRect);
 
diff --git a/Src/Win32/ModuleControlString.cpp b/Src/Win32/ModuleControlString.cpp
index a9676da..807a781 100644
--- a/Src/Win32/ModuleControlString.cpp
+++ b/Src/Win32/ModuleControlString.cpp
@@ -4,20 +4,20 @@ int CModuleControlString::GetHeightRequest() {
   return 14;
 }
 
-void CModuleControlString::Initialise(Dasher::CDasherInterfaceBase *pInterface) {
+void CModuleControlString::Initialise(CAppSettings *pAppSets) {
   std::wstring strText;
-  WinUTF8::UTF8string_to_wstring(pInterface->GetStringParameter(m_iId), strText);
+  WinUTF8::UTF8string_to_wstring(pAppSets->GetStringParameter(m_iId), strText);
   SendMessage(m_hEntry, WM_SETTEXT, 0, (LPARAM)strText.c_str());
 }
 
-void CModuleControlString::Apply(Dasher::CDasherInterfaceBase *pInterface) {
+void CModuleControlString::Apply(CAppSettings *pAppSets) {
   TCHAR tcBuffer[256];
   SendMessage(m_hEntry, WM_GETTEXT, 100, (LPARAM)tcBuffer);
   
   std::string strUTF8Text;
   WinUTF8::wstring_to_UTF8string(tcBuffer, strUTF8Text);
 
-  pInterface->SetStringParameter(m_iId, strUTF8Text);
+  pAppSets->SetStringParameter(m_iId, strUTF8Text);
 }
 
 void CModuleControlString::CreateChild(HWND hParent) {
diff --git a/Src/Win32/ModuleControlString.h b/Src/Win32/ModuleControlString.h
index 694ae85..8a51197 100644
--- a/Src/Win32/ModuleControlString.h
+++ b/Src/Win32/ModuleControlString.h
@@ -8,8 +8,8 @@ public:
   CModuleControlString(SModuleSettings *pSetting) : CModuleControl(pSetting) {};
 
   virtual int GetHeightRequest();
-  virtual void Initialise(Dasher::CDasherInterfaceBase *pInterface);
-  virtual void Apply(Dasher::CDasherInterfaceBase *pInterface);
+  virtual void Initialise(CAppSettings *pAppSets);
+  virtual void Apply(CAppSettings *pAppSets);
   virtual void CreateChild(HWND hParent);
   virtual void LayoutChild(RECT &sRect);
 
diff --git a/Src/Win32/ModuleSettings.cpp b/Src/Win32/ModuleSettings.cpp
index 869fff1..2a00e50 100644
--- a/Src/Win32/ModuleSettings.cpp
+++ b/Src/Win32/ModuleSettings.cpp
@@ -6,10 +6,10 @@
 
 CONST UINT WM_MS_CLOSE = RegisterWindowMessage(_WM_MS_CLOSE);
 
-CModuleSettings::CModuleSettings(const std::string &strModuleName, SModuleSettings *pSettings, int iCount, Dasher::CDasherInterfaceBase *pInterface) {
+CModuleSettings::CModuleSettings(const std::string &strModuleName, SModuleSettings *pSettings, int iCount, CAppSettings *pAppSets) {
   m_iCount = iCount;
   m_pControls = new CModuleControl*[m_iCount];
-  m_pInterface = pInterface;
+  m_pAppSets = pAppSets;
   m_strModuleName = strModuleName;
 
   for(int i(0); i < m_iCount; ++i) {
@@ -51,7 +51,7 @@ void CModuleSettings::Create(HWND hWndParent, ATL::_U_RECT rect) {
 
   for(int i(0); i < m_iCount; ++i) {
     m_pControls[i]->Create(m_hWnd);
-    m_pControls[i]->Initialise(m_pInterface);
+    m_pControls[i]->Initialise(m_pAppSets);
     iHeight += m_pControls[i]->GetHeightRequest() + 2;
   }
 
@@ -101,7 +101,7 @@ LRESULT CModuleSettings::OnCommand(UINT message, WPARAM wParam, LPARAM lParam, B
       bHandled = true;
       // Apply and close 
       for(int i(0); i < m_iCount; ++i) {
-        m_pControls[i]->Apply(m_pInterface);
+        m_pControls[i]->Apply(m_pAppSets);
       }
       ShowWindow(SW_HIDE);
       SendMessage(m_hParent, WM_MS_CLOSE, 0, 0);
diff --git a/Src/Win32/ModuleSettings.h b/Src/Win32/ModuleSettings.h
index 497f09a..1fe6f46 100644
--- a/Src/Win32/ModuleSettings.h
+++ b/Src/Win32/ModuleSettings.h
@@ -1,7 +1,7 @@
 //#ifndef __ModuleSettings_h__
 //#define __ModuleSettings_h__
 
-#include "../DasherCore/DasherInterfaceBase.h"
+#include "AppSettings.h"
 #include "ModuleControl.h"
 
 #include <atlbase.h>
@@ -13,7 +13,7 @@ extern CONST UINT WM_MS_CLOSE;
 
 class CModuleSettings : public CWindowImpl<CModuleSettings> {
 public:
-  CModuleSettings(const std::string &strModuleName, SModuleSettings *pSettings, int iCount, Dasher::CDasherInterfaceBase *pInterface);
+  CModuleSettings(const std::string &strModuleName, SModuleSettings *pSettings, int iCount, CAppSettings *pAppSets);
   ~CModuleSettings();
 
   void Create(HWND hWndParent, ATL::_U_RECT rect);
@@ -44,7 +44,7 @@ private:
   HWND m_hOk;
   HWND m_hCancel;
 
-  Dasher::CDasherInterfaceBase *m_pInterface;
+  CAppSettings *m_pAppSets;
 };
 
 //#endif
\ No newline at end of file
diff --git a/Src/Win32/Sockets/SocketInput.cpp b/Src/Win32/Sockets/SocketInput.cpp
index 7ef733f..54fedab 100644
--- a/Src/Win32/Sockets/SocketInput.cpp
+++ b/Src/Win32/Sockets/SocketInput.cpp
@@ -52,9 +52,9 @@ static char THIS_FILE[] = __FILE__;
 
 
 
-CSocketInput::CSocketInput(CMessageDisplay *pMsgs, CEventHandler * pEventHandler, CSettingsStore * pSettingsStore)
+CSocketInput::CSocketInput(CSettingsUser *pCreator,CMessageDisplay *pMsgs)
 
-:CSocketInputBase(pMsgs, pEventHandler, pSettingsStore) {
+:CSocketInputBase(pCreator, pMsgs) {
 
 
 
diff --git a/Src/Win32/Sockets/SocketInput.h b/Src/Win32/Sockets/SocketInput.h
index 923bb6b..4a997af 100644
--- a/Src/Win32/Sockets/SocketInput.h
+++ b/Src/Win32/Sockets/SocketInput.h
@@ -15,7 +15,7 @@ class Dasher::CSocketInput:public CSocketInputBase {
 
 public:
 
-  CSocketInput(CMessageDisplay *pMsgs, CEventHandler * pEventHandler, CSettingsStore * pSettingsStore);
+  CSocketInput(CSettingsUser *pCreator,CMessageDisplay *pMsgs);
   ~CSocketInput();
 
   void SetDebug(bool _debug);
diff --git a/Src/Win32/Widgets/AdvancedPage.cpp b/Src/Win32/Widgets/AdvancedPage.cpp
index 1ce2156..9c2dead 100644
--- a/Src/Win32/Widgets/AdvancedPage.cpp
+++ b/Src/Win32/Widgets/AdvancedPage.cpp
@@ -27,8 +27,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CAdvancedPage::CAdvancedPage(HWND Parent, CDasherInterfaceBase *DI, CAppSettings *pAppSettings)
-:CPrefsPageBase(Parent, DI, pAppSettings) {
+CAdvancedPage::CAdvancedPage(HWND Parent, CAppSettings *pAppSettings)
+:CPrefsPageBase(Parent, pAppSettings) {
 }
 
 struct menuentry {
@@ -70,7 +70,6 @@ void CAdvancedPage::PopulateList() {
 
 
   // Populate the controls in the dialogue box based on the relevent parameters
-  // in m_pDasherInterface
   for(int ii = 0; ii<sizeof(menutable)/sizeof(menuentry); ii++)
   {
     if(m_pAppSettings->GetBoolParameter(menutable[ii].paramNum)) {
diff --git a/Src/Win32/Widgets/AdvancedPage.h b/Src/Win32/Widgets/AdvancedPage.h
index ae9da1f..29a8f83 100644
--- a/Src/Win32/Widgets/AdvancedPage.h
+++ b/Src/Win32/Widgets/AdvancedPage.h
@@ -14,12 +14,9 @@
 #include "../resource.h"
 #include "../AppSettings.h"
 
-#include "../../DasherCore/DasherInterfaceBase.h"
-#include "../../DasherCore/ColourIO.h"
-
 class CAdvancedPage:public CPrefsPageBase {
 public:
-  CAdvancedPage(HWND Parent, Dasher::CDasherInterfaceBase * DI, CAppSettings *pAppSettings);
+  CAdvancedPage(HWND Parent, CAppSettings *pAppSettings);
   
   LRESULT WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM lParam);
 
@@ -29,9 +26,6 @@ private:
 
   std::string GetControlText(HWND Dialog, int ControlID);
 
-  std::vector < std::string > ColourList;
-  std::string m_CurrentColours;
-  Dasher::CColourIO::ColourInfo CurrentInfo;
 
   // Some status flags:
   void PopulateList();
diff --git a/Src/Win32/Widgets/AlphabetBox.cpp b/Src/Win32/Widgets/AlphabetBox.cpp
index 479caea..48e9d07 100644
--- a/Src/Win32/Widgets/AlphabetBox.cpp
+++ b/Src/Win32/Widgets/AlphabetBox.cpp
@@ -10,6 +10,7 @@
 
 #include "AlphabetBox.h"
 #include "../resource.h"
+#include "../../DasherCore/DasherTypes.h"
 
 using namespace Dasher;
 using namespace std;
@@ -35,8 +36,8 @@ static menuentry menutable[] = {
   {BP_PALETTE_CHANGE, IDC_COLOURSCHEME, true}
 };
 
-CAlphabetBox::CAlphabetBox(HWND Parent, CDasherInterfaceBase *DI, CAppSettings *pAppSettings)
-: CPrefsPageBase(Parent, DI, pAppSettings), m_pDasherInterface(DI), m_CurrentAlphabet(DI->GetStringParameter(SP_ALPHABET_ID)),  Editing(false), Cloning(false), EditChar(false), CustomBox(0), CurrentGroup(0), CurrentChar(0) {
+CAlphabetBox::CAlphabetBox(HWND Parent, CAppSettings *pAppSettings)
+: CPrefsPageBase(Parent, pAppSettings), m_CurrentAlphabet(pAppSettings->GetStringParameter(SP_ALPHABET_ID)),  Editing(false), Cloning(false), EditChar(false), CustomBox(0), CurrentGroup(0), CurrentChar(0) {
   m_hwnd = 0;
   m_hPropertySheet = 0;
 }
@@ -115,9 +116,9 @@ void CAlphabetBox::PopulateList() {
   HWND ListBox = GetDlgItem(m_hwnd, IDC_ALPHABETS);
   SendMessage(ListBox, LB_RESETCONTENT, 0, 0);
 
-  m_CurrentAlphabet = m_pDasherInterface->GetStringParameter(SP_ALPHABET_ID);
+  m_CurrentAlphabet = m_pAppSettings->GetStringParameter(SP_ALPHABET_ID);
 
-  m_pDasherInterface->GetPermittedValues(SP_ALPHABET_ID, AlphabetList);
+  m_pAppSettings->GetPermittedValues(SP_ALPHABET_ID, AlphabetList);
 
   int iDefaultIndex(-1);
   int iFallbackIndex(-1);
@@ -158,7 +159,7 @@ void CAlphabetBox::PopulateList() {
 // all the button checkboxes
   for(int ii = 0; ii<sizeof(menutable)/sizeof(menuentry); ii++)
   {
-    if(m_pDasherInterface->GetBoolParameter(menutable[ii].paramNum) != menutable[ii].bInvert) 
+    if(m_pAppSettings->GetBoolParameter(menutable[ii].paramNum) != menutable[ii].bInvert) 
 	    SendMessage(GetDlgItem(m_hwnd, menutable[ii].idcNum), BM_SETCHECK, BST_CHECKED, 0);
     else  
 	    SendMessage(GetDlgItem(m_hwnd, menutable[ii].idcNum), BM_SETCHECK, BST_UNCHECKED, 0);
@@ -433,13 +434,12 @@ bool CAlphabetBox::Apply() {
 
 
   if(m_CurrentAlphabet != std::string("")) {
-    if(m_CurrentAlphabet != m_pDasherInterface->GetStringParameter(SP_ALPHABET_ID))
-      m_pDasherInterface->SetStringParameter(SP_ALPHABET_ID, m_CurrentAlphabet); 
+    m_pAppSettings->SetStringParameter(SP_ALPHABET_ID, m_CurrentAlphabet); 
   }
 
   for(int ii = 0; ii<sizeof(menutable)/sizeof(menuentry); ii++)
   {
-    m_pDasherInterface->SetBoolParameter(menutable[ii].paramNum, 
+    m_pAppSettings->SetBoolParameter(menutable[ii].paramNum, 
       (SendMessage(GetDlgItem(m_hwnd, menutable[ii].idcNum), BM_GETCHECK, 0, 0) == BST_CHECKED) != menutable[ii].bInvert);
   }
 
@@ -733,7 +733,7 @@ LRESULT CAlphabetBox::WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM l
     //  break;
     //case (IDOK):
     //  if(m_CurrentAlphabet != std::string("")) {
-    //    m_pDasherInterface->SetStringParameter(SP_ALPHABET_ID, m_CurrentAlphabet);
+    //    m_pAppSettings->SetStringParameter(SP_ALPHABET_ID, m_CurrentAlphabet);
     //  }
     //  // deliberate fall through
     //case (IDCANCEL):
diff --git a/Src/Win32/Widgets/AlphabetBox.h b/Src/Win32/Widgets/AlphabetBox.h
index 2590bd8..7b3a106 100644
--- a/Src/Win32/Widgets/AlphabetBox.h
+++ b/Src/Win32/Widgets/AlphabetBox.h
@@ -15,11 +15,10 @@
 
 class CAlphabetBox : public CPrefsPageBase {
 public:
-	CAlphabetBox(HWND Parent, Dasher::CDasherInterfaceBase *DI, CAppSettings *pAppSettings);
+	CAlphabetBox(HWND Parent, CAppSettings *pAppSettings);
 protected:
 	LRESULT WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM lParam);
 private:
-  Dasher::CDasherInterfaceBase * m_pDasherInterface;
   HWND m_hPropertySheet;
 
   HWND CustomBox;
@@ -28,9 +27,9 @@ private:
   std::string m_CurrentAlphabet;
   //Dasher::CAlphInfo CurrentInfo;//for editing alphabets
 
-  std::vector < std::string > ColourList;
+  //std::vector < std::string > ColourList;
   
-  Dasher::CColourIO::ColourInfo CurrentColourInfo;
+  //Dasher::CColourIO::ColourInfo CurrentColourInfo;
 
   // Some status flags:
   bool Editing;
diff --git a/Src/Win32/Widgets/Canvas.cpp b/Src/Win32/Widgets/Canvas.cpp
index 7ce700d..04f2091 100644
--- a/Src/Win32/Widgets/Canvas.cpp
+++ b/Src/Win32/Widgets/Canvas.cpp
@@ -38,11 +38,7 @@
 
 using namespace Dasher;
 
-CCanvas::CCanvas(CDasher *DI, Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore)
-  : CDasherComponent(pEventHandler, pSettingsStore) {
-
-  m_pDasherInterface = DI;
-  
+CCanvas::CCanvas(CDasher *DI) : m_pDasherInterface(DI) {
  
   m_dwTicksLastEvent = 0;
   m_bButtonDown = false;
@@ -591,14 +587,8 @@ bool CCanvas::GetCanvasSize(int& iTop, int& iLeft, int& iBottom, int& iRight) {
 }
 
 
-void CCanvas::HandleEvent(Dasher::CEvent *pEvent) {
-
-  if(pEvent->m_iEventType == 1) {
-    Dasher::CParameterNotificationEvent * pEvt(static_cast < Dasher::CParameterNotificationEvent * >(pEvent));
-    switch (pEvt->m_iParameter) {
-      case SP_DASHER_FONT:
-        m_pScreen->SetFont(m_pDasherInterface->GetStringParameter(SP_DASHER_FONT));
-        break;
+void CCanvas::SetFont(const std::string &strFont) {
+    m_pScreen->SetFont(strFont);
   /*  case BP_SOCKET_INPUT_ENABLE:
       OutputDebugString(TEXT("Processing BP_SOCKET_INPUT_ENABLE change\n"));
       if(GetBoolParameter(BP_SOCKET_INPUT_ENABLE)) {
@@ -613,9 +603,7 @@ void CCanvas::HandleEvent(Dasher::CEvent *pEvent) {
         }
         m_pDasherInterface->SetInput(0);
       }
-      break;*/
-    default:
       break;
     }
-  }
+  }*/
 }
diff --git a/Src/Win32/Widgets/Canvas.h b/Src/Win32/Widgets/Canvas.h
index 108f309..4f07406 100644
--- a/Src/Win32/Widgets/Canvas.h
+++ b/Src/Win32/Widgets/Canvas.h
@@ -39,7 +39,6 @@
 #include "../TabletPC/CursorInRange.h"
 #endif 
 
-#include "../../DasherCore/DasherComponent.h"
 #include "../../DasherCore/DasherTypes.h"
 #include "../KeyboardHelper.h"
 
@@ -53,7 +52,7 @@ namespace Dasher {
 class CEdit;
 class CScreen;
   
-class CCanvas : public ATL::CWindowImpl<CCanvas>, public Dasher::CDasherComponent {
+class CCanvas : public ATL::CWindowImpl<CCanvas> {
  public:
   static ATL::CWndClassInfo& GetWndClassInfo() { 
 #ifndef _WIN32_WCE
@@ -97,7 +96,7 @@ class CCanvas : public ATL::CWindowImpl<CCanvas>, public Dasher::CDasherComponen
 #endif
   END_MSG_MAP()
 
-  CCanvas(Dasher::CDasher *DI, Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore);
+  CCanvas(Dasher::CDasher *DI);
   ~CCanvas();
 
   HWND Create(HWND hParent);
@@ -182,7 +181,7 @@ class CCanvas : public ATL::CWindowImpl<CCanvas>, public Dasher::CDasherComponen
 
   bool GetCanvasSize(int& pTop, int& pLeft, int& pBottom, int& pRight);
 
-  void HandleEvent(Dasher::CEvent *pEvent);
+  void SetFont(const std::string &strFont);
 
 private:
 
diff --git a/Src/Win32/Widgets/ControlPage.cpp b/Src/Win32/Widgets/ControlPage.cpp
index 5c54af6..8919d29 100644
--- a/Src/Win32/Widgets/ControlPage.cpp
+++ b/Src/Win32/Widgets/ControlPage.cpp
@@ -22,7 +22,7 @@ using namespace std;
 
 
 CControlPage::CControlPage(HWND Parent, CDasherInterfaceBase *DI, CAppSettings *pAppSettings)
-:CPrefsPageBase(Parent, DI, pAppSettings) {
+:CPrefsPageBase(Parent, pAppSettings), m_pDasherInterface(DI) {
 }
 
 struct menuentry {
@@ -105,7 +105,7 @@ void CControlPage::PopulateList() {
  // {
 //    int i(0);
     std::vector<std::string> vValues;
-    m_pDasherInterface->GetPermittedValues(listtable[i].paramNum, vValues);
+    m_pAppSettings->GetPermittedValues(listtable[i].paramNum, vValues);
 
     for(std::vector<std::string>::iterator it(vValues.begin()); it != vValues.end(); ++it) {
       Tstring Item;
@@ -307,7 +307,7 @@ LRESULT CControlPage::WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM l
 
           RECT sRect;
 
-          m_pModuleSettingsDialogue = new CModuleSettings(strNewValue, pSettings, iSettingsCount, m_pDasherInterface);
+          m_pModuleSettingsDialogue = new CModuleSettings(strNewValue, pSettings, iSettingsCount, m_pAppSettings);
           m_pModuleSettingsDialogue->Create(m_hwnd, &sRect);
           m_pModuleSettingsDialogue->ShowWindow(SW_RESTORE);
         
@@ -336,7 +336,7 @@ LRESULT CControlPage::WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM l
 
           RECT sRect;
 
-          m_pModuleSettingsDialogue = new CModuleSettings(strNewValue, pSettings, iSettingsCount, m_pDasherInterface);
+          m_pModuleSettingsDialogue = new CModuleSettings(strNewValue, pSettings, iSettingsCount, m_pAppSettings);
           m_pModuleSettingsDialogue->Create(m_hwnd, &sRect);
           m_pModuleSettingsDialogue->ShowWindow(SW_RESTORE);
         
diff --git a/Src/Win32/Widgets/ControlPage.h b/Src/Win32/Widgets/ControlPage.h
index d656555..fa53d85 100644
--- a/Src/Win32/Widgets/ControlPage.h
+++ b/Src/Win32/Widgets/ControlPage.h
@@ -27,6 +27,8 @@ protected:
 private:
   HWND CustomBox;
   
+  Dasher::CDasherInterfaceBase *m_pDasherInterface;
+
   std::vector < std::string > ColourList;
   std::string m_CurrentColours;
   Dasher::CColourIO::ColourInfo CurrentInfo;
diff --git a/Src/Win32/Widgets/LMPage.cpp b/Src/Win32/Widgets/LMPage.cpp
index 6304727..8ab1762 100644
--- a/Src/Win32/Widgets/LMPage.cpp
+++ b/Src/Win32/Widgets/LMPage.cpp
@@ -26,8 +26,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CLMPage::CLMPage(HWND Parent, CDasherInterfaceBase *DI, CAppSettings *pAppSettings)
-:CPrefsPageBase(Parent, DI, pAppSettings) {
+CLMPage::CLMPage(HWND Parent, CAppSettings *pAppSettings)
+:CPrefsPageBase(Parent, pAppSettings) {
  
 }
 
diff --git a/Src/Win32/Widgets/LMPage.h b/Src/Win32/Widgets/LMPage.h
index 2a0ab4f..c8d9ff2 100644
--- a/Src/Win32/Widgets/LMPage.h
+++ b/Src/Win32/Widgets/LMPage.h
@@ -14,12 +14,9 @@
 #include "../resource.h"
 #include "../AppSettings.h"
 
-#include "../../DasherCore/DasherInterfaceBase.h"
-#include "../../DasherCore/ColourIO.h"
-
 class CLMPage:public CPrefsPageBase {
 public:
-  CLMPage(HWND Parent, Dasher::CDasherInterfaceBase * DI, CAppSettings *pAppSettings);
+  CLMPage(HWND Parent, CAppSettings *pAppSettings);
 protected:
   LRESULT WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM lParam);
 private:
diff --git a/Src/Win32/Widgets/Prefs.cpp b/Src/Win32/Widgets/Prefs.cpp
index 60b48e0..7a618ca 100755
--- a/Src/Win32/Widgets/Prefs.cpp
+++ b/Src/Win32/Widgets/Prefs.cpp
@@ -24,10 +24,10 @@ CPrefs::CPrefs(HWND hParent, CDasher *pDasher, CAppSettings *pAppSettings) {
   m_hwnd = 0;
 
   // FIXME - is hParent still needed here?
-  m_pAlphabetBox = new CAlphabetBox(hParent, pDasher, pAppSettings);
+  m_pAlphabetBox = new CAlphabetBox(hParent, pAppSettings);
   m_pControlPage = new CControlPage(hParent, pDasher, pAppSettings);
-  m_pViewPage = new CViewPage(hParent, pDasher, pAppSettings);
-  m_pAdvancedPage = new CAdvancedPage(hParent, pDasher, pAppSettings);
+  m_pViewPage = new CViewPage(hParent, pAppSettings);
+  m_pAdvancedPage = new CAdvancedPage(hParent, pAppSettings);
  // m_pLMPage = new CLMPage(hParent, pDasher, pAppSettings);
 
   // Set up the property sheets which go into the preferences
diff --git a/Src/Win32/Widgets/PrefsPageBase.cpp b/Src/Win32/Widgets/PrefsPageBase.cpp
index 6041ef7..ccc8958 100755
--- a/Src/Win32/Widgets/PrefsPageBase.cpp
+++ b/Src/Win32/Widgets/PrefsPageBase.cpp
@@ -26,8 +26,8 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CPrefsPageBase::CPrefsPageBase(HWND Parent, CDasherInterfaceBase *DI, CAppSettings *pAppSettings)
-:m_pDasherInterface(DI), m_pAppSettings(pAppSettings) {
+CPrefsPageBase::CPrefsPageBase(HWND Parent, CAppSettings *pAppSettings)
+: m_pAppSettings(pAppSettings) {
   m_hwnd = 0;
   m_hPropertySheet = 0;
 }
diff --git a/Src/Win32/Widgets/PrefsPageBase.h b/Src/Win32/Widgets/PrefsPageBase.h
index d5431f6..b345da1 100755
--- a/Src/Win32/Widgets/PrefsPageBase.h
+++ b/Src/Win32/Widgets/PrefsPageBase.h
@@ -16,11 +16,9 @@
 #include "../resource.h"
 #include "../AppSettings.h"
 
-#include "../../DasherCore/DasherInterfaceBase.h"
-
 class CPrefsPageBase:public CWinWrap {
 public:
-	CPrefsPageBase(HWND Parent, Dasher::CDasherInterfaceBase * DI, CAppSettings *pAppSettings);
+	CPrefsPageBase(HWND Parent, CAppSettings *pAppSettings);
 
 protected:
   LRESULT WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM lParam);
@@ -33,8 +31,7 @@ protected:
   // what's up in order to prevent page turning.
   virtual bool Validate();
   
-  Dasher::CDasherInterfaceBase * m_pDasherInterface;
-  CAppSettings *m_pAppSettings;
+  CAppSettings * const m_pAppSettings;
   HWND m_hPropertySheet; // the property sheet of which we are one page
 };
 
diff --git a/Src/Win32/Widgets/Slidebar.cpp b/Src/Win32/Widgets/Slidebar.cpp
index 9263b0d..85d1c2f 100644
--- a/Src/Win32/Widgets/Slidebar.cpp
+++ b/Src/Win32/Widgets/Slidebar.cpp
@@ -25,7 +25,7 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CSlidebar::CSlidebar(HWND ParentWindow, CDasherInterfaceBase *NewDasherInterface) {
+CSlidebar::CSlidebar(HWND ParentWindow, CAppSettings *pAppSettings) {
   m_hRebar = CreateWindowEx(WS_EX_WINDOWEDGE,
                             REBARCLASSNAME,
                             NULL,
@@ -48,7 +48,7 @@ CSlidebar::CSlidebar(HWND ParentWindow, CDasherInterfaceBase *NewDasherInterface
   rbBand.fMask  = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE;
   rbBand.fStyle = RBBS_CHILDEDGE | RBBS_GRIPPERALWAYS;
 
-  m_pStatusControl = new CStatusControl(NewDasherInterface);
+  m_pStatusControl = new CStatusControl(pAppSettings);
   m_pStatusControl->Create(ParentWindow);
 
   RECT rc;
diff --git a/Src/Win32/Widgets/Slidebar.h b/Src/Win32/Widgets/Slidebar.h
index 199eeeb..9deb898 100644
--- a/Src/Win32/Widgets/Slidebar.h
+++ b/Src/Win32/Widgets/Slidebar.h
@@ -16,12 +16,11 @@
 #define __Slidebar_h__
 
 #include "Canvas.h"
-#include "../../DasherCore/DasherInterfaceBase.h"
 #include "StatusControl.h"
 
 class CSlidebar {
 public:
-	CSlidebar(HWND ParentWindow, Dasher::CDasherInterfaceBase * DasherInterface);
+	CSlidebar(HWND ParentWindow, CAppSettings *pAppSettings);
 
   // Called when the parent window gets resized, makes the rebar position itself correctly
   void Resize();
diff --git a/Src/Win32/Widgets/StatusControl.cpp b/Src/Win32/Widgets/StatusControl.cpp
index 4a89d2b..858357d 100644
--- a/Src/Win32/Widgets/StatusControl.cpp
+++ b/Src/Win32/Widgets/StatusControl.cpp
@@ -6,8 +6,7 @@
 // TODO: Make this a notify?
 CONST UINT DASHER_SHOW_PREFS = RegisterWindowMessage(_DASHER_SHOW_PREFS);
 
-CStatusControl::CStatusControl(Dasher::CDasherInterfaceBase *pDasherInterface) {
-  m_pDasherInterface = pDasherInterface;
+CStatusControl::CStatusControl(CAppSettings *pAppSettings) : m_pAppSettings(pAppSettings) {
 }
 
 // TODO: ATL has more sophisticated handlers for conrol and notify messages - consider using them instead
@@ -37,7 +36,7 @@ LRESULT CStatusControl::OnNotify(UINT message, WPARAM wParam, LPARAM lParam, BOO
         SendMessage(m_hEdit, WM_GETTEXT, 32, (long)wszBuffer);
         double dNewSpeed = _tstof(wszBuffer);
 
-        m_pDasherInterface->SetLongParameter(LP_MAX_BITRATE, dNewSpeed * 100);
+        m_pAppSettings->SetLongParameter(LP_MAX_BITRATE, dNewSpeed * 100);
       }
       break;
     default:
@@ -188,22 +187,22 @@ void CStatusControl::PopulateCombo() {
 
   std::wstring strEntry;
   
-  WinUTF8::UTF8string_to_wstring(m_pDasherInterface->GetStringParameter(SP_ALPHABET_ID), strEntry);
+  WinUTF8::UTF8string_to_wstring(m_pAppSettings->GetStringParameter(SP_ALPHABET_ID), strEntry);
   SendMessage(m_hCombo, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR)strEntry.c_str());
 
-  WinUTF8::UTF8string_to_wstring(m_pDasherInterface->GetStringParameter(SP_ALPHABET_1), strEntry);
+  WinUTF8::UTF8string_to_wstring(m_pAppSettings->GetStringParameter(SP_ALPHABET_1), strEntry);
   if(strEntry.size() > 0)
     SendMessage(m_hCombo, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR)strEntry.c_str());
 
-  WinUTF8::UTF8string_to_wstring(m_pDasherInterface->GetStringParameter(SP_ALPHABET_2), strEntry);
+  WinUTF8::UTF8string_to_wstring(m_pAppSettings->GetStringParameter(SP_ALPHABET_2), strEntry);
   if(strEntry.size() > 0)
     SendMessage(m_hCombo, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR)strEntry.c_str());
 
-  WinUTF8::UTF8string_to_wstring(m_pDasherInterface->GetStringParameter(SP_ALPHABET_3), strEntry);
+  WinUTF8::UTF8string_to_wstring(m_pAppSettings->GetStringParameter(SP_ALPHABET_3), strEntry);
   if(strEntry.size() > 0)
     SendMessage(m_hCombo, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR)strEntry.c_str());
 
-  WinUTF8::UTF8string_to_wstring(m_pDasherInterface->GetStringParameter(SP_ALPHABET_4), strEntry);
+  WinUTF8::UTF8string_to_wstring(m_pAppSettings->GetStringParameter(SP_ALPHABET_4), strEntry);
   if(strEntry.size() > 0)
     SendMessage(m_hCombo, CB_ADDSTRING, 0, (LPARAM) (LPCTSTR)strEntry.c_str());
 
@@ -226,14 +225,14 @@ void CStatusControl::SelectAlphabet() {
     std::string strNewValue;
     WinUTF8::wstring_to_UTF8string(szSelection, strNewValue);
 
-    m_pDasherInterface->SetStringParameter(SP_ALPHABET_ID, strNewValue);
+    m_pAppSettings->SetStringParameter(SP_ALPHABET_ID, strNewValue);
   }
 
   delete[] szSelection;
 }
 
 void CStatusControl::PopulateSpeed() {
-  int iValue(m_pDasherInterface->GetLongParameter(LP_MAX_BITRATE));
+  int iValue(m_pAppSettings->GetLongParameter(LP_MAX_BITRATE));
 
   TCHAR *Buffer = new TCHAR[10];
   _stprintf(Buffer, TEXT("%0.2f"), iValue / 100.0);
@@ -257,5 +256,5 @@ void CStatusControl::UpdateSpeed(int iPos, int iDelta) {
   SendMessage(m_hEdit, WM_SETTEXT, 0, (LPARAM) (LPCSTR) Buffer);
   delete[]Buffer;
 
-  m_pDasherInterface->SetLongParameter(LP_MAX_BITRATE, iValue);
+  m_pAppSettings->SetLongParameter(LP_MAX_BITRATE, iValue);
 }
diff --git a/Src/Win32/Widgets/StatusControl.h b/Src/Win32/Widgets/StatusControl.h
index f4a2f57..14b8456 100644
--- a/Src/Win32/Widgets/StatusControl.h
+++ b/Src/Win32/Widgets/StatusControl.h
@@ -2,7 +2,7 @@
 #define __StatusControl_h__
 
 #include "../Common/WinCommon.h"
-#include "../../DasherCore/DasherInterfaceBase.h"
+#include "../AppSettings.h"
 
 #include <atlbase.h>
 #include <atlwin.h>
@@ -12,7 +12,7 @@ extern CONST UINT DASHER_SHOW_PREFS;
 
 class CStatusControl : public ATL::CWindowImpl<CStatusControl> {
 public:
-	CStatusControl(Dasher::CDasherInterfaceBase *pDasherInterface);
+	CStatusControl(CAppSettings *pAppSettings);
 
   // ATL boilerplate code
   DECLARE_WND_SUPERCLASS(L"STATUSCONTROL", L"STATIC");
@@ -58,7 +58,7 @@ private:
   void UpdateSpeed(int iPos, int iDelta);
 
   // The Dasher interface with which this control communicates
-  Dasher::CDasherInterfaceBase *m_pDasherInterface;
+  CAppSettings *m_pAppSettings;
 
   // Handles to child windows
   HWND m_hEdit;
diff --git a/Src/Win32/Widgets/ViewPage.cpp b/Src/Win32/Widgets/ViewPage.cpp
index dcaecd5..e2ef89a 100644
--- a/Src/Win32/Widgets/ViewPage.cpp
+++ b/Src/Win32/Widgets/ViewPage.cpp
@@ -26,10 +26,10 @@ static char THIS_FILE[] = __FILE__;
 #endif
 #endif
 
-CViewPage::CViewPage(HWND Parent, Dasher::CDasherInterfaceBase *DI, CAppSettings *pAppSettings)
-:CPrefsPageBase(Parent, DI, pAppSettings) {
+CViewPage::CViewPage(HWND Parent, CAppSettings *pAppSettings)
+:CPrefsPageBase(Parent, pAppSettings) {
 
-  m_CurrentColours = DI->GetStringParameter(SP_COLOUR_ID);
+  m_CurrentColours = pAppSettings->GetStringParameter(SP_COLOUR_ID);
 }
 
 struct menuentry {
@@ -69,7 +69,7 @@ void CViewPage::PopulateList() {
 
 
   HWND ListBox = GetDlgItem(m_hwnd, IDC_COLOURS);
-  m_pDasherInterface->GetPermittedValues(SP_COLOUR_ID, ColourList);
+  m_pAppSettings->GetPermittedValues(SP_COLOUR_ID, ColourList);
 
   // Add each string to list box and index each one
   bool SelectionSet = false;
@@ -128,7 +128,7 @@ bool CViewPage::Apply() {
 
 
   if(m_CurrentColours != std::string("")) {
-        m_pDasherInterface->SetStringParameter(SP_COLOUR_ID, m_CurrentColours);
+        m_pAppSettings->SetStringParameter(SP_COLOUR_ID, m_CurrentColours);
   }
 
   m_pAppSettings->SetBoolParameter(BP_PALETTE_CHANGE, 
diff --git a/Src/Win32/Widgets/ViewPage.h b/Src/Win32/Widgets/ViewPage.h
index 3f0a85c..e6c1ad9 100644
--- a/Src/Win32/Widgets/ViewPage.h
+++ b/Src/Win32/Widgets/ViewPage.h
@@ -14,12 +14,12 @@
 #include "../resource.h"
 #include "../AppSettings.h"
 
-#include "../../DasherCore/DasherInterfaceBase.h"
+#include "../Dasher.h"
 #include "../../DasherCore/ColourIO.h"
 
 class CViewPage:public CPrefsPageBase {
 public:
-	CViewPage(HWND Parent, Dasher::CDasherInterfaceBase *DI, CAppSettings *pAppSettings);
+	CViewPage(HWND Parent, CAppSettings *pAppSettings);
   LRESULT WndProc(HWND Window, UINT message, WPARAM wParam, LPARAM lParam);
 
 private:
diff --git a/Src/iPhone/Classes/ActionConfigurator.mm b/Src/iPhone/Classes/ActionConfigurator.mm
index 7c28a6b..5475ef4 100644
--- a/Src/iPhone/Classes/ActionConfigurator.mm
+++ b/Src/iPhone/Classes/ActionConfigurator.mm
@@ -14,6 +14,8 @@
 int CONTROL_MODE_BPS[] = {BP_CONTROL_MODE_HAS_COPY, BP_CONTROL_MODE_HAS_SPEECH, BP_CONTROL_MODE_HAS_HALT, BP_CONTROL_MODE_HAS_EDIT};
 int OTHER_BPS[] = {BP_COPY_ALL_ON_STOP, BP_SPEAK_ALL_ON_STOP, BP_SPEAK_WORDS};
 
+using Dasher::Settings::GetParameterName;
+
 @implementation ActionConfigurator
 
 - (id)initWithButton:(ActionButton *)_button {
@@ -155,7 +157,7 @@ int OTHER_BPS[] = {BP_COPY_ALL_ON_STOP, BP_SPEAK_ALL_ON_STOP, BP_SPEAK_WORDS};
       sw.tag = cell.tag = [indexPath row] + 1;
       sw.on = [[NSUserDefaults standardUserDefaults] boolForKey:act->settingName];      
     } else {
-      CDasherInterfaceBase *intf=[DasherAppDelegate theApp].dasherInterface;
+      CDasherInterfaceBridge *intf=[DasherAppDelegate theApp].dasherInterface;
       int *params;
       if ([indexPath section]==0) {
         params=CONTROL_MODE_BPS;
@@ -166,7 +168,7 @@ int OTHER_BPS[] = {BP_COPY_ALL_ON_STOP, BP_SPEAK_ALL_ON_STOP, BP_SPEAK_WORDS};
       }
       int iParameter = params[[indexPath row]];
       [sw addTarget:self action:@selector(paramSlid:) forControlEvents:UIControlEventValueChanged];
-      cell.textLabel.text = NSStringFromStdString(intf->GetSettingsStore()->GetParameterName(iParameter));
+      cell.textLabel.text = NSStringFromStdString(GetParameterName(iParameter));
       //ensure we don't assign tag 0: 0 is default, so 'viewWithTag:0' could
       // return any subview.
       sw.tag = cell.tag = iParameter + 1;
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.h b/Src/iPhone/Classes/CDasherInterfaceBridge.h
index ec04329..bae704c 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.h
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.h
@@ -45,7 +45,7 @@ public:
   //redefinitions to make public....
   void Realize();//also calls OnUIRealised
   void NewFrame(unsigned long iTime, bool bForceRedraw);
-  
+
   void SetTiltAxes(Vec3 main, float off, Vec3 slow, float off2);
   virtual void WriteTrainFile(const std::string &filename,const std::string &strNewText);
   virtual int GetFileSize(const std::string &strFileName);
@@ -71,7 +71,6 @@ private:
   virtual void SetupPaths();
   virtual void CreateModules();
   virtual void SetupUI();
-  virtual void CreateSettingsStore();
   virtual void StartTimer();
   virtual void ShutdownTimer();
   
@@ -79,7 +78,7 @@ private:
   /// Pass events coming from the core to the appropriate handler.
   ///
   
-  void ExternalEventHandler(Dasher::CEvent *pEvent);
+  void HandleEvent(int iParameter);
   void GameMessageOut(int message, const void* messagedata);
   
   DasherAppDelegate *dasherApp;   // objc counterpart
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.mm b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
index 80a9d6d..fee2e14 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.mm
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
@@ -26,28 +26,28 @@
 
 using namespace std;
 
-CDasherInterfaceBridge::CDasherInterfaceBridge(DasherAppDelegate *aDasherApp) : dasherApp(aDasherApp) {
+CDasherInterfaceBridge::CDasherInterfaceBridge(DasherAppDelegate *aDasherApp) : CDashIntfScreenMsgs(new COSXSettingsStore()), dasherApp(aDasherApp) {
 }
 
 void CDasherInterfaceBridge::CreateModules() {
 	//create the default set...a good idea?!?!
 
-  RegisterModule(m_pUndoubledTouch = new UndoubledTouch(m_pEventHandler, m_pSettingsStore));
+  RegisterModule(m_pUndoubledTouch = new UndoubledTouch());
 	RegisterModule(m_pMouseDevice = 
-				new CIPhoneMouseInput(m_pEventHandler, m_pSettingsStore));
+				new CIPhoneMouseInput(this));
 	RegisterModule(m_pTiltDevice = 
-				new CIPhoneTiltInput(m_pEventHandler, m_pSettingsStore));
+				new CIPhoneTiltInput());
   SetDefaultInputDevice(m_pMouseDevice);
                  
-  RegisterModule(new CButtonMode(m_pEventHandler, m_pSettingsStore, this, true, 9, "Menu Mode"));
-  RegisterModule(new CButtonMode(m_pEventHandler, m_pSettingsStore, this, false, 8, "Direct Mode"));
-  RegisterModule(new CTwoButtonDynamicFilter(m_pEventHandler, m_pSettingsStore, this));
-  RegisterModule(new CTwoPushDynamicFilter(m_pEventHandler, m_pSettingsStore, this));
+  RegisterModule(new CButtonMode(this, this, true, 9, "Menu Mode"));
+  RegisterModule(new CButtonMode(this, this, false, 8, "Direct Mode"));
+  RegisterModule(new CTwoButtonDynamicFilter(this, this));
+  RegisterModule(new CTwoPushDynamicFilter(this, this));
   
 	RegisterModule(m_pTiltFilter =
-				   new CIPhoneTiltFilter(m_pEventHandler, m_pSettingsStore, this, 16, m_pMouseDevice));
+				   new CIPhoneTiltFilter(this, this, 16, m_pMouseDevice));
 	RegisterModule(m_pTouchFilter = 
-				   new CIPhoneTouchFilter(m_pEventHandler, m_pSettingsStore, this, 17, m_pUndoubledTouch, m_pTiltDevice));
+				   new CIPhoneTouchFilter(this, this, 17, m_pUndoubledTouch, m_pTiltDevice));
 	SetDefaultInputMethod(m_pTouchFilter);
 }
 	
@@ -69,7 +69,7 @@ void CDasherInterfaceBridge::SetupUI() {
 
 void CDasherInterfaceBridge::Realize() {  
   CDasherInterfaceBase::Realize();
-  ExternalEventHandler(&CParameterNotificationEvent(SP_ALPHABET_ID)); //calls dasherApp::SetAlphabet
+  HandleEvent(SP_ALPHABET_ID); //calls dasherApp::SetAlphabet
   CDasherInterfaceBase::OnUIRealised();
 }
 
@@ -77,12 +77,8 @@ void CDasherInterfaceBridge::SetupPaths() {
   NSString *systemDir = [NSString stringWithFormat:@"%@/", [[NSBundle mainBundle] bundlePath]];
   NSString *userDir = [NSString stringWithFormat:@"%@/", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]];
 
-  m_pSettingsStore->SetStringParameter(SP_SYSTEM_LOC, StdStringFromNSString(systemDir));
-  m_pSettingsStore->SetStringParameter(SP_USER_LOC, StdStringFromNSString(userDir));
-}
-
-void CDasherInterfaceBridge::CreateSettingsStore() {
-  m_pSettingsStore = new COSXSettingsStore(m_pEventHandler);
+  SetStringParameter(SP_SYSTEM_LOC, StdStringFromNSString(systemDir));
+  SetStringParameter(SP_USER_LOC, StdStringFromNSString(userDir));
 }
 
 void CDasherInterfaceBridge::ScanAlphabetFiles(std::vector<std::string> &vFileList) {
@@ -141,30 +137,17 @@ void CDasherInterfaceBridge::GameMessageOut(int message, const void* messagedata
   NSLog(@"GameMessageOut");
 }
 
-void CDasherInterfaceBridge::ExternalEventHandler(Dasher::CEvent *pEvent) {
+void CDasherInterfaceBridge::HandleEvent(int iParameter) {
   
-  switch (pEvent->m_iEventType) {
-    case EV_PARAM_NOTIFY:
-      // don't need to do anything because the PreferencesController is observing changes to the 
-      // user defaults controller which is observing the user defaults and will be notified when
-      // the parameter is actually written by COSXSettingsStore.
-//      CParameterNotificationEvent *parameterEvent(static_cast < CParameterNotificationEvent * >(pEvent));
-//      NSLog(@"CParameterNotificationEvent, m_iParameter: %d", parameterEvent->m_iParameter);
-	  {
-		Dasher::CParameterNotificationEvent *pEvt(static_cast<Dasher::CParameterNotificationEvent *>(pEvent));
-		if (pEvt->m_iParameter == LP_MAX_BITRATE || pEvt->m_iParameter == LP_BOOSTFACTOR)
-			[dasherApp notifySpeedChange];
-    else if (pEvt->m_iParameter == SP_ALPHABET_ID)
-      [dasherApp setAlphabet:GetActiveAlphabet()];
-    }
-      break;
-   case EV_SCREEN_GEOM:
-     //no need to do anything
-     break;
-   default:
-     NSLog(@"ExternalEventHandler, UNKNOWN m_iEventType = %d", pEvent->m_iEventType);
-     break;
-   }
+  // don't need to do anything because the PreferencesController is observing changes to the 
+  // user defaults controller which is observing the user defaults and will be notified when
+  // the parameter is actually written by COSXSettingsStore.
+  //NSLog(@"CParameterNotificationEvent, m_iParameter: %d", parameterEvent->m_iParameter);
+  if (iParameter == LP_MAX_BITRATE || iParameter == LP_BOOSTFACTOR)
+    [dasherApp notifySpeedChange];
+  else if (iParameter == SP_ALPHABET_ID)
+    [dasherApp setAlphabet:GetActiveAlphabet()];
+  CDasherInterfaceBase::HandleEvent(iParameter);
 }
 
 void CDasherInterfaceBridge::editOutput(const string &strText, CDasherNode *pNode) {
diff --git a/Src/iPhone/Classes/COSXSettingsStore.h b/Src/iPhone/Classes/COSXSettingsStore.h
index e1c1d07..24467fb 100644
--- a/Src/iPhone/Classes/COSXSettingsStore.h
+++ b/Src/iPhone/Classes/COSXSettingsStore.h
@@ -17,9 +17,9 @@
 @class PreferencesController;
 @class NSDictionary;
 
-class COSXSettingsStore:public CSettingsStore {
+class COSXSettingsStore:public Dasher::CSettingsStore {
 public:
-  COSXSettingsStore(Dasher::CEventHandler * pEventHandler);
+  COSXSettingsStore();
   ~COSXSettingsStore();
   std::string GetParamName(int iParameter);
 
diff --git a/Src/iPhone/Classes/COSXSettingsStore.mm b/Src/iPhone/Classes/COSXSettingsStore.mm
index 4550b58..9c5e831 100644
--- a/Src/iPhone/Classes/COSXSettingsStore.mm
+++ b/Src/iPhone/Classes/COSXSettingsStore.mm
@@ -12,7 +12,7 @@
 #import <iostream>
 #import "DasherUtil.h"
 
-COSXSettingsStore::COSXSettingsStore(Dasher::CEventHandler *pEventHandler):CSettingsStore(pEventHandler) {
+COSXSettingsStore::COSXSettingsStore() {
   LoadPersistent();
 };
 
diff --git a/Src/iPhone/Classes/IPhoneFilters.h b/Src/iPhone/Classes/IPhoneFilters.h
index 855773e..36e2366 100644
--- a/Src/iPhone/Classes/IPhoneFilters.h
+++ b/Src/iPhone/Classes/IPhoneFilters.h
@@ -35,14 +35,14 @@ extern NSString *TOUCH_USE_TILT_X;
 #define TOUCH_FILTER "IPhone Touch Filter"
 class CIPhoneTiltFilter : public COneDimensionalFilter, private IPhonePrefsObserver {
 public:
-	CIPhoneTiltFilter(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, CDasherInput *pTouch);
+	CIPhoneTiltFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, CDasherInput *pTouch);
   ///override to enable hold-to-go
 	virtual void KeyDown(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel, CUserLogBase *pUserLog);
   ///override to enable hold-to-go
 	virtual void KeyUp(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel);
 
   ///respond to BP_DASHER_PAUSED by engaging wakelock (if !hold-to-go)
-  virtual void HandleEvent(CEvent *pEvent);
+  virtual void HandleEvent(int iParameter);
   void iPhonePrefsChanged(NSString *key);
   bool supportsPause();
 protected:
@@ -59,7 +59,7 @@ private:
 
 class CIPhoneTouchFilter : public CStylusFilter, private IPhonePrefsObserver {
 public:
-	CIPhoneTouchFilter(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, UndoubledTouch *pUndoubledTouch, CIPhoneTiltInput *pTilt);
+	CIPhoneTouchFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, UndoubledTouch *pUndoubledTouch, CIPhoneTiltInput *pTilt);
 	
 	virtual void KeyUp(int iTime, int iId, CDasherView *pView, CDasherInput *pInput, CDasherModel *pModel);
   
diff --git a/Src/iPhone/Classes/IPhoneFilters.mm b/Src/iPhone/Classes/IPhoneFilters.mm
index 3713bc6..3f3a6dd 100644
--- a/Src/iPhone/Classes/IPhoneFilters.mm
+++ b/Src/iPhone/Classes/IPhoneFilters.mm
@@ -64,8 +64,8 @@ IPhonePrefsObserver::~IPhonePrefsObserver() {
   [obsvr release];
 }
 
-CIPhoneTiltFilter::CIPhoneTiltFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, CDasherInput *pTouch)
-: COneDimensionalFilter(pEventHandler, pSettingsStore, pInterface, iID, TILT_FILTER), m_pTouch(pTouch) {
+CIPhoneTiltFilter::CIPhoneTiltFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, CDasherInput *pTouch)
+: COneDimensionalFilter(pCreator, pInterface, iID, TILT_FILTER), m_pTouch(pTouch) {
   ObserveKeys(HOLD_TO_GO, TILT_USE_TOUCH_X, TILT_1D, @"CircleStart", nil);
 };
 			
@@ -102,12 +102,12 @@ void CIPhoneTiltFilter::ApplyOffset(myint &iDasherX, myint &iDasherY) {
   //Do not apply LP_TARGET_OFFSET, or BP_AUTO_CALIBRATE
 }
 
-void CIPhoneTiltFilter::HandleEvent(CEvent *pEvent) {
-  if (pEvent->m_iEventType == EV_PARAM_NOTIFY
-      && static_cast<CParameterNotificationEvent *>(pEvent)->m_iParameter==BP_DASHER_PAUSED
+void CIPhoneTiltFilter::HandleEvent(int iParameter) {
+  if (iParameter==BP_DASHER_PAUSED
       && m_pInterface->GetActiveInputMethod()==this) {
     [UIApplication sharedApplication].idleTimerDisabled=(!GetBoolParameter(BP_DASHER_PAUSED) && !bHoldToGo);
   }
+  COneDimensionalFilter::HandleEvent(iParameter);
 }
 
 void CIPhoneTiltFilter::iPhonePrefsChanged(NSString *key) {
@@ -132,8 +132,8 @@ CStartHandler *CIPhoneTiltFilter::MakeStartHandler() {
   return CDefaultFilter::MakeStartHandler();
 }
 
-CIPhoneTouchFilter::CIPhoneTouchFilter(Dasher::CEventHandler * pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, UndoubledTouch *pUndoubledTouch, CIPhoneTiltInput *pTilt)
-: CStylusFilter(pEventHandler, pSettingsStore, pInterface, iID, TOUCH_FILTER), m_pUndoubledTouch(pUndoubledTouch), m_pTilt(pTilt) {
+CIPhoneTouchFilter::CIPhoneTouchFilter(CSettingsUser *pCreator, CDasherInterfaceBase *pInterface, ModuleID_t iID, UndoubledTouch *pUndoubledTouch, CIPhoneTiltInput *pTilt)
+: CStylusFilter(pCreator, pInterface, iID, TOUCH_FILTER), m_pUndoubledTouch(pUndoubledTouch), m_pTilt(pTilt) {
   ObserveKeys(TOUCH_USE_TILT_X,nil);
   
 };
diff --git a/Src/iPhone/Classes/IPhoneInputs.h b/Src/iPhone/Classes/IPhoneInputs.h
index e1093af..178dd99 100644
--- a/Src/iPhone/Classes/IPhoneInputs.h
+++ b/Src/iPhone/Classes/IPhoneInputs.h
@@ -9,7 +9,7 @@
 
 #import "../DasherCore/DasherInput.h"
 #import "../DasherCore/DasherTypes.h"
-
+#import "../DasherCore/SettingsStore.h"
 #import "SBTree.h"
 #import <deque>
 #import "Vec3.h"
@@ -22,7 +22,7 @@ namespace Dasher {
 
 class CIPhoneTiltInput : public CScreenCoordInput {
 public:
-	CIPhoneTiltInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore); 
+	CIPhoneTiltInput(); 
 	~CIPhoneTiltInput();
 	
 	void NotifyTilt(float fx, float fy, float fz);
@@ -51,15 +51,15 @@ private:
 
 class UndoubledTouch : public CScreenCoordInput {
 public:
-  UndoubledTouch(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore);
+  UndoubledTouch();
   bool GetScreenCoords(screenint &iX, screenint &iY, CDasherView *pView);
 protected:
-  UndoubledTouch(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, ModuleID_t iId, const char *szName);
+  UndoubledTouch(ModuleID_t iId, const char *szName);
 };
 
-class CIPhoneMouseInput : public UndoubledTouch {
+class CIPhoneMouseInput : public UndoubledTouch, protected CSettingsUser {
 public:
-	CIPhoneMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore);
+	CIPhoneMouseInput(CSettingsUser *pCreator);
   
   bool GetScreenCoords(screenint &iX, screenint &iY, CDasherView *pView);
 };
diff --git a/Src/iPhone/Classes/IPhoneInputs.mm b/Src/iPhone/Classes/IPhoneInputs.mm
index a0aa967..4458a39 100644
--- a/Src/iPhone/Classes/IPhoneInputs.mm
+++ b/Src/iPhone/Classes/IPhoneInputs.mm
@@ -35,8 +35,8 @@ using namespace Dasher;
 }
 @end
 
-CIPhoneTiltInput::CIPhoneTiltInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore) 
-	: CScreenCoordInput(pEventHandler, pSettingsStore, 8, TILT_INPUT) {
+CIPhoneTiltInput::CIPhoneTiltInput() 
+	: CScreenCoordInput(8, TILT_INPUT) {
 	deleg = [[Accel alloc] initWithInput:this];	
 	xTilts = NULL;
 };
@@ -100,10 +100,10 @@ bool CIPhoneTiltInput::GetScreenCoords(screenint &iX, screenint &iY, CDasherView
   return true;
 }
 
-UndoubledTouch::UndoubledTouch(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore) : CScreenCoordInput(pEventHandler, pSettingsStore, 7, UNDOUBLED_TOUCH) {
+UndoubledTouch::UndoubledTouch() : CScreenCoordInput(7, UNDOUBLED_TOUCH) {
 }
 
-UndoubledTouch::UndoubledTouch(CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, ModuleID_t iId, const char *szName) : CScreenCoordInput(pEventHandler, pSettingsStore, iId, szName) {
+UndoubledTouch::UndoubledTouch(ModuleID_t iId, const char *szName) : CScreenCoordInput(iId, szName) {
 }
 
 bool UndoubledTouch::GetScreenCoords(screenint &iX, screenint &iY, CDasherView *pView) {
@@ -112,8 +112,8 @@ bool UndoubledTouch::GetScreenCoords(screenint &iX, screenint &iY, CDasherView *
 }
 
 
-CIPhoneMouseInput::CIPhoneMouseInput(CEventHandler * pEventHandler, CSettingsStore * pSettingsStore) 
-	: UndoubledTouch(pEventHandler, pSettingsStore, 9, TOUCH_INPUT) {
+CIPhoneMouseInput::CIPhoneMouseInput(CSettingsUser *pCreator) 
+	: UndoubledTouch(9, TOUCH_INPUT), CSettingsUser(pCreator) {
 };
 
 bool CIPhoneMouseInput::GetScreenCoords(screenint &iX, screenint &iY, CDasherView *pView) {
diff --git a/Src/iPhone/Classes/InputMethodSelector.mm b/Src/iPhone/Classes/InputMethodSelector.mm
index efccfb6..b1c3663 100644
--- a/Src/iPhone/Classes/InputMethodSelector.mm
+++ b/Src/iPhone/Classes/InputMethodSelector.mm
@@ -166,7 +166,7 @@ int numSections = sizeof(allMeths) / sizeof(allMeths[0]);
 	
 	// Set up the cell...
   cell.textLabel.text = filter->title;
-	CDasherInterfaceBase *intf = [DasherAppDelegate theApp].dasherInterface;
+	CDasherInterfaceBridge *intf = [DasherAppDelegate theApp].dasherInterface;
   if (filter->deviceName == intf->GetStringParameter(SP_INPUT_DEVICE)
       && filter->filterName == intf->GetStringParameter(SP_INPUT_FILTER)) {
     //filter is currently selected...
@@ -218,7 +218,7 @@ int numSections = sizeof(allMeths) / sizeof(allMeths[0]);
 
   //and record it as selected...
 	self->selectedPath = indexPath;
-	CDasherInterfaceBase *intf = [DasherAppDelegate theApp].dasherInterface;
+	CDasherInterfaceBridge *intf = [DasherAppDelegate theApp].dasherInterface;
 	SFilterDesc *filter = &allMeths[ [indexPath section] ].filters[ [indexPath row] ];
 	intf->SetStringParameter(SP_INPUT_DEVICE, filter->deviceName);
 	intf->SetStringParameter(SP_INPUT_FILTER, filter->filterName);
diff --git a/Src/iPhone/Classes/ParametersController.mm b/Src/iPhone/Classes/ParametersController.mm
index 8c4ba4c..3f399be 100644
--- a/Src/iPhone/Classes/ParametersController.mm
+++ b/Src/iPhone/Classes/ParametersController.mm
@@ -11,6 +11,7 @@
 #import "DasherUtil.h"
 
 using namespace Dasher;
+using Dasher::Settings::GetParameterName;
 
 //private methods
 @interface ParametersController ()
@@ -54,7 +55,7 @@ using namespace Dasher;
   CDasherInterfaceBridge *intf = [DasherAppDelegate theApp].dasherInterface;
   for (int i=0; i<count; i++) {
     if (settings[i].iType == T_BOOL) {
-      UISwitch *sw=[self makeSwitch:NSStringFromStdString(intf->GetSettingsStore()->GetParameterName(settings[i].iParameter)) onView:view atY:&y];
+      UISwitch *sw=[self makeSwitch:NSStringFromStdString(GetParameterName(settings[i].iParameter)) onView:view atY:&y];
       sw.tag = settings[i].iParameter;
       sw.on = intf->GetBoolParameter(settings[i].iParameter);
       [sw addTarget:self action:@selector(boolParamChanged:) forControlEvents:UIControlEventValueChanged];
@@ -109,7 +110,7 @@ using namespace Dasher;
       iDivisor/=10;
     }
     NSString *format =[@"%@: %." stringByAppendingFormat:@"%df",iPlaces];  
-    label.text = [NSString stringWithFormat:format,NSStringFromStdString(intf->GetSettingsStore()->GetParameterName(setting->iParameter)),(val / (float)setting->iDivisor)];
+    label.text = [NSString stringWithFormat:format,NSStringFromStdString(GetParameterName(setting->iParameter)),(val / (float)setting->iDivisor)];
   }
 }
 
diff --git a/Src/iPhone/Dasher.xcodeproj/project.pbxproj b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
index 40a85a1..868656f 100755
--- a/Src/iPhone/Dasher.xcodeproj/project.pbxproj
+++ b/Src/iPhone/Dasher.xcodeproj/project.pbxproj
@@ -87,6 +87,8 @@
 		3334D996101627140077948A /* alphabet.bengali.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3334D995101627130077948A /* alphabet.bengali.xml */; };
 		3334D99A101627A00077948A /* alphabet.hungarian.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3334D999101627A00077948A /* alphabet.hungarian.xml */; };
 		3334D99C101627DE0077948A /* alphabet.mongolian.xml in Resources */ = {isa = PBXBuildFile; fileRef = 3334D99B101627DE0077948A /* alphabet.mongolian.xml */; };
+		3335F61B13AB5144004F9371 /* DashIntfSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3335F61913AB5144004F9371 /* DashIntfSettings.cpp */; };
+		3335F63813AB7D95004F9371 /* Parameters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3335F63713AB7D95004F9371 /* Parameters.cpp */; };
 		3336B8FB0F74005B0063CBF4 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3336B8FA0F74005B0063CBF4 /* CoreGraphics.framework */; };
 		333B5D4F100F5A93002041C8 /* TextView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 333B5D4E100F5A93002041C8 /* TextView.mm */; };
 		333F6F4C11A8A6EF002E2BDF /* FliteTTS.m in Sources */ = {isa = PBXBuildFile; fileRef = 333F6F4B11A8A6EF002E2BDF /* FliteTTS.m */; };
@@ -177,7 +179,6 @@
 		3344FE240F71717C00506EAA /* ConversionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FD880F71717C00506EAA /* ConversionManager.cpp */; };
 		3344FE260F71717C00506EAA /* CustomColours.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FD8C0F71717C00506EAA /* CustomColours.cpp */; };
 		3344FE270F71717C00506EAA /* DasherButtons.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FD8E0F71717C00506EAA /* DasherButtons.cpp */; };
-		3344FE280F71717C00506EAA /* DasherComponent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FD900F71717C00506EAA /* DasherComponent.cpp */; };
 		3344FE300F71717C00506EAA /* DasherGameMode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FD990F71717C00506EAA /* DasherGameMode.cpp */; };
 		3344FE310F71717C00506EAA /* DasherInterfaceBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FD9C0F71717C00506EAA /* DasherInterfaceBase.cpp */; };
 		3344FE320F71717C00506EAA /* DasherModel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FD9E0F71717C00506EAA /* DasherModel.cpp */; };
@@ -188,7 +189,6 @@
 		3344FE380F71717C00506EAA /* DasherViewSquare.inl in Resources */ = {isa = PBXBuildFile; fileRef = 3344FDAB0F71717C00506EAA /* DasherViewSquare.inl */; };
 		3344FE390F71717C00506EAA /* DefaultFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDAC0F71717C00506EAA /* DefaultFilter.cpp */; };
 		3344FE3B0F71717C00506EAA /* DynamicFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDAF0F71717C00506EAA /* DynamicFilter.cpp */; };
-		3344FE3C0F71717C00506EAA /* EventHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDB20F71717C00506EAA /* EventHandler.cpp */; };
 		3344FE3E0F71717C00506EAA /* FileLogger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDB60F71717C00506EAA /* FileLogger.cpp */; };
 		3344FE3F0F71717C00506EAA /* GameLevel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDB90F71717C00506EAA /* GameLevel.cpp */; };
 		3344FE400F71717C00506EAA /* GameScorer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3344FDBC0F71717C00506EAA /* GameScorer.cpp */; };
@@ -398,6 +398,9 @@
 		3334D995101627130077948A /* alphabet.bengali.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = alphabet.bengali.xml; sourceTree = "<group>"; };
 		3334D999101627A00077948A /* alphabet.hungarian.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = alphabet.hungarian.xml; sourceTree = "<group>"; };
 		3334D99B101627DE0077948A /* alphabet.mongolian.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = alphabet.mongolian.xml; sourceTree = "<group>"; };
+		3335F61913AB5144004F9371 /* DashIntfSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DashIntfSettings.cpp; sourceTree = "<group>"; };
+		3335F61A13AB5144004F9371 /* DashIntfSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DashIntfSettings.h; sourceTree = "<group>"; };
+		3335F63713AB7D95004F9371 /* Parameters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Parameters.cpp; sourceTree = "<group>"; };
 		3336B8FA0F74005B0063CBF4 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
 		333B5D4D100F5A93002041C8 /* TextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextView.h; sourceTree = "<group>"; };
 		333B5D4E100F5A93002041C8 /* TextView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TextView.mm; sourceTree = "<group>"; };
@@ -564,8 +567,6 @@
 		3344FD8D0F71717C00506EAA /* CustomColours.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomColours.h; sourceTree = "<group>"; };
 		3344FD8E0F71717C00506EAA /* DasherButtons.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DasherButtons.cpp; sourceTree = "<group>"; };
 		3344FD8F0F71717C00506EAA /* DasherButtons.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherButtons.h; sourceTree = "<group>"; };
-		3344FD900F71717C00506EAA /* DasherComponent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DasherComponent.cpp; sourceTree = "<group>"; };
-		3344FD910F71717C00506EAA /* DasherComponent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherComponent.h; sourceTree = "<group>"; };
 		3344FD990F71717C00506EAA /* DasherGameMode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DasherGameMode.cpp; sourceTree = "<group>"; };
 		3344FD9A0F71717C00506EAA /* DasherGameMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherGameMode.h; sourceTree = "<group>"; };
 		3344FD9B0F71717C00506EAA /* DasherInput.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DasherInput.h; sourceTree = "<group>"; };
@@ -589,8 +590,6 @@
 		3344FDAF0F71717C00506EAA /* DynamicFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DynamicFilter.cpp; sourceTree = "<group>"; };
 		3344FDB00F71717C00506EAA /* DynamicFilter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DynamicFilter.h; sourceTree = "<group>"; };
 		3344FDB10F71717C00506EAA /* Event.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Event.h; sourceTree = "<group>"; };
-		3344FDB20F71717C00506EAA /* EventHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventHandler.cpp; sourceTree = "<group>"; };
-		3344FDB30F71717C00506EAA /* EventHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventHandler.h; sourceTree = "<group>"; };
 		3344FDB60F71717C00506EAA /* FileLogger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileLogger.cpp; sourceTree = "<group>"; };
 		3344FDB70F71717C00506EAA /* FileLogger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FileLogger.h; sourceTree = "<group>"; };
 		3344FDB80F71717C00506EAA /* FrameRate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrameRate.h; sourceTree = "<group>"; };
@@ -689,6 +688,7 @@
 		33627FB60F7A82CF000C8818 /* training_swedish_SE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = training_swedish_SE.txt; sourceTree = "<group>"; };
 		33627FB70F7A82CF000C8818 /* training_turkish_TR.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = training_turkish_TR.txt; sourceTree = "<group>"; };
 		33627FB80F7A82CF000C8818 /* training_welsh_GB.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = training_welsh_GB.txt; sourceTree = "<group>"; };
+		3370525D13ABBF8900821A25 /* Observable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Observable.h; sourceTree = "<group>"; };
 		337472D1121A9767001A858C /* AlphInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AlphInfo.cpp; sourceTree = "<group>"; };
 		337472D2121A976B001A858C /* AlphInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AlphInfo.h; sourceTree = "<group>"; };
 		337690120F989C870083FEB2 /* SBTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBTree.h; sourceTree = "<group>"; };
@@ -1196,8 +1196,6 @@
 				3344FD8D0F71717C00506EAA /* CustomColours.h */,
 				3344FD8E0F71717C00506EAA /* DasherButtons.cpp */,
 				3344FD8F0F71717C00506EAA /* DasherButtons.h */,
-				3344FD900F71717C00506EAA /* DasherComponent.cpp */,
-				3344FD910F71717C00506EAA /* DasherComponent.h */,
 				3344FD990F71717C00506EAA /* DasherGameMode.cpp */,
 				3344FD9A0F71717C00506EAA /* DasherGameMode.h */,
 				3344FD9B0F71717C00506EAA /* DasherInput.h */,
@@ -1205,6 +1203,8 @@
 				3344FD9D0F71717C00506EAA /* DasherInterfaceBase.h */,
 				33B3430613A8A927009AE0D5 /* DashIntfScreenMsgs.cpp */,
 				33B3430713A8A927009AE0D5 /* DashIntfScreenMsgs.h */,
+				3335F61913AB5144004F9371 /* DashIntfSettings.cpp */,
+				3335F61A13AB5144004F9371 /* DashIntfSettings.h */,
 				3344FD9E0F71717C00506EAA /* DasherModel.cpp */,
 				3344FD9F0F71717C00506EAA /* DasherModel.h */,
 				3344FDA00F71717C00506EAA /* DasherModule.cpp */,
@@ -1223,8 +1223,6 @@
 				3344FDAF0F71717C00506EAA /* DynamicFilter.cpp */,
 				3344FDB00F71717C00506EAA /* DynamicFilter.h */,
 				3344FDB10F71717C00506EAA /* Event.h */,
-				3344FDB20F71717C00506EAA /* EventHandler.cpp */,
-				3344FDB30F71717C00506EAA /* EventHandler.h */,
 				3344FDB60F71717C00506EAA /* FileLogger.cpp */,
 				3344FDB70F71717C00506EAA /* FileLogger.h */,
 				3344FDB80F71717C00506EAA /* FrameRate.h */,
@@ -1243,6 +1241,7 @@
 				3344FDE10F71717C00506EAA /* ModuleManager.h */,
 				3344FDE20F71717C00506EAA /* NodeCreationManager.cpp */,
 				3344FDE30F71717C00506EAA /* NodeCreationManager.h */,
+				3370525D13ABBF8900821A25 /* Observable.h */,
 				3344FDE60F71717C00506EAA /* OneButtonDynamicFilter.cpp */,
 				3344FDE70F71717C00506EAA /* OneButtonDynamicFilter.h */,
 				3344FDE80F71717C00506EAA /* OneButtonFilter.cpp */,
@@ -1250,6 +1249,7 @@
 				3344FDEA0F71717C00506EAA /* OneDimensionalFilter.cpp */,
 				3344FDEB0F71717C00506EAA /* OneDimensionalFilter.h */,
 				3344FDEC0F71717C00506EAA /* Parameters.h */,
+				3335F63713AB7D95004F9371 /* Parameters.cpp */,
 				332F32A6103C8A1E008448D7 /* AlternatingDirectMode.cpp */,
 				332F32A7103C8A1E008448D7 /* AlternatingDirectMode.h */,
 				332F32A8103C8A1E008448D7 /* ButtonMode.cpp */,
@@ -1583,7 +1583,6 @@
 				3344FE240F71717C00506EAA /* ConversionManager.cpp in Sources */,
 				3344FE260F71717C00506EAA /* CustomColours.cpp in Sources */,
 				3344FE270F71717C00506EAA /* DasherButtons.cpp in Sources */,
-				3344FE280F71717C00506EAA /* DasherComponent.cpp in Sources */,
 				3344FE300F71717C00506EAA /* DasherGameMode.cpp in Sources */,
 				3344FE310F71717C00506EAA /* DasherInterfaceBase.cpp in Sources */,
 				3344FE320F71717C00506EAA /* DasherModel.cpp in Sources */,
@@ -1593,7 +1592,6 @@
 				3344FE370F71717C00506EAA /* DasherViewSquare.cpp in Sources */,
 				3344FE390F71717C00506EAA /* DefaultFilter.cpp in Sources */,
 				3344FE3B0F71717C00506EAA /* DynamicFilter.cpp in Sources */,
-				3344FE3C0F71717C00506EAA /* EventHandler.cpp in Sources */,
 				3344FE3E0F71717C00506EAA /* FileLogger.cpp in Sources */,
 				3344FE3F0F71717C00506EAA /* GameLevel.cpp in Sources */,
 				3344FE400F71717C00506EAA /* GameScorer.cpp in Sources */,
@@ -1725,6 +1723,8 @@
 				333FDB5A139FB413009D018A /* ConvertingAlphMgr.cpp in Sources */,
 				33B3430813A8A927009AE0D5 /* DashIntfScreenMsgs.cpp in Sources */,
 				33FDB7F5135F310E00D6C952 /* UserLogBase.cpp in Sources */,
+				3335F61B13AB5144004F9371 /* DashIntfSettings.cpp in Sources */,
+				3335F63813AB7D95004F9371 /* Parameters.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]