[dasher: 18/27] Redo output handling, DasherView::Render returns node covering crosshair



commit 545796a25af8627785af0a42c5403735073e6be0
Author: Alan Lawrence <acl33 inf phy cam ac uk>
Date:   Sat Aug 14 18:56:02 2010 +0100

    Redo output handling, DasherView::Render returns node covering crosshair
    
    Implemented for rects, {trunc,}tris, circles.
    
    RecursiveOutput and HandleOutput combined into OutputTo, taking leaf as param

 Src/DasherCore/DasherModel.cpp      |   97 +++++++++++------------------------
 Src/DasherCore/DasherModel.h        |   22 +-------
 Src/DasherCore/DasherView.cpp       |    5 +-
 Src/DasherCore/DasherView.h         |   33 ++++++------
 Src/DasherCore/DasherViewSquare.cpp |   90 ++++++++++++++++++++++++---------
 Src/DasherCore/DasherViewSquare.h   |    9 ++--
 6 files changed, 123 insertions(+), 133 deletions(-)
---
diff --git a/Src/DasherCore/DasherModel.cpp b/Src/DasherCore/DasherModel.cpp
index 2ee0f95..d79c477 100644
--- a/Src/DasherCore/DasherModel.cpp
+++ b/Src/DasherCore/DasherModel.cpp
@@ -222,12 +222,6 @@ void CDasherModel::ClearRootQueue() {
   }
 }
 
