[dasher] Fix rebuilding of parents and language changing.



commit a082f96160999718b19b07d25eab3a5d5b7f352f
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Mon Feb 8 19:08:25 2010 +0100

    Fix rebuilding of parents and language changing.
    
    Removed DasherNode::NodeIsParent
    DasherModel::RebuildAroundNode became DasherModel::RebuildAroundCrossHair

 ChangeLog                            |    4 +++
 Src/DasherCore/AlphabetManager.cpp   |   43 ++++++++------------------------
 Src/DasherCore/AlphabetManager.h     |    8 ------
 Src/DasherCore/ControlManager.cpp    |    1 -
 Src/DasherCore/ConversionManager.cpp |    1 -
 Src/DasherCore/DasherModel.cpp       |   45 ++++++++++++++++-----------------
 Src/DasherCore/DasherModel.h         |   10 ++++---
 Src/DasherCore/DasherNode.cpp        |    8 ------
 Src/DasherCore/DasherNode.h          |    1 -
 9 files changed, 43 insertions(+), 78 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index a01f14e..6aabb2d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-02-08  Alan Lawrence <acl33 inf phy cam ac uk>
+
+	* Fix rebuilding of parents and language changing.
+
 2009-02-06  Alan Lawrence <acl33 inf phy cam ac uk>
 
 	* Fix SymbolStream UTF-8 character input function.
diff --git a/Src/DasherCore/AlphabetManager.cpp b/Src/DasherCore/AlphabetManager.cpp
index 2d00985..c82c2c4 100644
--- a/Src/DasherCore/AlphabetManager.cpp
+++ b/Src/DasherCore/AlphabetManager.cpp
@@ -74,28 +74,8 @@ CAlphabetManager::CGroupNode *CAlphabetManager::makeGroup(CDasherNode *pParent,
 }
 
 CAlphabetManager::CAlphNode *CAlphabetManager::GetRoot(CDasherNode *pParent, int iLower, int iUpper, bool bEnteredLast, int iOffset) {
-  
-  CAlphNode *pNewNode = BuildNodeForOffset(pParent, iLower, iUpper, bEnteredLast, max(-1,iOffset-1));
-  if (!pNewNode) {
-    DASHER_ASSERT(bEnteredLast);
-    //could not build a node 'responsible' for entering the preceding character,
-    // as said character is not in the current alphabet! However, we'll allow the
-    // user to start entering text afresh
-    return BuildNodeForOffset(pParent, iLower, iUpper, false, iOffset);
-    // (the new node'll be constructed using the current alphabet's default context,
-    // i.e. start of sentence)
-  }
-  pNewNode->SetFlag(NF_SEEN, true);
-  
-  //    if(m_bGameMode) {
-  //    pNodeUserData->iGameOffset = -1;
-  pNewNode->SetFlag(NF_GAME, true);
-  //  }
-  
-  return pNewNode;
-}
 
