[dasher: 19/28] Refactor Game Mode startup to allow changing settings; RM BP_GAME_MODE



commit 57f734d6916f0e0236327bf1c1d388e44a7655b1
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Tue Sep 27 11:04:52 2011 +0100

    Refactor Game Mode startup to allow changing settings; RM BP_GAME_MODE
    
    Add EnterGameMode and LeaveGameMode methods; drop params from CreateGameModule
    GetGameModule()!=NULL is now official way to tell whether in GameMode or not
    
    Note that no platform-specific subclass does actually present gamemode settings
     to the user, in the manner specified, yet; this remains a TODO.
    
    also hide CDasherInterfaceBase::m_DasherScreen (call GetView()->Screen())

 Src/DasherCore/DashIntfScreenMsgs.cpp        |   21 +++++-----
 Src/DasherCore/DashIntfScreenMsgs.h          |    2 +-
 Src/DasherCore/DasherInterfaceBase.cpp       |   54 ++++++++++++++-----------
 Src/DasherCore/DasherInterfaceBase.h         |   41 +++++++++++++++----
 Src/DasherCore/DemoFilter.cpp                |    4 +-
 Src/DasherCore/GameModule.cpp                |    5 +-
 Src/DasherCore/NodeCreationManager.cpp       |   34 ++++++++---------
 Src/DasherCore/NodeCreationManager.h         |    6 ++-
 Src/DasherCore/Parameters.cpp                |    1 -
 Src/DasherCore/Parameters.h                  |    2 +-
 Src/Gtk2/DasherControl.cpp                   |   10 ++--
 Src/Gtk2/DasherControl.h                     |    2 +-
 Src/Gtk2/GtkDasherControl.cpp                |   13 ++++++
 Src/Gtk2/GtkDasherControl.h                  |    5 ++-
 Src/Gtk2/dasher_editor.cpp                   |    6 +--
 Src/Gtk2/dasher_editor.h                     |    8 ++--
 Src/Gtk2/dasher_editor_internal.cpp          |   11 +++--
 Src/Gtk2/dasher_main.cpp                     |   15 +++----
 Src/MacOSX/COSXDasherControl.h               |    5 +-
 Src/MacOSX/COSXDasherControl.mm              |   16 +++++---
 Src/MacOSX/DasherApp.mm                      |   10 +++-
 Src/iPhone/Classes/CDasherInterfaceBridge.h  |    8 ++-
 Src/iPhone/Classes/CDasherInterfaceBridge.mm |   16 ++++++--
 Src/iPhone/Classes/DasherAppDelegate.mm      |   10 +++--
 24 files changed, 185 insertions(+), 120 deletions(-)