-CDasherNode *CDasherModel::Get_node_under_crosshair() {
-  DASHER_ASSERT(m_Root != NULL);
-
-  return m_Root->Get_node_under(GetLongParameter(LP_NORMALIZATION), m_Rootmin + m_iDisplayOffset, m_Rootmax + m_iDisplayOffset, GetLongParameter(LP_OX), GetLongParameter(LP_OY));
-}
-
 void CDasherModel::SetOffset(int iOffset, CAlphabetManager *pMgr, CDasherView *pView, bool bForce) {
   //if we don't have a root, always "re"build the tree!
   // (if we have a root, only rebuild to move location or if bForce says to)
@@ -391,15 +385,6 @@ void CDasherModel::UpdateBounds(myint iNewMin, myint iNewMax, unsigned long iTim
 
   // Now actually zoom to the new location
   NewGoTo(iNewMin, iNewMax, pAdded, pNumDeleted);
-
-
-  // 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);
 }
 
 void CDasherModel::RecordFrame(unsigned long Time) {
@@ -410,27 +395,6 @@ void CDasherModel::RecordFrame(unsigned long Time) {
     pTeacher->NewFrame(Time);
 }
 
-void CDasherModel::RecursiveOutput(CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded) {
-  if(pNode->Parent()) {
-    if (!pNode->Parent()->GetFlag(NF_SEEN))
-      RecursiveOutput(pNode->Parent(), pAdded);
-
-    pNode->Parent()->Leave();
-  }
-  
-  pNode->Enter();
-  
-  m_pLastOutput = pNode;
-  pNode->SetFlag(NF_SEEN, true);
-  pNode->Output(pAdded, GetLongParameter(LP_NORMALIZATION));
-
-  // If the node we are outputting is the last one in a game target sentence, then
-  // notify the game mode teacher.
-  if(m_bGameMode)
-    if(pNode->GetFlag(NF_END_GAME))
-      GameMode::CDasherGameMode::GetTeacher()->SentenceFinished();
-}
-
 void CDasherModel::NewGoTo(myint newRootmin, myint newRootmax, Dasher::VECTOR_SYMBOL_PROB* pAdded, int* pNumDeleted) {
 
   // Update the max and min of the root node to make iTargetMin and
@@ -487,27 +451,35 @@ void CDasherModel::NewGoTo(myint newRootmin, myint newRootmax, Dasher::VECTOR_SY
   }
 }
 
-void CDasherModel::HandleOutput(Dasher::VECTOR_SYMBOL_PROB* pAdded, int* pNumDeleted) {
-  CDasherNode *pNewNode = Get_node_under_crosshair();
-  DASHER_ASSERT(pNewNode != NULL);
-  
-  //  std::cout << "HandleOutput: " << m_pLastOutput << " => " << pNewNode << std::endl;
-  
-  CDasherNode *pLastSeen = pNewNode;
-  while (pLastSeen && !pLastSeen->GetFlag(NF_SEEN))
-    pLastSeen = pLastSeen->Parent();
-  
-  while (m_pLastOutput != pLastSeen) {
-    m_pLastOutput->Undo(pNumDeleted);
-    m_pLastOutput->Leave(); //Should we? I think so, but the old code didn't...?
-    m_pLastOutput->SetFlag(NF_SEEN, false);
+void CDasherModel::OutputTo(CDasherNode *pNewNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int* pNumDeleted) {
+  //first, recurse back up to last seen node (must be processed ancestor-first)
+  if (pNewNode && !pNewNode->GetFlag(NF_SEEN)) {
+    OutputTo(pNewNode->Parent(), pAdded, pNumDeleted);
+    if (pNewNode->Parent()) pNewNode->Parent()->Leave();
+    pNewNode->Enter();
     
-    m_pLastOutput = m_pLastOutput->Parent();
-    if (m_pLastOutput) m_pLastOutput->Enter();
-  }
-  
-  if(!pNewNode->GetFlag(NF_SEEN)) {
-    RecursiveOutput(pNewNode, pAdded);
+    m_pLastOutput = pNewNode;
+    pNewNode->SetFlag(NF_SEEN, true);
+    pNewNode->Output(pAdded, GetLongParameter(LP_NORMALIZATION));
+    
+    // If the node we are outputting is the last one in a game target sentence, then
+    // notify the game mode teacher.
+    if(m_bGameMode)
+      if(pNewNode->GetFlag(NF_END_GAME))
+        GameMode::CDasherGameMode::GetTeacher()->SentenceFinished();
+  } else {
+    //either pNewNode is null, or else it's been seen. So delete back to that...
+    while (m_pLastOutput != pNewNode) {
+      // if pNewNode is null, m_pLastOutput is not; else, pNewNode has been seen,
+      // so we should encounter it on the way back out to the root, _before_ null
+      m_pLastOutput->Undo(pNumDeleted);
+      m_pLastOutput->Leave(); //Should we? I think so, but the old code didn't...?
+      m_pLastOutput->SetFlag(NF_SEEN, false);
+      
+      m_pLastOutput = m_pLastOutput->Parent();
+      if (m_pLastOutput) m_pLastOutput->Enter();
+      else DASHER_ASSERT (!pNewNode); //both null
+    }
   }
 }
 
@@ -566,13 +538,10 @@ void CDasherModel::RenderToView(CDasherView *pView, CExpansionPolicy &policy) {
   DASHER_ASSERT(pView != NULL);
   DASHER_ASSERT(m_Root != NULL);
 
-  // XXX we HandleOutput in RenderToView
-  // DASHER_ASSERT(Get_node_under_crosshair() == m_pLastOutput);
-
   // The Render routine will fill iGameTargetY with the Dasher Coordinate of the 
   // youngest node with NF_GAME set. The model is responsible for setting NF_GAME on
   // the appropriate Nodes.
-  pView->Render(m_Root, m_Rootmin + m_iDisplayOffset, m_Rootmax + m_iDisplayOffset, policy, true);  
+  CDasherNode *pOutput = pView->Render(m_Root, m_Rootmin + m_iDisplayOffset, m_Rootmax + m_iDisplayOffset, policy, true);  
 
   /////////GAME MODE TEMP//////////////
   if(m_bGameMode)
@@ -588,17 +557,13 @@ void CDasherModel::RenderToView(CDasherView *pView, CExpansionPolicy &policy) {
 
   // TODO: Fix up stats
   // TODO: Is this the right way to handle this?
-  HandleOutput(NULL, NULL);
+  OutputTo(pOutput, NULL, NULL);
 }
 
 bool CDasherModel::CheckForNewRoot(CDasherView *pView) {
   DASHER_ASSERT(m_Root != NULL);
   // TODO: pView is redundant here
 
-#ifdef DEBUG
-  CDasherNode *pOldNode = Get_node_under_crosshair();
-#endif
-
   if(!(m_Root->GetFlag(NF_SUPER))) {
     CDasherNode *root(m_Root);    
     Reparent_root();
@@ -622,8 +587,6 @@ bool CDasherModel::CheckForNewRoot(CDasherView *pView) {
     Make_root(pNewRoot);
   }
 
-  DASHER_ASSERT(Get_node_under_crosshair() == pOldNode);
-
   return false;
 }
 
diff --git a/Src/DasherCore/DasherModel.h b/Src/DasherCore/DasherModel.h
index f0050eb..4e20685 100644
--- a/Src/DasherCore/DasherModel.h
+++ b/Src/DasherCore/DasherModel.h
@@ -310,27 +310,11 @@ class Dasher::CDasherModel:public Dasher::CFrameRate, private NoClones
 
   void Reparent_root(); 
 
-  ///
-  /// Return a pointer to the Dasher node which is currently under the
-  /// crosshair. Used for output, and apparently needed for game mode.
-  ///
-
-  CDasherNode *Get_node_under_crosshair();    
-
-  ///
-  /// Output a node, which has not been seen (& first, any ancestors that haven't been seen either),
-  /// but which _is_ a descendant of m_pLastOutput.
-  ///
-  
-  void RecursiveOutput(CDasherNode *pNode, Dasher::VECTOR_SYMBOL_PROB* pAdded);
-  
-  ///
   /// Handle the output caused by a change in node over the crosshair. Specifically,
   /// deletes from m_pLastOutput back to closest ancestor of pNewNode,
-  /// then outputs from that ancestor to the node now under the crosshair (inclusively)
-  ///
-
-  void HandleOutput(Dasher::VECTOR_SYMBOL_PROB* pAdded, int* pNumDeleted);
+  /// then outputs from that ancestor to that node
+  /// @param pNewNode innermost node now covering the crosshair
+  void OutputTo(CDasherNode *pNewNode, Dasher::VECTOR_SYMBOL_PROB* pAdded, int* pNumDeleted);
 
 
   ///
diff --git a/Src/DasherCore/DasherView.cpp b/Src/DasherCore/DasherView.cpp
index fdde335..f9b9afe 100644
--- a/Src/DasherCore/DasherView.cpp
+++ b/Src/DasherCore/DasherView.cpp
@@ -22,7 +22,6 @@
 
 #include "DasherGameMode.h"
 #include "DasherInput.h"
-#include "DasherModel.h"
 #include "DasherView.h"
 #include "Event.h"
 #include "EventHandler.h"
@@ -56,11 +55,11 @@ void CDasherView::ChangeScreen(CDasherScreen *NewScreen) {
 
 /////////////////////////////////////////////////////////////////////////////
 
-void CDasherView::Render(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy, bool bRedrawDisplay) {
+CDasherNode *CDasherView::Render(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy, bool bRedrawDisplay) {
 
   m_iRenderCount = 0;
   Screen()->SetLoadBackground(false);
-  RenderNodes(pRoot, iRootMin, iRootMax, policy);
+  return RenderNodes(pRoot, iRootMin, iRootMax, policy);
 }
 
 int CDasherView::GetCoordinateCount() {
diff --git a/Src/DasherCore/DasherView.h b/Src/DasherCore/DasherView.h
index ba7a276..b7b40f7 100644
--- a/Src/DasherCore/DasherView.h
+++ b/Src/DasherCore/DasherView.h
@@ -6,7 +6,6 @@
 #define __DasherView_h_
 
 namespace Dasher {
-  class CDasherModel;
   class CDasherInput; // Why does DasherView care about input? - pconlon
   class CDasherComponent;
   class CDasherView;
@@ -23,7 +22,7 @@ namespace Dasher {
 
 /// \brief View base class.
 ///
-/// Dasher views represent the visualisation of a Dasher model on the screen.
+/// Dasher views render the tree of Dasher nodes onto a screen.
 ///
 /// Note that we really should aim to avoid having to try and keep
 /// multiple pointers to the same object (model etc.) up-to-date at
@@ -34,13 +33,6 @@ namespace Dasher {
 /// notifying this object every time it changes. The same logic can be
 /// applied in several other places.
 ///
-/// We should also attempt to try and remove the need for this class
-/// to know about the model. When we call render we should just pass a
-/// pointer to the root node, which we can obtain elsewhere, and make
-/// sure that the data structure contains all the info we need to do
-/// the rendering (eg make sure it contains strings as well as symbol
-/// IDs).
-///
 /// There are really three roles played by CDasherView: providing high
 /// level drawing functions, providing a mapping between Dasher
 /// co-ordinates and screen co-ordinates and providing a mapping
@@ -70,8 +62,7 @@ public:
   void SetInput(CDasherInput * _pInput);
   void SetDemoMode(bool);
   void SetGameMode(bool);
-  /// Translates the screen coordinates to Dasher coordinates and calls
-  /// dashermodel.TapOnDisplay
+  /// Translates the screen coordinates to Dasher coordinates
   virtual int GetCoordinates(myint &iDasherX, myint &iDasherY);
 
   
@@ -119,9 +110,18 @@ public:
   /// Drawing more complex structures, generally implemented by derived class
   /// @{
 
-  /// Renders Dasher with mouse-dependent items
-  /// \todo Clarify relationship between Render functions and probably only expose one
-  virtual void Render(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy, bool bRedrawDisplay);
+  /// Top-level/public render function - renders all nodes.
+  /// TODO the difference between this and RenderNodes (which gets implemented
+  /// by subclasses) seems to be only that (a) this one sets m_iRenderCount to 0;
+  /// since m_iRenderCount is then only incremented by subclasses, should it
+  /// really be a field of CDasherView at all? and (b) it calls Screen()->SetLoadBackground(true)
+  /// first - a method/call which exists only for Gtk2/CanvasExperimental.{h,cpp}...
+  /// note the experimental, I doubt it works, or tbh whether it's worth making it...!
+  /// @param pRoot outermost node to render. should cover screen if possible;
+  /// function will blank out around it (in white) if not
+  /// @param bRedrawDisplay ignored; purpose unclear - also TODO...
+  /// @return the innermost node covering the crosshair
+  CDasherNode *Render(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy, bool bRedrawDisplay);
 
   /// @}
 
@@ -197,8 +197,9 @@ private:
   CDasherScreen *m_pScreen;    // provides the graphics (text, lines, rectangles):
   CDasherInput *m_pInput;       // Input device abstraction
 
-  /// Renders the Dasher node structure
-  virtual void RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy) = 0;
+  /// Renders the Dasher node structure, including blanking out around the root node if necessary
+  /// @return the innermost node covering the crosshair
+  virtual CDasherNode *RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy) = 0;
 
 
   /// Get the co-ordinates from the input device
diff --git a/Src/DasherCore/DasherViewSquare.cpp b/Src/DasherCore/DasherViewSquare.cpp
index e4c00d1..dfb7fa7 100644
--- a/Src/DasherCore/DasherViewSquare.cpp
+++ b/Src/DasherCore/DasherViewSquare.cpp
@@ -95,7 +95,7 @@ void CDasherViewSquare::HandleEvent(Dasher::CEvent *pEvent) {
   }
 }
 
-void CDasherViewSquare::RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax,
+CDasherNode *CDasherViewSquare::RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax,
 				    CExpansionPolicy &policy) {
   DASHER_ASSERT(pRoot != 0);
   myint iDasherMinX;
@@ -114,25 +114,26 @@ void CDasherViewSquare::RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iR
   Dasher2Screen(0, iRootMax, iScreenRight, iScreenBottom);
 
   // Blank the region around the root node:
+  if (GetLongParameter(LP_SHAPE_TYPE)==0) { //disjoint rects, so go round root
+    if(iRootMin > iDasherMinY)
+      DasherDrawRectangle(iDasherMaxX, iDasherMinY, iDasherMinX, iRootMin, 0, -1, Nodes1, 0);
   
-  if(iRootMin > iDasherMinY)
-    DasherDrawRectangle(iDasherMaxX, iDasherMinY, iDasherMinX, iRootMin, 0, -1, Nodes1, 0);
-  
-  if(iRootMax < iDasherMaxY)
-    DasherDrawRectangle(iDasherMaxX, iRootMax, iDasherMinX, iDasherMaxY, 0, -1, Nodes1, 0);
-
-  //to left (greater Dasher X)
-  if (iRootMax - iRootMin < iDasherMaxX)
-    DasherDrawRectangle(iDasherMaxX, std::max(iRootMin,iDasherMinY), iRootMax-iRootMin, std::min(iRootMax,iDasherMaxY), 0, -1, Nodes1, 0);
+    if(iRootMax < iDasherMaxY)
+      DasherDrawRectangle(iDasherMaxX, iRootMax, iDasherMinX, iDasherMaxY, 0, -1, Nodes1, 0);
 
-  //to right (margin)
-  DasherDrawRectangle(0, iDasherMinY, iDasherMinX, iDasherMaxY, 0, -1, Nodes1, 0);
-  //  Screen()->DrawRectangle(iScreenRight, std::max(0, (int)iScreenTop),
-  //		  Screen()->GetWidth(), std::min(Screen()->GetHeight(), (int)iScreenBottom), 
-  //		  0, -1, Nodes1, false, true, 1);
+    //to left (greater Dasher X)
+    if (iRootMax - iRootMin < iDasherMaxX)
+      DasherDrawRectangle(iDasherMaxX, std::max(iRootMin,iDasherMinY), iRootMax-iRootMin, std::min(iRootMax,iDasherMaxY), 0, -1, Nodes1, 0);
 
+    //to right (margin)
+    DasherDrawRectangle(0, iDasherMinY, iDasherMinX, iDasherMaxY, 0, -1, Nodes1, 0);
+  } else {
+    //overlapping rects/shapes
+    Screen()->DrawRectangle(0, 0, Screen()->GetWidth(), Screen()->GetHeight(), 0, -1, Nodes1, 0);
+  }
   // Render the root node (and children)
-  RecursiveRender(pRoot, iRootMin, iRootMax, NULL, policy, std::numeric_limits<double>::infinity(), 0);
+  CDasherNode *pOutput = pRoot->Parent();
+  RecursiveRender(pRoot, iRootMin, iRootMax, NULL, policy, std::numeric_limits<double>::infinity(), 0, pOutput);
 
   // Labels are drawn in a second parse to get the overlapping right
   for (vector<CTextString *>::iterator it=m_DelayedTexts.begin(), E=m_DelayedTexts.end(); it!=E; it++)
@@ -141,6 +142,7 @@ void CDasherViewSquare::RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iR
   
   // Finally decorate the view
   Crosshair((myint)GetLongParameter(LP_OX));
+  return pOutput;
 }
 
 /// Draw text specified in Dasher co-ordinates. The position is
@@ -462,7 +464,7 @@ bool CDasherViewSquare::IsSpaceAroundNode(myint y1, myint y2) {
 
 void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2,
 					CTextString *pPrevText, CExpansionPolicy &policy, double dMaxCost,
-					int parent_color)
+					int parent_color, CDasherNode *&pOutput)
 {
   DASHER_ASSERT_VALIDPTR_RW(pRender);
   
@@ -515,16 +517,57 @@ void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2
     }
   }
   
+  //Does node cover crosshair? (quick reject)
+  if (pOutput == pRender->Parent() && Range > GetLongParameter(LP_OX) && y1 < GetLongParameter(LP_OY) && y2 > GetLongParameter(LP_OY)) {
+    bool bCovers;
+    switch (GetLongParameter(LP_SHAPE_TYPE)) {
+      case 0: case 1: //Rectangles
+        bCovers = true;
+        break;
+      case 2: {       //Triangles
+        myint iMidY((y1+y2)/2);
+        bCovers = (iMidY > GetLongParameter(LP_OY))
+          ? ((GetLongParameter(LP_OY)-y1)*Range) > (iMidY - y1) * GetLongParameter(LP_OX)
+          : ((y2-GetLongParameter(LP_OY))*Range) > (y2 - iMidY) * GetLongParameter(LP_OX);
+        break;
+      }
+      case 3: {       //Truncated tris
+        myint midy1((y1+y1+y2)/3), midy2((y1+y2+y2)/3);
+        if (midy1 > GetLongParameter(LP_OY)) //(0,y1) - (Range,midy1)
+          bCovers = (GetLongParameter(LP_OY)-y1)*Range > (midy1 - y1) * GetLongParameter(LP_OX);
+        else if (midy2 > GetLongParameter(LP_OY)) // (Range,midy1) - (Range,midy2)
+          bCovers = true;
+        else
+          bCovers = (y2 - GetLongParameter(LP_OY))*Range > (y2 - midy2) * GetLongParameter(LP_OX);
+        break;
+      }
+      case 4: //quadrics. We'll approximate with circles, as they're easier...
+        // however, note that the circle is bigger, so this'll output things
+        // too soon/aggressively :-(.
+        // (hence, fallthrough to:)
+      case 5: { //circles - actually ellipses, as x diameter is twice y diameter, hence the *4 
+        const myint y_dist(GetLongParameter(LP_OY) - (y1+y2)/2);
+        bCovers = GetLongParameter(LP_OX) * GetLongParameter(LP_OX) + y_dist*y_dist*4 < Range*Range;
+      }
+    }
+    if (bCovers) pOutput = pRender;
+  }
+  
   if (pRender->ChildCount() == 0) {
-    //allow empty node to be expanded, it's big enough.
-	  policy.pushNode(pRender, y1, y2, true, dMaxCost);
+    if (pOutput==pRender) {
+      //covers crosshair! forcibly populate, now!
+      pRender->PopulateChildren(); //TODO we are bypassing rest of CDasherModel::ExpandNode...
+      pRender->SetFlag(NF_ALLCHILDREN, true);
+    } else //allow empty node to be expanded, it's big enough.
+      policy.pushNode(pRender, y1, y2, true, dMaxCost);
+    
     //fall through to draw outline
   } else {
     //Node has children. It can therefore be collapsed...however,
     // we don't allow a node covering the crosshair to be collapsed
     // (at best this'll mean there's nowhere useful to go forwards;
     // at worst, all kinds of crashes trying to do text output!)
-    if (!pRender->GetFlag(NF_GAME) && !pRender->GetFlag(NF_SEEN))
+    if (!pRender->GetFlag(NF_GAME) && pRender != pOutput)
       dMaxCost = policy.pushNode(pRender, y1, y2, false, dMaxCost);
     
     // Render children  
@@ -545,8 +588,7 @@ void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2
           if (newy2-newy1 < iDasherMaxX)
             DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(y1,iDasherMinY), newy2-newy1, std::min(y2,iDasherMaxY), myColor, -1, Nodes1, 0);
         RecursiveRender(pChild, newy1, newy2, pPrevText, 
-                        policy, dMaxCost,
-                        myColor);
+                        policy, dMaxCost, myColor, pOutput);
         //leave pRender->onlyChildRendered set, so remaining children are skipped
       }
       else
@@ -568,7 +610,7 @@ void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2
           pRender->onlyChildRendered = pChild;
           if (newy2-newy1 < iDasherMaxX)
             DasherDrawRectangle(std::min(Range,iDasherMaxX), std::max(y1,iDasherMinY), newy2-newy1, std::min(y2,iDasherMaxY), myColor, -1, Nodes1, 0);
-          RecursiveRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor);
+          RecursiveRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor, pOutput);
           //ensure we don't blank over this child in "finishing off" the parent (!)
           lasty=newy2;
           break; //no need to render any more children!
@@ -587,7 +629,7 @@ void CDasherViewSquare::RecursiveRender(CDasherNode *pRender, myint y1, myint y2
             }
             lasty = newy2;
           }
-          RecursiveRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor); 
+          RecursiveRender(pChild, newy1, newy2, pPrevText, policy, dMaxCost, myColor, pOutput);
         } else {
           // We get here if the node is too small to render or is off-screen.
           // So, collapse it immediately.
diff --git a/Src/DasherCore/DasherViewSquare.h b/Src/DasherCore/DasherViewSquare.h
index da37c67..0962a71 100644
--- a/Src/DasherCore/DasherViewSquare.h
+++ b/Src/DasherCore/DasherViewSquare.h
@@ -140,12 +140,13 @@ private:
   ///
   /// Render the current state of the model.
   ///
-  virtual void RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy);
+  virtual CDasherNode *RenderNodes(CDasherNode *pRoot, myint iRootMin, myint iRootMax, CExpansionPolicy &policy);
   
   ///
-  /// (Recursively) render a node and all contained subnodes. Responsible for rendering exactly the area contained within the node.
-  ///
-  void RecursiveRender(CDasherNode * Render, myint y1, myint y2, CTextString *prevText, CExpansionPolicy &policy, double dMaxCost,int parent_color);
+  /// (Recursively) render a node and all contained subnodes. Responsible
+  /// for rendering exactly the area contained within the node.
+  /// @param pOutput The innermost node covering the crosshair (if any)
+  void RecursiveRender(CDasherNode * Render, myint y1, myint y2, CTextString *prevText, CExpansionPolicy &policy, double dMaxCost,int parent_color, CDasherNode *&pOutput);
 
 #ifdef _WIN32
   ///



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