-CAlphabetManager::CAlphNode *CAlphabetManager::BuildNodeForOffset(CDasherNode *pParent, int iLower, int iUpper, bool bSym, int iNewOffset) {
+  int iNewOffset(max(-1,iOffset-1));
   
   std::vector<symbol> vContextSymbols;
   // TODO: make the LM get the context, rather than force it to fix max context length as an int
@@ -127,8 +107,9 @@ CAlphabetManager::CAlphNode *CAlphabetManager::BuildNodeForOffset(CDasherNode *p
   }
   if (it == vContextSymbols.end()) {
     //previous character was not in the alphabet!
-    if (bSym) return NULL; //can't construct a node "responsible" for entering such a character!
-    //ok. Create a node as if we were starting a new sentence...
+    //can't construct a node "responsible" for entering it
+    bEnteredLast=false;
+    //instead, Create a node as if we were starting a new sentence...
     vContextSymbols.clear();
     m_pNCManager->GetAlphabet()->GetSymbols(vContextSymbols, m_pNCManager->GetAlphabet()->GetDefaultContext());
     it = vContextSymbols.begin();
@@ -139,7 +120,7 @@ CAlphabetManager::CAlphNode *CAlphabetManager::BuildNodeForOffset(CDasherNode *p
     m_pLanguageModel->EnterSymbol(iContext, *(it++));
   }
   
-  if(!bSym) {
+  if(!bEnteredLast) {
     pDisplayInfo->strDisplayText = ""; //equivalent to do m_pNCManager->GetAlphabet()->GetDisplayText(0)
     pDisplayInfo->iColour = m_pNCManager->GetAlphabet()->GetColour(0, iNewOffset%2);
     pNewNode = makeGroup(pParent, iLower, iUpper, pDisplayInfo, NULL);
@@ -148,6 +129,11 @@ CAlphabetManager::CAlphNode *CAlphabetManager::BuildNodeForOffset(CDasherNode *p
     pDisplayInfo->strDisplayText = m_pNCManager->GetAlphabet()->GetDisplayText(iSymbol);
     pDisplayInfo->iColour = m_pNCManager->GetAlphabet()->GetColour(iSymbol, iNewOffset%2);
     pNewNode = makeSymbol(pParent, iLower, iUpper, pDisplayInfo, iSymbol);
+    //if the new node is not child of an existing node, then it
+    // represents a symbol that's already happened - so we're either
+    // going backwards (rebuildParent) or creating a new root after a language change
+    DASHER_ASSERT (!pParent);
+    pNewNode->SetFlag(NF_SEEN, true);
   }
 
   pNewNode->m_iOffset = iNewOffset;
@@ -450,14 +436,7 @@ CDasherNode *CAlphabetManager::CAlphNode::RebuildParent(int iNewOffset) {
   //possible that we have a parent, as RebuildParent() rebuilds back to closest AlphNode.
   if (Parent()) return Parent();
   
-  CAlphNode *pNewNode = m_pMgr->BuildNodeForOffset(NULL, 0, 0, iNewOffset!=-1, iNewOffset);
-  if (!pNewNode) {
-    //could not rebuild parent node, as the preceding character was not
-    // in the current alphabet. Returning null means the user won't be able
-    // to reverse any further; he'll have to change language (to one
-    // including that symbol) instead.
-    return NULL;
-  }
+  CAlphNode *pNewNode = m_pMgr->GetRoot(NULL, 0, 0, iNewOffset!=-1, iNewOffset+1);
   
   //now fill in the new node - recursively - until it reaches us
   m_pMgr->IterateChildGroups(pNewNode, NULL, this);
diff --git a/Src/DasherCore/AlphabetManager.h b/Src/DasherCore/AlphabetManager.h
index ae17605..94ca091 100644
--- a/Src/DasherCore/AlphabetManager.h
+++ b/Src/DasherCore/AlphabetManager.h
@@ -126,14 +126,6 @@ namespace Dasher {
     virtual CDasherNode *CreateSymbolNode(CAlphNode *pParent, symbol iSymbol, unsigned int iLbnd, unsigned int iHbnd);
     virtual CLanguageModel::Context CreateSymbolContext(CAlphNode *pParent, symbol iSymbol);
     virtual CGroupNode *CreateGroupNode(CAlphNode *pParent, SGroupInfo *pInfo, unsigned int iLbnd, unsigned int iHbnd);
-
-    ///
-    ///Builds a new node from the context leading up to the specified offset
-    /// bSym - true if the build node should be considered as having entered the last symbol (e.g. when rebuilding parent,
-    /// but not when escaping back to Alphabet)
-    /// iNewOffset - m_iOffset of the new node (i.e. index into context of character the node represents)
-    ///
-    CAlphNode *BuildNodeForOffset(CDasherNode *pParent, int iLower, int iUpper, bool bSym, int iNewOffset);
     
     CLanguageModel *m_pLanguageModel;
     CNodeCreationManager *m_pNCManager;
diff --git a/Src/DasherCore/ControlManager.cpp b/Src/DasherCore/ControlManager.cpp
index a118839..fe7435a 100644
--- a/Src/DasherCore/ControlManager.cpp
+++ b/Src/DasherCore/ControlManager.cpp
@@ -312,7 +312,6 @@ void CControlManager::CContNode::PopulateChildren() {
        // Escape back to alphabet
 
        pNewNode = m_pMgr->m_pNCManager->GetAlphRoot(this, iLbnd, iHbnd, false, m_iOffset);
-       pNewNode->SetFlag(NF_SEEN, false);
      }
      else {
 
diff --git a/Src/DasherCore/ConversionManager.cpp b/Src/DasherCore/ConversionManager.cpp
index 13d912c..b6564df 100644
--- a/Src/DasherCore/ConversionManager.cpp
+++ b/Src/DasherCore/ConversionManager.cpp
@@ -103,7 +103,6 @@ void CConversionManager::CConvNode::PopulateChildren() {
   int iHbnd(m_pMgr->m_pNCManager->GetLongParameter(LP_NORMALIZATION));
 
   CDasherNode *pNewNode = m_pMgr->m_pNCManager->GetAlphRoot(this, iLbnd, iHbnd, false, m_iOffset + 1);
-  pNewNode->SetFlag(NF_SEEN, false);
 
   DASHER_ASSERT(GetChildren().back()==pNewNode);
 }
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index 44da803..ab34ea9 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -112,7 +112,7 @@ void CDasherModel::HandleEvent(Dasher::CEvent *pEvent) {
 
     switch (pEvt->m_iParameter) {
     case BP_CONTROL_MODE: // Rebuild the model if control mode is switched on/off
-      RebuildAroundNode(Get_node_under_crosshair());
+      RebuildAroundCrosshair();
       break;
     case BP_SMOOTH_OFFSET:
       if (!GetBoolParameter(BP_SMOOTH_OFFSET))
@@ -150,7 +150,7 @@ void CDasherModel::Make_root(CDasherNode *pNewRoot) {
   //  std::cout << "Make root" << std::endl;
 
   DASHER_ASSERT(pNewRoot != NULL);
-  DASHER_ASSERT(pNewRoot->NodeIsParent(m_Root));
+  DASHER_ASSERT(pNewRoot->Parent() == m_Root);
 
   m_Root->SetFlag(NF_COMMITTED, true);
 
@@ -189,25 +189,24 @@ void CDasherModel::RecursiveMakeRoot(CDasherNode *pNewRoot) {
   // TODO: we really ought to check that pNewRoot is actually a
   // descendent of the root, although that should be guaranteed
 
-  if(!pNewRoot->NodeIsParent(m_Root))
+  if(pNewRoot->Parent() != m_Root)
     RecursiveMakeRoot(pNewRoot->Parent());
 
   Make_root(pNewRoot);
 }
 
-// RebuildAroundNode is only used when BP_CONTROL changes,
-// so not very often.
-void CDasherModel::RebuildAroundNode(CDasherNode *pNode) {
+// only used when BP_CONTROL changes, so not very often.
+void CDasherModel::RebuildAroundCrosshair() {
+  CDasherNode *pNode = Get_node_under_crosshair();
   DASHER_ASSERT(pNode != NULL);
+  DASHER_ASSERT(pNode == m_pLastOutput);
 
   RecursiveMakeRoot(pNode);
-
+  DASHER_ASSERT(m_Root == pNode);
   ClearRootQueue();
   m_Root->Delete_children();
 
   m_Root->PopulateChildren();
-
-  m_pLastOutput = m_Root;
 }
 
 void CDasherModel::Reparent_root(int lower, int upper) {
@@ -304,15 +303,10 @@ void CDasherModel::InitialiseAtOffset(int iOffset, CDasherView *pView) {
   DeleteTree();
 
   m_Root = m_pNodeCreationManager->GetAlphRoot(NULL, 0,GetLongParameter(LP_NORMALIZATION), iOffset!=0, iOffset);
-
-  m_pLastOutput = m_Root;
-
-  // Create children of the root
-  // TODO: What about parents?
-
-  if(m_Root->Range() >= 0.1 * GetLongParameter(LP_NORMALIZATION)) {
-    ExpandNode(m_Root);
-  }
+  m_pLastOutput = (m_Root->GetFlag(NF_SEEN)) ? m_Root : NULL;
+  
+  // Create children of the root...
+  ExpandNode(m_Root);
 	
   // Set the root coordinates so that the root node is an appropriate
   // size and we're not in any of the children
@@ -326,6 +320,7 @@ void CDasherModel::InitialiseAtOffset(int iOffset, CDasherView *pView) {
 
   m_iDisplayOffset = 0;
 
+  //now (re)create parents, while they show on the screen
   if(pView) {
     while(pView->IsNodeVisible(m_Rootmin,m_Rootmax)) {
       CDasherNode *pOldRoot = m_Root;
@@ -462,6 +457,9 @@ void CDasherModel::UpdateBounds(myint iNewMin, myint iNewMax, unsigned long iTim
   // Check whether new nodes need to be created
   ExpandNode(Get_node_under_crosshair());
   
+// This'll get done again when we render the frame, later, but we use NF_SEEN
+// (set here) to ensure the node under the cursor can never be collapsed
+// (even when the node budget is exceeded) when we do the rendering...
   HandleOutput(pAdded, pNumDeleted);
 }
 
@@ -535,8 +533,9 @@ void CDasherModel::HandleOutput(Dasher::VECTOR_SYMBOL_PROB* pAdded, int* pNumDel
   
   //  std::cout << "HandleOutput: " << m_pLastOutput << " => " << pNewNode << std::endl;
   
-  CDasherNode *pLastSeen;
-  for (pLastSeen = pNewNode; !pLastSeen->GetFlag(NF_SEEN); pLastSeen = pLastSeen->Parent());
+  CDasherNode *pLastSeen = pNewNode;
+  while (pLastSeen && !pLastSeen->GetFlag(NF_SEEN))
+    pLastSeen = pLastSeen->Parent();
   
   while (m_pLastOutput != pLastSeen) {
     m_pLastOutput->Undo();
@@ -547,7 +546,7 @@ void CDasherModel::HandleOutput(Dasher::VECTOR_SYMBOL_PROB* pAdded, int* pNumDel
       (*pNumDeleted) += m_pLastOutput->m_iNumSymbols;
     
     m_pLastOutput = m_pLastOutput->Parent();
-    m_pLastOutput->Enter();
+    if (m_pLastOutput) m_pLastOutput->Enter();
   }
   
   if(!pNewNode->GetFlag(NF_SEEN)) {
@@ -610,7 +609,8 @@ bool CDasherModel::RenderToView(CDasherView *pView, CExpansionPolicy &policy) {
   DASHER_ASSERT(pView != NULL);
   DASHER_ASSERT(m_Root != NULL);
 
-  DASHER_ASSERT(Get_node_under_crosshair() == m_pLastOutput);
+  // XXX we HandleOutput in RenderToView
+  // DASHER_ASSERT(Get_node_under_crosshair() == m_pLastOutput);
 
   bool bReturnValue = false;
   std::vector<std::pair<myint,bool> > vGameTargetY;
@@ -643,7 +643,6 @@ bool CDasherModel::CheckForNewRoot(CDasherView *pView) {
 
 #ifdef DEBUG
   CDasherNode *pOldNode = Get_node_under_crosshair();
-  DASHER_ASSERT(pOldNode == m_pLastOutput);
 #endif
 
   CDasherNode *root(m_Root);
diff --git a/Src/DasherCore/DasherModel.h b/Src/DasherCore/DasherModel.h
index f2f4b5d..f5f411d 100644
--- a/Src/DasherCore/DasherModel.h
+++ b/Src/DasherCore/DasherModel.h
@@ -324,12 +324,14 @@ class Dasher::CDasherModel:public CFrameRate, private NoClones
   void RecursiveMakeRoot(CDasherNode *pNewRoot);
 
   ///
-  /// Rebuild the data structure such that a given node is guaranteed
-  /// to be in the same place on the screen. This would usually be the
-  /// node under the crosshair
+  /// Makes the node under the crosshair the root by deleting everything
+  /// outside it, then rebuilds the nodes beneath it. (Thus, the node under
+  /// the crosshair stays in the same place.) Used when control mode is turned
+  /// on or off, or more generally, when the sizes of child nodes may have
+  /// changed.
   ///
 
-  void RebuildAroundNode(CDasherNode *pNode);
+  void RebuildAroundCrosshair();
 
   ///
   /// Rebuild the parent of the current root - used during backing off
diff --git a/Src/DasherCore/DasherNode.cpp b/Src/DasherCore/DasherNode.cpp
index 0a3d220..f5301a9 100644
--- a/Src/DasherCore/DasherNode.cpp
+++ b/Src/DasherCore/DasherNode.cpp
@@ -98,14 +98,6 @@ void CDasherNode::Trace() const {
    */
 }
 
-bool CDasherNode::NodeIsParent(CDasherNode *oldnode) const {
-  if(oldnode == m_pParent)
-    return true;
-  else
-    return false;
-
-}
-
 void CDasherNode::GetContext(CDasherInterfaceBase *pInterface, vector<symbol> &vContextSymbols, int iOffset, int iLength) {
   if (!GetFlag(NF_SEEN)) {
     DASHER_ASSERT(m_pParent);
diff --git a/Src/DasherCore/DasherNode.h b/Src/DasherCore/DasherNode.h
index fd4e7da..4b0b06a 100644
--- a/Src/DasherCore/DasherNode.h
+++ b/Src/DasherCore/DasherNode.h
@@ -185,7 +185,6 @@ class Dasher::CDasherNode:private NoClones {
   inline unsigned int ChildCount() const;
   inline CDasherNode *Parent() const;
   void SetParent(CDasherNode *pNewParent); 
-  bool NodeIsParent(CDasherNode * oldnode) const;
   // TODO: Should this be here?
   CDasherNode *const Get_node_under(int, myint y1, myint y2, myint smousex, myint smousey);   // find node under given co-ords
   



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