---
diff --git a/Src/DasherCore/DashIntfScreenMsgs.cpp b/Src/DasherCore/DashIntfScreenMsgs.cpp
index 4925cba..c5a5482 100644
--- a/Src/DasherCore/DashIntfScreenMsgs.cpp
+++ b/Src/DasherCore/DashIntfScreenMsgs.cpp
@@ -9,7 +9,7 @@ CDashIntfScreenMsgs::CDashIntfScreenMsgs(CSettingsStore *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));
+  CDasherScreen::Label *lab = GetView()->Screen()->MakeLabel(strText,GetLongParameter(LP_MESSAGE_FONTSIZE));
   if (bInterrupt) {
     m_dqModalMessages.push_back(pair<CDasherScreen::Label*,bool>(lab,false));
     if (CInputFilter *fil=GetActiveInputMethod()) fil->pause();
@@ -27,9 +27,10 @@ bool CDashIntfScreenMsgs::FinishRender(unsigned long ulTime) {
     m_dqAsyncMessages.pop_front(); // => stop displaying it
     bMsgsChanged=true;
   }
+  CDasherScreen * const pScreen(GetView()->Screen());
   if (!m_dqAsyncMessages.empty() || !m_dqModalMessages.empty()) {
-    screenint iY = m_DasherScreen->GetHeight();
-    const screenint iMinY((iY*3)/4), iSW(m_DasherScreen->GetWidth());
+    screenint iY = pScreen->GetHeight();
+    const screenint iMinY((iY*3)/4), iSW(pScreen->GetWidth());
     //still messages to display...first find out longest-ago N that will fit
     for (deque<pair<CDasherScreen::Label*, unsigned long> >::iterator it = m_dqAsyncMessages.begin(); it!=m_dqAsyncMessages.end() && iY>iMinY; it++) {
       if (it->second==0) {
@@ -38,7 +39,7 @@ bool CDashIntfScreenMsgs::FinishRender(unsigned long ulTime) {
         it->second = ulTime; //display message for first time
         bMsgsChanged=true;
       } 
-      iY-=m_DasherScreen->TextSize(it->first, GetLongParameter(LP_MESSAGE_FONTSIZE)).second;
+      iY-=pScreen->TextSize(it->first, GetLongParameter(LP_MESSAGE_FONTSIZE)).second;
     }
     if (!m_dqModalMessages.empty()) {
       bool bDisp(m_dqModalMessages.front().second != 0); //displaying anything atm?
@@ -50,7 +51,7 @@ bool CDashIntfScreenMsgs::FinishRender(unsigned long ulTime) {
           it->second = ulTime;
           bMsgsChanged = true;
         }
-        iY-=m_DasherScreen->TextSize(it->first, GetLongParameter(LP_MESSAGE_FONTSIZE)).second;
+        iY-=pScreen->TextSize(it->first, GetLongParameter(LP_MESSAGE_FONTSIZE)).second;
       }
     }
     //Now render messages proceeding downwards - non-modal first, then oldest first
@@ -59,11 +60,11 @@ bool CDashIntfScreenMsgs::FinishRender(unsigned long ulTime) {
       if (it==m_dqAsyncMessages.end()) {it=m_dqModalMessages.begin(); bModal=true;}
       if (it==m_dqModalMessages.end()) break;
       if (it->second==0) continue;
-      pair<screenint,screenint> textDims = m_DasherScreen->TextSize(it->first, GetLongParameter(LP_MESSAGE_FONTSIZE));
+      pair<screenint,screenint> textDims = pScreen->TextSize(it->first, GetLongParameter(LP_MESSAGE_FONTSIZE));
       //black (5) rectangle:
-      m_DasherScreen->DrawRectangle((iSW - textDims.first)/2, iY, (iSW+textDims.first)/2, iY+textDims.second, 5, -1, -1);
+      pScreen->DrawRectangle((iSW - textDims.first)/2, iY, (iSW+textDims.first)/2, iY+textDims.second, 5, -1, -1);
       //white (0) text for non-modal, yellow (111) for modal
-      m_DasherScreen->DrawString(it->first, (iSW-textDims.first)/2, iY, GetLongParameter(LP_MESSAGE_FONTSIZE), bModal ? 111 : 0);
+      pScreen->DrawString(it->first, (iSW-textDims.first)/2, iY, GetLongParameter(LP_MESSAGE_FONTSIZE), bModal ? 111 : 0);
       iY+=textDims.second;
     }
   }
@@ -98,6 +99,6 @@ void CDashIntfScreenMsgs::onUnpause(unsigned long lTime) {
   CDasherInterfaceBase::onUnpause(lTime);
 }
 
-CGameModule *CDashIntfScreenMsgs::CreateGameModule(CDasherView *pView, CDasherModel *pModel) {
-  return new CScreenGameModule(this, this, pView, pModel);
+CGameModule *CDashIntfScreenMsgs::CreateGameModule() {
+  return new CScreenGameModule(this, this, GetView(), m_pDasherModel);
 }
diff --git a/Src/DasherCore/DashIntfScreenMsgs.h b/Src/DasherCore/DashIntfScreenMsgs.h
index a589e25..9f2c013 100644
--- a/Src/DasherCore/DashIntfScreenMsgs.h
+++ b/Src/DasherCore/DashIntfScreenMsgs.h
@@ -60,7 +60,7 @@ public:
   
   ///Implement to return a ScreenGameModule, i.e. rendering text prompts
   /// onto the Screen with Labels, much as we do for messages!
-  CGameModule *CreateGameModule(CDasherView *pView, CDasherModel *pModel);
+  CGameModule *CreateGameModule();
 private:
   /// 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
diff --git a/Src/DasherCore/DasherInterfaceBase.cpp b/Src/DasherCore/DasherInterfaceBase.cpp
index eed28a8..2b33c57 100644
--- a/Src/DasherCore/DasherInterfaceBase.cpp
+++ b/Src/DasherCore/DasherInterfaceBase.cpp
@@ -296,28 +296,6 @@ void CDasherInterfaceBase::HandleEvent(int iParameter) {
     delete m_pWordSpeaker;
     m_pWordSpeaker = GetBoolParameter(BP_SPEAK_WORDS) ? new WordSpeaker(this) : NULL;
     break;
-  case BP_GAME_MODE:
-    if(GetBoolParameter(BP_GAME_MODE)) {
-      DASHER_ASSERT(m_pGameModule == NULL);
-      if (CWordGeneratorBase *pWords = m_pNCManager->GetAlphabetManager()->GetGameWords()) {
-        m_pGameModule = CreateGameModule(m_pDasherView,m_pDasherModel);
-        m_pGameModule->SetWordGenerator(m_pNCManager->GetAlphabet(), pWords);
-      } else {
-        ///TRANSLATORS: %s is the name of the alphabet; the string "GameTextFile"
-        /// refers to a setting name in gsettings or equivalent, and should not be translated.
-        const char *msg=_("Could not find game sentences file for %s - check alphabet definition, or override with GameTextFile setting");
-        char *buf(new char[strlen(msg)+m_pNCManager->GetAlphabet()->GetID().length()]);
-        sprintf(buf,msg,m_pNCManager->GetAlphabet()->GetID().c_str());
-        Message(buf,true);
-        delete buf;
-        SetBoolParameter(BP_GAME_MODE, false);
-      }
-    } else {
-      delete m_pGameModule;
-      m_pGameModule = NULL;
-    }
-    if (!GetBoolParameter(BP_CONTROL_MODE)) break;
-    //fall-through (GAME_MODE disables CONTROL_MODE, so we've effectively changed the latter too)
   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
@@ -329,12 +307,40 @@ void CDasherInterfaceBase::HandleEvent(int iParameter) {
   }
 }
 
+void CDasherInterfaceBase::EnterGameMode(CGameModule *pGameModule) {
+  DASHER_ASSERT(m_pGameModule == NULL);
+  if (CWordGeneratorBase *pWords = m_pNCManager->GetAlphabetManager()->GetGameWords()) {
+    if (!pGameModule) pGameModule=CreateGameModule();
+    m_pGameModule=pGameModule;
+    m_pGameModule->SetWordGenerator(m_pNCManager->GetAlphabet(), pWords);
+    m_pNCManager->updateControl();
+  } else {
+    ///TRANSLATORS: %s is the name of the alphabet; the string "GameTextFile"
+    /// refers to a setting name in gsettings or equivalent, and should not be translated.
+    const char *msg=_("Could not find game sentences file for %s - check alphabet definition, or override with GameTextFile setting");
+    char *buf(new char[strlen(msg)+m_pNCManager->GetAlphabet()->GetID().length()]);
+    sprintf(buf,msg,m_pNCManager->GetAlphabet()->GetID().c_str());
+    Message(buf,true);
+    delete buf;
+    delete pGameModule; //does nothing if null.
+  }
+}
+
+void CDasherInterfaceBase::LeaveGameMode() {
+  DASHER_ASSERT(m_pGameModule);
+  CGameModule *pMod = m_pGameModule;
+  m_pGameModule=NULL; //point at which we officially exit game mode
+  delete pMod;
+  m_pNCManager->updateControl();
+  SetBuffer(0);
+}
+
 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 (pIntf->GetGameModule()) return;
   if(pEditEvent->m_iEditType == 1) {
     if (pIntf->SupportsSpeech()) {
       const CAlphInfo *pAlphabet = pIntf->m_pNCManager->GetAlphabet();
@@ -842,7 +848,7 @@ void CDasherInterfaceBase::SetOffset(int iOffset, bool bForce) {
   if (iOffset == m_pDasherModel->GetOffset() && !bForce) return;
 
   CDasherNode *pNode = m_pNCManager->GetAlphabetManager()->GetRoot(NULL, iOffset!=0, iOffset);
-  if (GetBoolParameter(BP_GAME_MODE)) pNode->SetFlag(NF_GAME, true);
+  if (GetGameModule()) pNode->SetFlag(NF_GAME, true);
   m_pDasherModel->SetNode(pNode);
   
   //ACL TODO note that CTL_MOVE, etc., do not come here (that would probably
diff --git a/Src/DasherCore/DasherInterfaceBase.h b/Src/DasherCore/DasherInterfaceBase.h
index 20303a0..20f64b5 100644
--- a/Src/DasherCore/DasherInterfaceBase.h
+++ b/Src/DasherCore/DasherInterfaceBase.h
@@ -365,12 +365,34 @@ public:
   ///
   virtual int GetFileSize(const std::string &strFileName) = 0;
 
-  ///Gets a pointer to the game module. Will return null if game mode
-  /// is not on.
+  ///Gets a pointer to the game module. This is the correct way to determine
+  /// whether game mode is currently on or off.
+  /// \return pointer to current game module, if game mode on; or null, if off.
   CGameModule *GetGameModule() {
     return m_pGameModule;
   }
 
+  ///Call to enter game mode. The correct procedure for UI activation of game
+  /// mode, is to first create a game module (the method CreateGameModule is
+  /// provided for this purpose), and then prompt the user to change any
+  /// ModuleSettings for that GameModule (hence needing to create it first in
+  /// order to determine what settings it has); if the user clicks ok,
+  /// then the created module can be passed to this method. (If the user instead
+  /// clicks cancel, then the module should be deleted.)
+  /// Note method is virtual, so subclasses can override e.g. to detect entering
+  /// game mode (they should call this method, then check GetGameModule()).
+  /// \param pGameModule concrete instance of GameModule to use. This can be null,
+  /// in which case we will use the module returned by CreateGameModule (e.g.
+  /// this is done for demo filter). However
+  /// \param pGameModule newly-constructed GameModule to use, or NULL to use one
+  /// returned from CreateGameModule; in either case, will be deleted when we
+  /// leave game mode.
+  virtual void EnterGameMode(CGameModule *pGameModule);
+  
+  ///Exits game mode, including deleting the game module that was in use.
+  /// virtual so subclasses can override to detect leaving game mode.
+  void LeaveGameMode();
+  
 protected:
 
   /// @name Startup
@@ -396,11 +418,11 @@ protected:
 
   /// @}
 
-  ///Creates the game module - called on demand, i.e. (only) when game mode is started
-  /// by setting BP_GAME_MODE. Subclasses must implement to return a concrete subclass
-  /// of GameModule, perhaps by using platform-specific widgets (e.g. the edit box?)
-  
-  virtual CGameModule *CreateGameModule(CDasherView *pView, CDasherModel *pModel)=0;
+  ///Creates the game module. Subclasses must implement to return a concrete
+  /// subclass of CGameModule, perhaps by using platform-specific widgets (e.g.
+  /// the edit box?). Note the view and model can be obtained by calling GetView()
+  /// and reading m_pDasherModel, respectively
+  virtual CGameModule *CreateGameModule() = 0;
 
   /// Draw a new Dasher frame, regardless of whether we're paused etc.
   /// \param iTime Current time in ms.
@@ -428,8 +450,8 @@ protected:
   /// but with the mouse precisely over the crosshair)
   virtual void onUnpause(unsigned long lTime);
   
-  CDasherScreen *m_DasherScreen;
-
+  CDasherView *GetView() {return m_pDasherView;}
+  
   CDasherModel * const m_pDasherModel;
   ///Framerate monitor; created in constructor, req'd for DynamicFilter subclasses
   CFrameRate * const m_pFramerate;
@@ -511,6 +533,7 @@ protected:
   /// @name Child components
   /// Various objects which are 'owned' by the core.
   /// @{
+  CDasherScreen *m_DasherScreen;
   CDasherView *m_pDasherView;
   CDasherInput *m_pInput;
   CInputFilter* m_pInputFilter;
diff --git a/Src/DasherCore/DemoFilter.cpp b/Src/DasherCore/DemoFilter.cpp
index d1d5e96..9d22ca9 100644
--- a/Src/DasherCore/DemoFilter.cpp
+++ b/Src/DasherCore/DemoFilter.cpp
@@ -46,12 +46,12 @@ bool CDemoFilter::DecorateView(CDasherView *pView, CDasherInput *pInput) {
 }
 
 void CDemoFilter::Activate() {
-  SetBoolParameter(BP_GAME_MODE, true);
+  m_pInterface->EnterGameMode(NULL);
   HandleEvent(LP_FRAMERATE); //just to make sure!
 }
 
 void CDemoFilter::Deactivate() {
-  SetBoolParameter(BP_GAME_MODE, false);
+  m_pInterface->LeaveGameMode();
 }
 
 std::pair<double,double> GaussianRand() // Is there a random number class already?
diff --git a/Src/DasherCore/GameModule.cpp b/Src/DasherCore/GameModule.cpp
index 58dd065..739c0cc 100644
--- a/Src/DasherCore/GameModule.cpp
+++ b/Src/DasherCore/GameModule.cpp
@@ -28,7 +28,6 @@ bool CGameModule::GetSettings(SModuleSettings **sets, int *count) {
 }
 
 CGameModule::~CGameModule()  {
-  DASHER_ASSERT(!GetBoolParameter(BP_GAME_MODE));
   if (m_ulTotalTime) {
     //TODO make this a running commentary?
     ostringstream summary;
@@ -103,7 +102,7 @@ void CGameModule::SetWordGenerator(const CAlphInfo *pAlph, CWordGeneratorBase *p
 	if (!GenerateChunk()) {
     m_pInterface->Message("Game mode sentences file empty!",true);
     //this'll delete the 'this' pointer, so we'd better not do anything else afterwards!...
-    SetBoolParameter(BP_GAME_MODE, false);
+    m_pInterface->LeaveGameMode();
   }
 }
 
@@ -178,7 +177,7 @@ void CGameModule::DecorateView(unsigned long lTime, CDasherView *pView, CDasherM
     if (!GenerateChunk()) {
       m_pInterface->Message("Game mode sentence file finished!",true);
       //note this deletes the 'this' pointer...
-      SetBoolParameter(BP_GAME_MODE, false);
+      m_pInterface->LeaveGameMode();
       //so better get out of here, fast!
       return;
     }
diff --git a/Src/DasherCore/NodeCreationManager.cpp b/Src/DasherCore/NodeCreationManager.cpp
index 5c870fb..4ff8429 100644
--- a/Src/DasherCore/NodeCreationManager.cpp
+++ b/Src/DasherCore/NodeCreationManager.cpp
@@ -117,7 +117,7 @@ CNodeCreationManager::CNodeCreationManager(CSettingsUser *pCreateFrom,
 #endif
 
   HandleEvent(LP_ORIENTATION);
-  HandleEvent(BP_CONTROL_MODE);
+  updateControl();
 }
 
 CNodeCreationManager::~CNodeCreationManager() {
@@ -135,24 +135,22 @@ void CNodeCreationManager::ChangeScreen(CDasherScreen *pScreen) {
 }
 
 void CNodeCreationManager::HandleEvent(int iParameter) {
-  switch (iParameter) {
-    case BP_CONTROL_MODE:
-    case BP_GAME_MODE: {
-      delete m_pControlManager;
-      unsigned long iControlSpace;
-      //don't allow a control manager during Game Mode 
-      if (GetBoolParameter(BP_CONTROL_MODE) && !GetBoolParameter(BP_GAME_MODE)) {
-        m_pControlManager = new CControlManager(this, this, m_pInterface);
-        if (m_pScreen) m_pControlManager->MakeLabels(m_pScreen);
-        iControlSpace = CDasherModel::NORMALIZATION / 20;
-      } else {
-        m_pControlManager = NULL;
-        iControlSpace = 0;
-      }
-      m_iAlphNorm = CDasherModel::NORMALIZATION-iControlSpace;
-      break;
-    }
+  if (iParameter==BP_CONTROL_MODE) updateControl();
+}
+
+void CNodeCreationManager::updateControl() {
+  delete m_pControlManager;
+  unsigned long iControlSpace;
+  //don't allow a control manager during Game Mode 
+  if (GetBoolParameter(BP_CONTROL_MODE) && !m_pInterface->GetGameModule()) {
+    m_pControlManager = new CControlManager(this, this, m_pInterface);
+    if (m_pScreen) m_pControlManager->MakeLabels(m_pScreen);
+    iControlSpace = CDasherModel::NORMALIZATION / 20;
+  } else {
+    m_pControlManager = NULL;
+    iControlSpace = 0;
   }
+  m_iAlphNorm = CDasherModel::NORMALIZATION-iControlSpace;
 }
 
 void CNodeCreationManager::AddExtras(CDasherNode *pParent) {
diff --git a/Src/DasherCore/NodeCreationManager.h b/Src/DasherCore/NodeCreationManager.h
index 70221ae..c9d3bf2 100644
--- a/Src/DasherCore/NodeCreationManager.h
+++ b/Src/DasherCore/NodeCreationManager.h
@@ -32,8 +32,12 @@ class CNodeCreationManager : public Dasher::CSettingsUserObserver {
   
   ///Tells us the screen on which all created node labels must be rendered
   void ChangeScreen(Dasher::CDasherScreen *pScreen);
+  
+  ///Create/destroy Control Manager, as appropriate (according to
+  /// BP_CONTROL_MODE and game mode status)
+  void updateControl();
 
-  //we watch for changes to BP_CONTROL_MODE and create the Control Manager lazily
+  //Watch for changes to BP_CONTROL_MODE and call updateControl() as necessary
   void HandleEvent(int iParameter);
   ///
   /// Get a root node of a particular type
diff --git a/Src/DasherCore/Parameters.cpp b/Src/DasherCore/Parameters.cpp
index 598b063..91f1304 100644
--- a/Src/DasherCore/Parameters.cpp
+++ b/Src/DasherCore/Parameters.cpp
@@ -24,7 +24,6 @@ const bp_table boolparamtable[] = {
   {BP_TURBO_MODE, "TurboMode", PERS, true, "Boost speed when holding key1 or right mouse button"},
   {BP_AUTOCALIBRATE, "Autocalibrate", PERS, false, "Automatically learn TargetOffset e.g. gazetracking"},
   {BP_REMAP_XTREME, "RemapXtreme", PERS, false, "Pointer at extreme Y translates more and zooms less"},
-  {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"},
diff --git a/Src/DasherCore/Parameters.h b/Src/DasherCore/Parameters.h
index e7b1ece..d9fd287 100644
--- a/Src/DasherCore/Parameters.h
+++ b/Src/DasherCore/Parameters.h
@@ -34,7 +34,7 @@ enum {
   BP_COLOUR_MODE, BP_MOUSEPOS_MODE,
   BP_PALETTE_CHANGE, BP_TURBO_MODE,
   BP_AUTOCALIBRATE, BP_REMAP_XTREME,
-  BP_GAME_MODE, BP_LM_DICTIONARY, 
+  BP_LM_DICTIONARY, 
   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,
diff --git a/Src/Gtk2/DasherControl.cpp b/Src/Gtk2/DasherControl.cpp
index 781709c..832edf7 100644
--- a/Src/Gtk2/DasherControl.cpp
+++ b/Src/Gtk2/DasherControl.cpp
@@ -335,13 +335,13 @@ void CDasherControl::HandleEvent(int iParameter) {
 }
 
 void CDasherControl::editOutput(const std::string &strText, CDasherNode *pNode) {
-  if (!GetBoolParameter(BP_GAME_MODE)) //GameModule sets editbox directly
+  if (!GetGameModule()) //GameModule sets editbox directly
     g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_edit_insert", strText.c_str(), pNode->offset());
   CDasherInterfaceBase::editOutput(strText, pNode);
 }
 
 void CDasherControl::editDelete(const std::string &strText, CDasherNode *pNode) {
-  if (!GetBoolParameter(BP_GAME_MODE)) //GameModule sets editbox directly
+  if (!GetGameModule()) //GameModule sets editbox directly
     g_signal_emit_by_name(GTK_WIDGET(m_pDasherControl), "dasher_edit_delete", strText.c_str(), pNode->offset());
   CDasherInterfaceBase::editDelete(strText, pNode);
 }
@@ -464,10 +464,10 @@ private:
   GtkTextMark *m_mTarget; //after any "wrong" text, before target; if no wrong chars, ==m_entered.
 };
 
-CGameModule *CDasherControl::CreateGameModule(CDasherView *pView,CDasherModel *pModel) {
+CGameModule *CDasherControl::CreateGameModule() {
   if (GtkTextBuffer *buf=gtk_dasher_control_game_text_buffer(m_pDasherControl))
-    return new GtkGameModule(this, this, pView, pModel, buf);
-  return CDashIntfScreenMsgs::CreateGameModule(pView,pModel);
+    return new GtkGameModule(this, this, GetView(), m_pDasherModel, buf);
+  return CDashIntfScreenMsgs::CreateGameModule();
 }
 
 void CDasherControl::WriteTrainFile(const std::string &filename, const std::string &strNewText) {
diff --git a/Src/Gtk2/DasherControl.h b/Src/Gtk2/DasherControl.h
index 55a6249..f0de292 100644
--- a/Src/Gtk2/DasherControl.h
+++ b/Src/Gtk2/DasherControl.h
@@ -165,7 +165,7 @@ public:
   ///Override to emit Gtk2 signal
   virtual void SetLockStatus(const string &strText, int iPercent);
 
-  CGameModule *CreateGameModule(CDasherView *pView, CDasherModel *pModel);
+  CGameModule *CreateGameModule();
 private:
   virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
   virtual void ScanColourFiles(std::vector<std::string> &vFileList);
diff --git a/Src/Gtk2/GtkDasherControl.cpp b/Src/Gtk2/GtkDasherControl.cpp
index 6645ea1..0103142 100644
--- a/Src/Gtk2/GtkDasherControl.cpp
+++ b/Src/Gtk2/GtkDasherControl.cpp
@@ -125,6 +125,19 @@ GtkTextBuffer *gtk_dasher_control_game_text_buffer(GtkDasherControl *pDasherCont
   return dasher_editor_game_text_buffer(pPrivate->pEditor);
 }
 
+void gtk_dasher_control_set_game_mode(GtkDasherControl *pControl, bool bOn) {
+  GtkDasherControlPrivate *pPrivate = GTK_DASHER_CONTROL_GET_PRIVATE(pControl);
+  if (bOn)
+    pPrivate->pControl->EnterGameMode(NULL);
+  else
+    pPrivate->pControl->LeaveGameMode();
+}
+
+bool gtk_dasher_control_get_game_mode(GtkDasherControl *pControl) {
+  GtkDasherControlPrivate *pPrivate = GTK_DASHER_CONTROL_GET_PRIVATE(pControl);
+  return pPrivate->pControl->GetGameModule() ? true : false;
+}
+
 static void 
 gtk_dasher_control_finalize(GObject *pObject) {
   GtkDasherControl *pDasherControl = GTK_DASHER_CONTROL(pObject);
diff --git a/Src/Gtk2/GtkDasherControl.h b/Src/Gtk2/GtkDasherControl.h
index 59db145..058aecc 100644
--- a/Src/Gtk2/GtkDasherControl.h
+++ b/Src/Gtk2/GtkDasherControl.h
@@ -81,8 +81,11 @@ gint gtk_dasher_control_ctrl_delete(GtkDasherControl *pControl, bool bForwards,
 void gtk_dasher_control_external_key_down(GtkDasherControl *pControl, int iKeyVal);
 void gtk_dasher_control_external_key_up(GtkDasherControl *pControl, int iKeyVal);
 gboolean gtk_dasher_control_get_module_settings(GtkDasherControl * pControl, const gchar *szModule, SModuleSettings **pSettings, gint *iCount);
+//For constructing a GtkGameModule around the text buffer:
 GtkTextBuffer *gtk_dasher_control_game_text_buffer(GtkDasherControl *pPrivate);
-
+//Calls EnterGameMode or LeaveGameMode, as appropriate, on the underlying CDasherControl
+void gtk_dasher_control_set_game_mode(GtkDasherControl *pControl, bool bOn);
+bool gtk_dasher_control_get_game_mode(GtkDasherControl *pControl);
 void gtk_dasher_control_force_pause(GtkDasherControl *pControl);
 void gtk_dasher_user_log_new_trial(GtkDasherControl * pControl);
 void gtk_dasher_control_set_focus(GtkDasherControl * pControl);
diff --git a/Src/Gtk2/dasher_editor.cpp b/Src/Gtk2/dasher_editor.cpp
index b04e472..ea2df14 100644
--- a/Src/Gtk2/dasher_editor.cpp
+++ b/Src/Gtk2/dasher_editor.cpp
@@ -27,12 +27,10 @@
 
 #include "dasher_editor.h"
 #include "dasher_lock_dialogue.h"
-#include "dasher_main.h"
 
 typedef struct _DasherEditorPrivate DasherEditorPrivate;
 
 struct _DasherEditorPrivate {
-  DasherMain *pDasherMain;
   GtkTextView *pTextView;
   GtkTextBuffer *pBuffer;
   GtkClipboard *pTextClipboard;
@@ -136,9 +134,9 @@ dasher_editor_finalize(GObject *pObject) {
 }
 
 void
-dasher_editor_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, DasherMain *pDasherMain, GtkBuilder *pXML, const gchar *szFullPath) {
+dasher_editor_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, GtkDasherControl *pDasherCtrl, GtkBuilder *pXML, const gchar *szFullPath) {
   if(DASHER_EDITOR_GET_CLASS(pSelf)->initialise)
-    DASHER_EDITOR_GET_CLASS(pSelf)->initialise(pSelf, pAppSettings, pDasherMain, pXML, szFullPath);
+    DASHER_EDITOR_GET_CLASS(pSelf)->initialise(pSelf, pAppSettings, pDasherCtrl, pXML, szFullPath);
 }
 
 GtkTextBuffer *dasher_editor_game_text_buffer(DasherEditor *pSelf) {
diff --git a/Src/Gtk2/dasher_editor.h b/Src/Gtk2/dasher_editor.h
index 1c7efd2..7e408ed 100644
--- a/Src/Gtk2/dasher_editor.h
+++ b/Src/Gtk2/dasher_editor.h
@@ -8,10 +8,10 @@
 #include "../DasherCore/ControlManager.h"
 
 /* Forward declaration */
-typedef struct _DasherMain DasherMain;
-struct _DasherMain;
 typedef struct _DasherAppSettings DasherAppSettings;
 struct _DasherAppSettings;
+typedef struct _GtkDasherControl GtkDasherControl;
+struct _GtkDasherControl;
 
 G_BEGIN_DECLS
 #define DASHER_TYPE_EDITOR            (dasher_editor_get_type())
@@ -32,7 +32,7 @@ struct _DasherEditorClass {
   GtkVBoxClass parent_class;
 
   /* VTable */
-  void (*initialise)(DasherEditor *, DasherAppSettings *, DasherMain *, GtkBuilder *, const gchar *);
+  void (*initialise)(DasherEditor *, DasherAppSettings *, GtkDasherControl *, GtkBuilder *, const gchar *);
   gboolean (*command)(DasherEditor *, const gchar *);
   void (*clear)(DasherEditor *);
   const gchar *(*get_all_text)(DasherEditor *);
@@ -72,7 +72,7 @@ GType dasher_editor_get_type();
 /* Functions for initialisation and takedown */
 void dasher_editor_initialise(DasherEditor *pSelf,
                               DasherAppSettings *pAppSettings,
-                              DasherMain *pDasherMain, GtkBuilder *pXML,
+                              GtkDasherControl *pDasherCtrl, GtkBuilder *pXML,
                               const gchar *szFullPath);
 
 /* Abstract command handler */
diff --git a/Src/Gtk2/dasher_editor_internal.cpp b/Src/Gtk2/dasher_editor_internal.cpp
index 8d81c6c..7e7f8ea 100644
--- a/Src/Gtk2/dasher_editor_internal.cpp
+++ b/Src/Gtk2/dasher_editor_internal.cpp
@@ -17,12 +17,13 @@
 #include "dasher_editor_external.h"
 #include "dasher_lock_dialogue.h"
 #include "dasher_main.h"
+#include "GtkDasherControl.h"
 #include "../DasherCore/ControlManager.h"
 
 typedef struct _DasherEditorInternalPrivate DasherEditorInternalPrivate;
 
 struct _DasherEditorInternalPrivate {
-  DasherMain *pDasherMain;
+  GtkDasherControl *pDasherCtrl;
   GtkTextView *pTextView;
   GtkTextBuffer *pBuffer;
   GtkClipboard *pTextClipboard;
@@ -62,7 +63,7 @@ static void dasher_editor_internal_finalize(GObject *pObject);
 static void dasher_editor_internal_handle_font(DasherEditor *pSelf, const gchar *szFont);
 
 gboolean dasher_editor_internal_command(DasherEditor *pSelf, const gchar *szCommand);
-void dasher_editor_internal_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, DasherMain *pDasherMain, GtkBuilder *pXML, const gchar *szFullPath);
+void dasher_editor_internal_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, GtkDasherControl *pDasherCtrl, GtkBuilder *pXML, const gchar *szFullPath);
 
 /* Private methods */
 static void dasher_editor_internal_select_all(DasherEditor *pSelf);
@@ -227,11 +228,11 @@ dasher_editor_internal_new(void)
 }
 
 void
-dasher_editor_internal_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, DasherMain *pDasherMain, GtkBuilder *pXML, const gchar *szFullPath) {
+dasher_editor_internal_initialise(DasherEditor *pSelf, DasherAppSettings *pAppSettings, GtkDasherControl *pDasherCtrl, GtkBuilder *pXML, const gchar *szFullPath) {
   DasherEditorInternalPrivate *pPrivate = DASHER_EDITOR_INTERNAL_GET_PRIVATE(pSelf);
 
   pPrivate->pAppSettings = pAppSettings;
-  pPrivate->pDasherMain = pDasherMain;
+  pPrivate->pDasherCtrl = pDasherCtrl;
 
   dasher_editor_internal_handle_font(pSelf,
 				     dasher_app_settings_get_string(pPrivate->pAppSettings,
@@ -460,7 +461,7 @@ void dasher_editor_internal_mark_changed(DasherEditorInternal *pSelf, GtkTextIte
     // by a callback registered by editor_internal, which then emitted a context_changed
     // signal from the editor_internal. So just emit the context_changed directly...
     if (!pPrivate->bInControlAction //tho not if it's the result of a control-mode edit/delete
-        && !dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_GAME_MODE)) //and not in game mode
+        && !gtk_dasher_control_get_game_mode(pPrivate->pDasherCtrl)) //and not in game mode
       g_signal_emit_by_name(G_OBJECT(pSelf), "context_changed", G_OBJECT(pSelf), NULL, NULL);
   }
 }
diff --git a/Src/Gtk2/dasher_main.cpp b/Src/Gtk2/dasher_main.cpp
index 1c2c094..575201c 100644
--- a/Src/Gtk2/dasher_main.cpp
+++ b/Src/Gtk2/dasher_main.cpp
@@ -273,7 +273,7 @@ dasher_main_new(int *argc, char ***argv, SCommandLine *pCommandLine) {
     /* --- */
 
 
-    dasher_editor_initialise(pPrivate->pEditor, pPrivate->pAppSettings, pDasherMain, pPrivate->pXML, NULL);
+    dasher_editor_initialise(pPrivate->pEditor, pPrivate->pAppSettings, GTK_DASHER_CONTROL(pPrivate->pDasherWidget), pPrivate->pXML, NULL);
 
 
     dasher_main_setup_window(pDasherMain);
@@ -597,7 +597,7 @@ void show_game_file_dialog(GtkWidget *pButton, GtkWidget *pWidget, gpointer pDat
 		dasher_app_settings_set_string(pPrivate->pAppSettings,
 							SP_GAME_TEXT_FILE,
 							filename);
-		dasher_app_settings_set_bool(pPrivate->pAppSettings, BP_GAME_MODE, true);
+		gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), true);
 	}
 	gtk_widget_destroy(GTK_WIDGET(objRefs->first));
 }
@@ -605,8 +605,7 @@ void show_game_file_dialog(GtkWidget *pButton, GtkWidget *pWidget, gpointer pDat
 /**
  * Toggle game mode on and off. Toggling on causes a dialog box to be displayed
  * welcoming the user to game mode and prompting them to specify a file to play with.
- * Toggling off just sets BP_GAME_MODE to false, which then causes the dasher core
- * to respond appropriately.
+ * Toggling off just calls LeaveGameMode().
  *
  * @param pSelf a reference to an instance of DasherMain
  */ 
@@ -614,7 +613,7 @@ void dasher_main_command_toggle_game_mode(DasherMain *pSelf) {
 
   DasherMainPrivate *pPrivate = DASHER_MAIN_GET_PRIVATE(pSelf);
 
-  if(!dasher_app_settings_get_bool(pPrivate->pAppSettings, BP_GAME_MODE)) {
+  if(!gtk_dasher_control_get_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget))) {
 
     GtkWidget *pDialog = gtk_message_dialog_new(GTK_WINDOW(pPrivate->pMainWindow), GTK_DIALOG_MODAL, 
                                          GTK_MESSAGE_OTHER, GTK_BUTTONS_NONE, 
@@ -636,8 +635,8 @@ void dasher_main_command_toggle_game_mode(DasherMain *pSelf) {
 					(gpointer)&objRefs);
 
     if (gtk_dialog_run(GTK_DIALOG(pDialog))==GTK_RESPONSE_ACCEPT) {
-      dasher_app_settings_set_bool(pPrivate->pAppSettings, BP_GAME_MODE, true);
-//Tick menu?
+      gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), true);
+      //Tick menu?
     }
     //have to do this check because we might have destroyed the dialog already in show_game_file_dialog
     if(GTK_IS_WIDGET(pDialog))
@@ -651,7 +650,7 @@ void dasher_main_command_toggle_game_mode(DasherMain *pSelf) {
     GtkWidget *pYesButton = gtk_dialog_add_button(GTK_DIALOG(pDialog), GTK_STOCK_YES, GTK_RESPONSE_ACCEPT);
 
     if(gtk_dialog_run(GTK_DIALOG(pDialog))==GTK_RESPONSE_ACCEPT) {
-      dasher_app_settings_set_bool(pPrivate->pAppSettings, BP_GAME_MODE, false);
+      gtk_dasher_control_set_game_mode(GTK_DASHER_CONTROL(pPrivate->pDasherWidget), false);
     }
     DASHER_ASSERT(GTK_IS_WIDGET(pDialog));
     gtk_widget_destroy(GTK_WIDGET(pDialog));
diff --git a/Src/MacOSX/COSXDasherControl.h b/Src/MacOSX/COSXDasherControl.h
index 35fc331..5a65c7b 100644
--- a/Src/MacOSX/COSXDasherControl.h
+++ b/Src/MacOSX/COSXDasherControl.h
@@ -54,9 +54,10 @@ public:
   void ClearAllContext();
   std::string GetContext(unsigned int iOffset, unsigned int iLength);
   virtual int GetFileSize(const std::string &strFileName);
-  void HandleEvent(int iParameter);
+  void EnterGameMode(CGameModule *pModule);
+  void LeaveGameMode();
   void SetEdit(id<DasherEdit> pEdit);
-  CGameModule *CreateGameModule(CDasherView *pView, CDasherModel *pModel);
+  CGameModule *CreateGameModule();
 private:
   virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
   virtual void ScanColourFiles(std::vector<std::string> &vFileList);
diff --git a/Src/MacOSX/COSXDasherControl.mm b/Src/MacOSX/COSXDasherControl.mm
index 326f736..501bf6a 100644
--- a/Src/MacOSX/COSXDasherControl.mm
+++ b/Src/MacOSX/COSXDasherControl.mm
@@ -175,10 +175,14 @@ void COSXDasherControl::TimerFired(NSPoint p) {
   [[dasherApp dasherView] redisplay];
 }  
  
-void COSXDasherControl::HandleEvent(int iParameter) {
-  CDashIntfScreenMsgs::HandleEvent(iParameter);
-  if (iParameter == BP_GAME_MODE)
-    [dasherApp setGameModeOn:(GetBoolParameter(BP_GAME_MODE) ? NSOnState : NSOffState)];
+void COSXDasherControl::EnterGameMode(CGameModule *pGameModule) {
+  CDashIntfScreenMsgs::EnterGameMode(pGameModule);
+  [dasherApp setGameModeOn:(GetGameModule()!=NULL)];
+}
+
+void COSXDasherControl::LeaveGameMode() {
+  CDashIntfScreenMsgs::LeaveGameMode();
+  [dasherApp setGameModeOn:(GetGameModule()!=NULL)];
 }
 
 void COSXDasherControl::SetEdit(id<DasherEdit> _dasherEdit) {
@@ -359,6 +363,6 @@ void COSXDasherControl::ClearAllContext() {
   SetBuffer(0);
 }
 
-CGameModule *COSXDasherControl::CreateGameModule(CDasherView *pView, CDasherModel *pModel) {
-  return new COSXGameModule(this, this, pView, pModel, [dasherApp textView]);
+CGameModule *COSXDasherControl::CreateGameModule() {
+  return new COSXGameModule(this, this, GetView(), m_pDasherModel, [dasherApp textView]);
 }
diff --git a/Src/MacOSX/DasherApp.mm b/Src/MacOSX/DasherApp.mm
index bec5cd9..a3ac70f 100644
--- a/Src/MacOSX/DasherApp.mm
+++ b/Src/MacOSX/DasherApp.mm
@@ -128,7 +128,7 @@ static NSString *FilenameToUntitledName = @"NilToUntitled";
 }
 
 -(BOOL)gameModeOn {
-  return aquaDasherControl->GetBoolParameter(BP_GAME_MODE);
+  return aquaDasherControl->GetGameModule()!=NULL;
 }
 
 -(void)setGameModeOn:(BOOL)bVal {
@@ -145,8 +145,12 @@ static NSString *FilenameToUntitledName = @"NilToUntitled";
   //we can now try and startup game mode in the core;
   // with no automatic checking of the menuitem pending, any changes we make
   // to the gameModeOn property will be correctly reflected in the menu... 
-  if (obj && directMode) self.directMode=false; //turn off direct mode first _if_necessary_ (properties do not check for no-change)
-  aquaDasherControl->SetBoolParameter(BP_GAME_MODE, obj!=nil);
+  if (obj) {
+    if (directMode) self.directMode=false; //turn off direct mode first _if_necessary_ (properties do not check for no-change)
+    if (!aquaDasherControl->GetGameModule())
+      aquaDasherControl->EnterGameMode(NULL);
+  } else if (aquaDasherControl->GetGameModule())
+    aquaDasherControl->LeaveGameMode();
 }
 
 -(void)setDirectMode:(BOOL)bVal {
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.h b/Src/iPhone/Classes/CDasherInterfaceBridge.h
index 04aca70..34acb4b 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.h
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.h
@@ -68,7 +68,11 @@ public:
   void editProtect(Dasher::CDasherNode *pNode);
   ///Override for asynchronous messages only...TODO?
   void Message(const string &strText, bool bInterrupt);
-  Dasher::CGameModule *CreateGameModule(Dasher::CDasherView *pView,Dasher::CDasherModel *pModel);
+  Dasher::CGameModule *CreateGameModule();
+  
+  void HandleEvent(int iParameter);
+  void EnterGameMode(Dasher::CGameModule *pGameModule);
+  void LeaveGameMode();
 private:
   virtual void ScanAlphabetFiles(std::vector<std::string> &vFileList);
   virtual void ScanColourFiles(std::vector<std::string> &vFileList);
@@ -80,8 +84,6 @@ private:
   /// Pass events coming from the core to the appropriate handler.
   ///
   
-  void HandleEvent(int iParameter);
-  
   DasherAppDelegate *dasherApp;   // objc counterpart
   	
   Dasher::CIPhoneMouseInput *m_pMouseDevice;
diff --git a/Src/iPhone/Classes/CDasherInterfaceBridge.mm b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
index 1b8c3c9..1c23198 100644
--- a/Src/iPhone/Classes/CDasherInterfaceBridge.mm
+++ b/Src/iPhone/Classes/CDasherInterfaceBridge.mm
@@ -190,11 +190,19 @@ void CDasherInterfaceBridge::HandleEvent(int iParameter) {
     [dasherApp notifySpeedChange];
   else if (iParameter == SP_ALPHABET_ID)
     [dasherApp setAlphabet:GetActiveAlphabet()];
-  else if (iParameter == BP_GAME_MODE)
-    [dasherApp refreshToolbar];
   CDashIntfScreenMsgs::HandleEvent(iParameter);
 }
 
+void CDasherInterfaceBridge::EnterGameMode(CGameModule *pGameModule) {
+  CDashIntfScreenMsgs::EnterGameMode(pGameModule);
+  [dasherApp refreshToolbar];
+}
+
+void CDasherInterfaceBridge::LeaveGameMode() {
+  CDashIntfScreenMsgs::LeaveGameMode();
+  [dasherApp refreshToolbar];
+}
+
 void CDasherInterfaceBridge::editOutput(const string &strText, CDasherNode *pNode) {
 //NSLog(@"ExternalEventHandler edit insert");
   [dasherApp outputCallback:NSStringFromStdString(strText)];
@@ -290,6 +298,6 @@ void CDasherInterfaceBridge::WriteTrainFile(const std::string &filename,const st
   close(fd);
 }
 
-CGameModule *CDasherInterfaceBridge::CreateGameModule(CDasherView *pView, CDasherModel *pModel) {
-  return new IPhoneGameModule(this, this, pView, pModel, [dasherApp getWebView]);  
+CGameModule *CDasherInterfaceBridge::CreateGameModule() {
+  return new IPhoneGameModule(this, this, GetView(), m_pDasherModel, [dasherApp getWebView]);  
 }
diff --git a/Src/iPhone/Classes/DasherAppDelegate.mm b/Src/iPhone/Classes/DasherAppDelegate.mm
index 7809b57..dbc095c 100644
--- a/Src/iPhone/Classes/DasherAppDelegate.mm
+++ b/Src/iPhone/Classes/DasherAppDelegate.mm
@@ -221,7 +221,7 @@ using namespace Dasher;
 }
 
 -(void)refreshToolbar {
-  UIBarButtonSystemItem icon = _dasherInterface->GetBoolParameter(BP_GAME_MODE) ? UIBarButtonSystemItemStop : UIBarButtonSystemItemPlay;
+  UIBarButtonSystemItem icon = _dasherInterface->GetGameModule() ? UIBarButtonSystemItemStop : UIBarButtonSystemItemPlay;
   UIBarButtonItem *game = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:icon target:self action:@selector(toggleGameMode)] autorelease];
   UIBarButtonItem *action = [ActionButton buttonForToolbar:tools];
   if (!toolbarItems) {
@@ -238,8 +238,7 @@ using namespace Dasher;
     [toolbarItems replaceObjectAtIndex:4 withObject:game];
     [toolbarItems replaceObjectAtIndex:6 withObject:action];
   }
-  textView.hidden = _dasherInterface->GetBoolParameter(BP_GAME_MODE);
-  webView.hidden = !_dasherInterface->GetBoolParameter(BP_GAME_MODE);
+  webView.hidden = !(textView.hidden = _dasherInterface->GetGameModule() ? YES : NO);
   [tools setItems:toolbarItems];
 }
 
@@ -309,7 +308,10 @@ using namespace Dasher;
 }
 
 - (void)toggleGameMode {
-  _dasherInterface->SetBoolParameter(BP_GAME_MODE, !_dasherInterface->GetBoolParameter(BP_GAME_MODE));
+  if (_dasherInterface->GetGameModule())
+    _dasherInterface->LeaveGameMode();
+  else
+    _dasherInterface->EnterGameMode(NULL);
 }
 
 -(UIWebView *)getWebView {



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