diff --git starmath/inc/node.hxx starmath/inc/node.hxx index dabb503..25509e1 100644 --- starmath/inc/node.hxx +++ starmath/inc/node.hxx @@ -31,6 +31,23 @@ #include +#include +#include +#include + +//Jonas' special assert function, that doesn't stop execution... +#define j_assert(cond, msg) do{ \ + if(!(cond)){ \ + std::cerr<<"Failed assertion: "< SmNodeArray; typedef std::vector< SmStructureNode * > SmStructureNodeArray; @@ -97,6 +116,9 @@ class SmNode : public SmRect nAttributes; BOOL bIsPhantom, bIsDebug; + + /** parent of this node or NULL if root */ + SmNode * aParentNode; protected: SmNode(SmNodeType eNodeType, const SmToken &rNodeToken); @@ -180,6 +202,44 @@ public: const SmNode * FindTokenAt(USHORT nRow, USHORT nCol) const; const SmNode * FindRectClosestTo(const Point &rPoint) const; + + /** Get the parent SmNode of this node or NULL if this is the root node */ + SmNode * GetParent() { + j_assert(aParentNode || GetType() == NTABLE, "parent must be set or this should have type NROOT"); + return aParentNode; + } + /** Set the parent of this node, should be set if this is not the root */ + void SetParent(SmNode* parent) { aParentNode = parent; } + + /** The tree as dot graph for graphviz, usable for debugging + Convert the output to a image using $ dot graph.gv -Tpng > graph.png + */ + void DumpAsDot(std::ostream &out, String* label = NULL, int number = -1) const; + + /** Takes the first child, or NextOutOf this */ + SmCaretPos IntoNext(); + /** Takes the last child, or PrevOutOf this */ + SmCaretPos IntoPrev(); + + /** Accept a visitor + * @remarks This method is left abstract to ensure that classes that doesn't implement + * this will never be instantiated. + */ + virtual void accept(SmVisitor* pVisitor); +private: + /** Takes the next child of the parent, or takes the NextOutOf the parent */ + SmCaretPos NextOutOf(); + /** Takes the previous child of the parent, or takes the PrevOutOf the parent */ + SmCaretPos PrevOutOf(); +protected: + /** Assign this node as parent to its subnodes */ + void ClaimPaternity(){ + SmNode *pNode; + USHORT nSize = GetNumSubNodes(); + for (USHORT i = 0; i < nSize; i++) + if (NULL != (pNode = GetSubNode(i))) + pNode->SetParent(this); + } }; @@ -266,7 +326,7 @@ public: virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); - + void accept(SmVisitor* pVisitor); #ifdef SM_RECT_DEBUG using SmRect::Draw; #endif @@ -294,7 +354,7 @@ public: virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); - + void accept(SmVisitor* pVisitor); #ifdef SM_RECT_DEBUG using SmRect::Draw; #endif @@ -324,6 +384,7 @@ public: nFontDesc = nFontDescP; } + void accept(SmVisitor* pVisitor); USHORT GetFontDesc() const { return nFontDesc; } void SetText(const XubString &rText) { aText = rText; } @@ -357,6 +418,7 @@ public: : SmTextNode(NSPECIAL, rNodeToken, FNT_MATH) //! default Font nicht immer richtig {} + void accept(SmVisitor* pVisitor); virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); @@ -377,6 +439,7 @@ public: : SmSpecialNode(NGLYPH_SPECIAL, rNodeToken, FNT_MATH) {} + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -398,6 +461,7 @@ protected: public: SmMathSymbolNode(const SmToken &rNodeToken); + void accept(SmVisitor* pVisitor); virtual void AdaptToX(const OutputDevice &rDev, ULONG nWidth); virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight); @@ -421,7 +485,7 @@ public: virtual void AdaptToX(const OutputDevice &rDev, ULONG nWidth); virtual void AdaptToY(const OutputDevice &rDev, ULONG nHeight); - + void accept(SmVisitor* pVisitor); #ifdef SM_RECT_DEBUG using SmRect::Draw; #endif @@ -440,6 +504,7 @@ public: { } + void accept(SmVisitor* pVisitor); virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -457,6 +522,7 @@ public: SetText((xub_Unicode) MS_ERROR); } + void accept(SmVisitor* pVisitor); virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -474,6 +540,7 @@ public: using SmNode::GetLeftMost; virtual SmNode * GetLeftMost(); + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -493,7 +560,7 @@ public: SmLineNode(const SmToken &rNodeToken) : SmStructureNode(NLINE, rNodeToken) {} - + void accept(SmVisitor* pVisitor); virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -508,7 +575,7 @@ public: SmExpressionNode(const SmToken &rNodeToken) : SmLineNode(NEXPRESSION, rNodeToken) {} - + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); void CreateTextFromNode(String &rText); }; @@ -525,7 +592,7 @@ public: { SetNumSubNodes(2); } - + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -546,7 +613,7 @@ public: { SetNumSubNodes(3); } - + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); void CreateTextFromNode(String &rText); }; @@ -563,7 +630,7 @@ public: { SetNumSubNodes(3); } - + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -582,7 +649,7 @@ public: using SmNode::GetLeftMost; virtual SmNode * GetLeftMost(); - + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); void CreateTextFromNode(String &rText); }; @@ -601,6 +668,7 @@ class SmBinDiagonalNode : public SmStructureNode public: SmBinDiagonalNode(const SmToken &rNodeToken); + void accept(SmVisitor* pVisitor); BOOL IsAscending() const { return bAscending; } void SetAscending(BOOL bVal) { bAscending = bVal; } @@ -646,6 +714,7 @@ public: bUseLimits = FALSE; } + void accept(SmVisitor* pVisitor); SmNode * GetBody() { return GetSubNode(0); } const SmNode * GetBody() const { @@ -674,6 +743,7 @@ public: { SetNumSubNodes(3); } + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); void CreateTextFromNode(String &rText); @@ -688,6 +758,7 @@ class SmBracebodyNode : public SmStructureNode long nBodyHeight; public: + void accept(SmVisitor* pVisitor); inline SmBracebodyNode(const SmToken &rNodeToken); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); @@ -711,6 +782,7 @@ public: inline SmVerticalBraceNode(const SmToken &rNodeToken); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); + void accept(SmVisitor* pVisitor); }; @@ -732,6 +804,7 @@ public: { SetNumSubNodes(2); } + void accept(SmVisitor* pVisitor); SmNode * GetSymbol(); const SmNode * GetSymbol() const @@ -754,7 +827,7 @@ public: SmAlignNode(const SmToken &rNodeToken) : SmStructureNode(NALIGN, rNodeToken) {} - + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; @@ -768,7 +841,7 @@ public: SmAttributNode(const SmToken &rNodeToken) : SmStructureNode(NATTRIBUT, rNodeToken) {} - + void accept(SmVisitor* pVisitor); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); void CreateTextFromNode(String &rText); }; @@ -790,6 +863,8 @@ public: aFontSize = Fraction(1L); } + void accept(SmVisitor* pVisitor); + void SetSizeParameter(const Fraction &rValue, USHORT nType); const Fraction & GetSizeParameter() const {return aFontSize;} const USHORT& GetSizeType() const {return nSizeType;} @@ -815,6 +890,7 @@ public: nNumRows = nNumCols = 0; } + void accept(SmVisitor* pVisitor); USHORT GetNumRows() const {return nNumRows;} USHORT GetNumCols() const {return nNumCols;} void SetRowCol(USHORT nMatrixRows, USHORT nMatrixCols); @@ -843,7 +919,7 @@ public: void IncreaseBy(const SmToken &rToken); void Clear() { nNum = 0; } - + void accept(SmVisitor* pVisitor); virtual void Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell); virtual void Arrange(const OutputDevice &rDev, const SmFormat &rFormat); }; diff --git starmath/inc/view.hxx starmath/inc/view.hxx index eab2444..d105e2d 100644 --- starmath/inc/view.hxx +++ starmath/inc/view.hxx @@ -47,10 +47,39 @@ class SmViewShell; /**************************************************************************/ +/** Representation of caret position with an equantion */ +struct SmCaretPos{ + SmCaretPos(SmNode* selectedNode = NULL, int iIndex = 0) { + pSelectedNode = selectedNode; + this->index = iIndex; + } + /** Selected node */ + SmNode* pSelectedNode; + /** Index within the selected node + * Used by the visitors for the nodes internally.. + */ + int index; //TODO: Use this later + /** True, if this is a valid caret position */ + bool IsValid() { return pSelectedNode != NULL; } + bool operator!=(SmCaretPos pos) const { + return pos.pSelectedNode != pSelectedNode || index != pos.index; + } +}; + +/**************************************************************************/ + class SmGraphicWindow : public ScrollableWindow { Point aFormulaDrawPos; Rectangle aCursorRect; + /** Current caret position */ + SmCaretPos aCaretPos; + Point caretPoint; //TODO: Remove this!!! + /** Equantion root node from when aCaretPos was last set, used to + * determine if a new tree have been created and thus the old SmCaretPos + * have been invalidated. E.g. may point to something really nasty!!! + */ + const SmNode *pLastTreeNode; ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > xAccessible; diff --git starmath/inc/visitors.hxx starmath/inc/visitors.hxx new file mode 100644 index 0000000..931137b --- /dev/null +++ starmath/inc/visitors.hxx @@ -0,0 +1,284 @@ +#ifndef SMVISITORS_H +#define SMVISITORS_H + +#include "node.hxx" +#include "view.hxx" + +/** Base class for visitors that visits a tree of SmNodes + * @remarks all methods have been left abstract to ensure that implementers + * don't forget to implement one. + */ +class SmVisitor{ +public: + virtual void visit(SmTableNode* node) = 0; + virtual void visit(SmBraceNode* node) = 0; + virtual void visit(SmBracebodyNode* node) = 0; + virtual void visit(SmOperNode* node) = 0; + virtual void visit(SmAlignNode* node) = 0; + virtual void visit(SmAttributNode* node) = 0; + virtual void visit(SmFontNode* node) = 0; + virtual void visit(SmUnHorNode* node) = 0; + virtual void visit(SmBinHorNode* node) = 0; + virtual void visit(SmBinVerNode* node) = 0; + virtual void visit(SmBinDiagonalNode* node) = 0; + virtual void visit(SmSubSupNode* node) = 0; + virtual void visit(SmMatrixNode* node) = 0; + virtual void visit(SmPlaceNode* node) = 0; + virtual void visit(SmTextNode* node) = 0; + virtual void visit(SmSpecialNode* node) = 0; + virtual void visit(SmGlyphSpecialNode* node) = 0; + virtual void visit(SmMathSymbolNode* node) = 0; + virtual void visit(SmBlankNode* node) = 0; + virtual void visit(SmErrorNode* node) = 0; + virtual void visit(SmLineNode* node) = 0; + virtual void visit(SmExpressionNode* node) = 0; + virtual void visit(SmPolyLineNode* node) = 0; + virtual void visit(SmRootNode* node) = 0; + virtual void visit(SmRootSymbolNode* node) = 0; + virtual void visit(SmRectangleNode* node) = 0; + virtual void visit(SmVerticalBraceNode* node) = 0; +}; + +/** Simple visitor for testing SmVisitor */ +class SmVisitorTest : public SmVisitor{ +public: + void visit(SmTableNode* node); + void visit(SmBraceNode* node); + void visit(SmBracebodyNode* node); + void visit(SmOperNode* node); + void visit(SmAlignNode* node); + void visit(SmAttributNode* node); + void visit(SmFontNode* node); + void visit(SmUnHorNode* node); + void visit(SmBinHorNode* node); + void visit(SmBinVerNode* node); + void visit(SmBinDiagonalNode* node); + void visit(SmSubSupNode* node); + void visit(SmMatrixNode* node); + void visit(SmPlaceNode* node); + void visit(SmTextNode* node); + void visit(SmSpecialNode* node); + void visit(SmGlyphSpecialNode* node); + void visit(SmMathSymbolNode* node); + void visit(SmBlankNode* node); + void visit(SmErrorNode* node); + void visit(SmLineNode* node); + void visit(SmExpressionNode* node); + void visit(SmPolyLineNode* node); + void visit(SmRootNode* node); + void visit(SmRootSymbolNode* node); + void visit(SmRectangleNode* node); + void visit(SmVerticalBraceNode* node); +private: + /** Auxiliary method for visiting the children of a node */ + void visitChildren(SmNode* node){ + SmNode *pNode; + USHORT nSize = node->GetNumSubNodes(); + for (USHORT i = 0; i < nSize; i++) + if (NULL != (pNode = node->GetSubNode(i))) + pNode->accept(this); + } +}; + +/** Abstract visitor for searching for a caret position + * @remarks Templates method canExclude() and suggest should be + * implemented in subclasses. + * This class works by suggestion all possibe caret position to the + * template method suggest() implement this method in concrete subclasses + * and save the proposal that you prefer. + */ +class SmCaretPosSearchVisitor : public SmVisitor{ +public: + void visit(SmTableNode* node); + void visit(SmBraceNode* node); + void visit(SmBracebodyNode* node); + void visit(SmOperNode* node); + void visit(SmAlignNode* node); + void visit(SmAttributNode* node); + void visit(SmFontNode* node); + void visit(SmUnHorNode* node); + void visit(SmBinHorNode* node); + void visit(SmBinVerNode* node); + void visit(SmBinDiagonalNode* node); + void visit(SmSubSupNode* node); + void visit(SmMatrixNode* node); + void visit(SmPlaceNode* node); + void visit(SmTextNode* node); + void visit(SmSpecialNode* node); + void visit(SmGlyphSpecialNode* node); + void visit(SmMathSymbolNode* node); + void visit(SmBlankNode* node); + void visit(SmErrorNode* node); + void visit(SmLineNode* node); + void visit(SmExpressionNode* node); + void visit(SmPolyLineNode* node); + void visit(SmRootNode* node); + void visit(SmRootSymbolNode* node); + void visit(SmRectangleNode* node); + void visit(SmVerticalBraceNode* node); +private: + /** Can any proposals within rect be excluded from the search ? + * @remarks All structure nodes will test this before offering suggestions + * from either itself or its children. And will ofcourse not offer + * suggestions if it can be excluded. + * Default implementation returns false, e.g. no exclusions are performed. + */ + virtual bool canExclude(SmRect* rect); + /** Suggests a caret position + * @param propsal The suggested SmCaretPos + * @param pos Actual position of the caret if proposal is chosen + */ + virtual void suggest(SmCaretPos proposal, Point pos) = 0; + + /** Default implementation for nodes + * Later a more specific implementation is needed for most nodes. + * this is just a quick hack to test the approach! + */ + inline void defaultVisit(SmNode* node){ + if(node->IsVisible()){ + j_assert(node->GetNumSubNodes() == 0, "Visible nodes shouldn't have children!"); + suggest(SmCaretPos(node), node->GetCenter()); //Move away from using center when going to beam caret + }else if(!canExclude(node)){ + SmNode *pNode; + USHORT nSize = node->GetNumSubNodes(); + for (USHORT i = 0; i < nSize; i++) + if (NULL != (pNode = node->GetSubNode(i))) + pNode->accept(this); + } + } +}; + +/** Searches for a position left of the given position */ +class SmLeftCaretPosSearchVisitor : public SmCaretPosSearchVisitor{ +public: + SmLeftCaretPosSearchVisitor(SmCaretPos from_, Point pos, SmNode* tree) { + this->from = from_; + from_pos = pos; + tree->accept(this); + } + SmCaretPos result(){ + return best; + } + Point resultPos(){ + return best_pos; + } +private: + SmCaretPos from; + Point from_pos; + SmCaretPos best; + Point best_pos; + //TODO: Implement: bool canExclude(SmRect* rect); + void suggest(SmCaretPos proposal, Point pos); +}; + +/** Searches for a position right of the given position */ +class SmRightCaretPosSearchVisitor : public SmCaretPosSearchVisitor{ +public: + SmRightCaretPosSearchVisitor(SmCaretPos from_, Point pos, SmNode* tree) { + this->from = from_; + from_pos = pos; + tree->accept(this); + } + SmCaretPos result(){ + return best; + } + Point resultPos(){ + return best_pos; + } +private: + SmCaretPos from; + Point from_pos; + SmCaretPos best; + Point best_pos; + //TODO: Implement: bool canExclude(SmRect* rect); + void suggest(SmCaretPos proposal, Point pos); +}; + +/** Searches for a position above of the given position */ +class SmUpCaretPosSearchVisitor : public SmCaretPosSearchVisitor{ +public: + SmUpCaretPosSearchVisitor(SmCaretPos from_, Point pos, SmNode* tree) { + this->from = from_; + from_pos = pos; + tree->accept(this); + } + SmCaretPos result(){ + return best; + } + Point resultPos(){ + return best_pos; + } +private: + SmCaretPos from; + Point from_pos; + SmCaretPos best; + Point best_pos; + //TODO: Implement: bool canExclude(SmRect* rect); + void suggest(SmCaretPos proposal, Point pos); +}; + +/** Searches for a position below of the given position */ +class SmDownCaretPosSearchVisitor : public SmCaretPosSearchVisitor{ +public: + SmDownCaretPosSearchVisitor(SmCaretPos from_, Point pos, SmNode* tree) { + this->from = from_; + from_pos = pos; + tree->accept(this); + } + SmCaretPos result(){ + return best; + } + Point resultPos(){ + return best_pos; + } +private: + SmCaretPos from; + Point from_pos; + SmCaretPos best; + Point best_pos; + //TODO: Implement: bool canExclude(SmRect* rect); + void suggest(SmCaretPos proposal, Point pos); +}; + +//TODO: Implement SmCaretPosDrawingVisitor +//TODO: Implement SmCaretPos2PointVisitor, for conversation from SmCaretPos to Point + +///////////////////////////////// Initial approach /////////////////////////////////// + +class SmMoveLeftVisitor : public SmVisitor { +public: + SmCaretPos result(){ return pCaret; } + void visit(SmTableNode* node); + void visit(SmBraceNode* node); + void visit(SmBracebodyNode* node); + void visit(SmOperNode* node); + void visit(SmAlignNode* node); + void visit(SmAttributNode* node); + void visit(SmFontNode* node); + void visit(SmUnHorNode* node); + void visit(SmBinHorNode* node); + void visit(SmBinVerNode* node); + void visit(SmBinDiagonalNode* node); + void visit(SmSubSupNode* node); + void visit(SmMatrixNode* node); + void visit(SmPlaceNode* node); + void visit(SmTextNode* node); + void visit(SmSpecialNode* node); + void visit(SmGlyphSpecialNode* node); + void visit(SmMathSymbolNode* node); + void visit(SmBlankNode* node); + void visit(SmErrorNode* node); + void visit(SmLineNode* node); + void visit(SmExpressionNode* node); + void visit(SmPolyLineNode* node); + void visit(SmRootNode* node); + void visit(SmRootSymbolNode* node); + void visit(SmRectangleNode* node); + void visit(SmVerticalBraceNode* node); +private: + /** Parameters and return value */ + SmCaretPos pCaret; //TODO: Rename this !!! +}; + + +#endif /* SMVISITORS_H */ diff --git starmath/source/edit.cxx starmath/source/edit.cxx index 1994271..3535c83 100644 --- starmath/source/edit.cxx +++ starmath/source/edit.cxx @@ -262,8 +262,8 @@ IMPL_LINK(SmEditWindow, CursorMoveTimerHdl, Timer *, EMPTYARG /*pTimer*/) // every once in a while check cursor position (selection) of edit // window and if it has changed (try to) set the formula-cursor // according to that. -{ - ESelection aNewSelection (GetSelection()); +{ //TODO: remove this dirty crap: + /*ESelection aNewSelection (GetSelection()); if (!aNewSelection.IsEqual(aOldSelection)) { SmViewShell *pView = rCmdBox.GetView(); @@ -280,7 +280,7 @@ IMPL_LINK(SmEditWindow, CursorMoveTimerHdl, Timer *, EMPTYARG /*pTimer*/) aOldSelection = aNewSelection; } - } + }*/ return 0; } diff --git starmath/source/makefile.mk starmath/source/makefile.mk index 912e6e6..c1763f0 100644 --- starmath/source/makefile.mk +++ starmath/source/makefile.mk @@ -63,6 +63,7 @@ SLO1FILES = \ $(SLO)$/mathmlexport.obj \ $(SLO)$/format.obj \ $(SLO)$/node.obj \ + $(SLO)$/visitors.obj \ $(SLO)$/parse.obj \ $(SLO)$/utility.obj \ $(SLO)$/smdll.obj \ diff --git starmath/source/node.cxx starmath/source/node.cxx index b243ced..07b0e1f 100644 --- starmath/source/node.cxx +++ starmath/source/node.cxx @@ -40,6 +40,7 @@ #include "node.hxx" +#include "visitors.hxx" #include #include "symbol.hxx" #include "smmod.hxx" @@ -51,6 +52,7 @@ #include #include +#include // define this to draw rectangles for debugging //#define SM_RECT_DEBUG @@ -144,6 +146,15 @@ SmNode::SmNode(SmNodeType eNodeType, const SmToken &rNodeToken) eScaleMode = SCALE_NONE; aNodeToken = rNodeToken; nAccIndex = -1; + /* This is only valid if eType == NROOT, but will be set later. + Ideally this should be done using constructors in the parser, + however this would require large rewrite and who knows what + effect this would have on import/export stuff... So modifying + SmStructureNode where nodes can aquire subnodes is probably easier. + I even doubt doing this in the parser using the constructor would + be easy... + */ + aParentNode = NULL; } @@ -570,6 +581,275 @@ const SmNode * SmNode::FindNodeWithAccessibleIndex(xub_StrLen nAccIdx) const return pResult; } +void SmNode::DumpAsDot(std::ostream &out, String* label, int number) const +{ + //If this is the root start the file + if(number == -1){ + out<<"digraph {"< n"< n"<GetText(), RTL_TEXTENCODING_UTF8).GetBuffer(); + break; + case NSPECIAL: out<<"SmSpecialNode"; break; + case NGLYPH_SPECIAL: out<<"SmGlyphSpecialNode"; break; + case NMATH: + out<<"SmMathSymbolNode: "; + out<< ByteString( ((SmMathSymbolNode*)this)->GetText(), RTL_TEXTENCODING_UTF8).GetBuffer(); + break; + case NBLANK: out<<"SmBlankNode"; break; + case NERROR: out<<"SmErrorNode"; break; + case NLINE: out<<"SmLineNode"; break; + case NEXPRESSION: out<<"SmExpressionNode"; break; + case NPOLYLINE: out<<"SmPolyLineNode"; break; + case NROOT: out<<"SmRootNode"; break; + case NROOTSYMBOL: out<<"SmRootSymbolNode"; break; + case NRECTANGLE: out<<"SmRectangleNode"; break; + case NVERTICAL_BRACE: out<<"SmVerticalBraceNode"; break; + default: + out<<"Unknown Node"; + } + out<<"\"];"<DumpAsDot(out, NULL, i); + + //If this is the root end the file + if( number == -1 ) + out<<"}"<GetNumSubNodes(); + for (USHORT i = 0; i < nSize; i++) + if (NULL != (pNode = GetParent()->GetSubNode(i))) { + if (pNode == this) + metThis = true; + else if (metThis) + return SmCaretPos((SmNode*)pNode); + } + j_assert(metThis, "Didn't meet this!"); + return GetParent()->NextOutOf(); +} + +//Takes the last child, or PrevOutOf this +SmCaretPos SmNode::IntoPrev(){ + const SmNode *prevNode = NULL; + const SmNode *pNode; + USHORT nSize = GetParent()->GetNumSubNodes(); + for (USHORT i = 0; i < nSize; i++) + if (NULL != (pNode = GetParent()->GetSubNode(i))) + prevNode = pNode; + + if(prevNode) + return SmCaretPos((SmNode*)prevNode); + + return PrevOutOf(); +} +//Takes the previous child of the parent, or takes the PrevOutOf the parent +SmCaretPos SmNode::PrevOutOf(){ + if(!GetParent()) + return SmCaretPos(this); + + const SmNode *prevNode = NULL; + const SmNode *pNode; + USHORT nSize = GetParent()->GetNumSubNodes(); + for (USHORT i = 0; i < nSize; i++) + if (NULL != (pNode = GetParent()->GetSubNode(i))) { + if (pNode == this && prevNode) + return SmCaretPos((SmNode*)prevNode); + else if(pNode == this) + break; + prevNode = pNode; + } + j_assert(!prevNode, "prevNode shouldn't be NULL"); + return GetParent()->PrevOutOf(); +} + +void SmNode::accept(SmVisitor* pVisitor){ + j_assert(false, "This is really bad!!!"); +} + +/////////////////////////////////////////////////////////////////////////// +//Implementation of all accept methods for visitor + +void SmTableNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmBraceNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmBracebodyNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmOperNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmAlignNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmAttributNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmFontNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmUnHorNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmBinHorNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmBinVerNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmBinDiagonalNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmSubSupNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmMatrixNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmPlaceNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmTextNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmSpecialNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmGlyphSpecialNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmMathSymbolNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmBlankNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmErrorNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmLineNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmExpressionNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmPolyLineNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmRootNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmRootSymbolNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmRectangleNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + +void SmVerticalBraceNode::accept(SmVisitor* aVisitor) { + aVisitor->visit(this); +} + /////////////////////////////////////////////////////////////////////////// SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) : @@ -616,6 +896,8 @@ SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode ) SmNode *pNode = rNode.aSubNodes[i]; aSubNodes[i] = pNode ? new SmNode( *pNode ) : 0; } + //We've got new subnodes, assign this a parent to them + ClaimPaternity(); return *this; } @@ -631,12 +913,16 @@ void SmStructureNode::SetSubNodes(SmNode *pFirst, SmNode *pSecond, SmNode *pThir aSubNodes[1] = pSecond; if (pThird) aSubNodes[2] = pThird; + //We've got new subnodes, assign this a parent to them + ClaimPaternity(); } void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray) { aSubNodes = rNodeArray; + //We've got new subnodes, assign this a parent to them + ClaimPaternity(); } diff --git starmath/source/view.cxx starmath/source/view.cxx index f00036f..5449e28 100644 --- starmath/source/view.cxx +++ starmath/source/view.cxx @@ -178,6 +178,13 @@ void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt) if (pTree->OrientedDist(aPos) <= 0) pNode = pTree->FindRectClosestTo(aPos); + if(pNode){ + aCaretPos.pSelectedNode = (SmNode*)pNode; //Discard const :) + pLastTreeNode = pTree; + SetCursor(aCaretPos.pSelectedNode); + caretPoint = pNode->GetCenter(); + } +/* if (pNode) { SmEditWindow *pEdit = pViewShell->GetEditWindow(); const SmToken aToken (pNode->GetToken()); @@ -208,9 +215,11 @@ void SmGraphicWindow::MouseButtonDown(const MouseEvent& rMEvt) // allow for immediate editing and //! implicitly synchronize the cursor position mark in this window - pEdit->GrabFocus(); - } + //pEdit->GrabFocus(); //Disabled with patch for visual editing... + }*/ } + //Let this controller grab focus... So now we get keyinput + GrabFocus(); } void SmGraphicWindow::GetFocus() @@ -316,6 +325,11 @@ void SmGraphicWindow::Paint(const Rectangle&) SetIsCursorVisible(FALSE); // (old) cursor must be drawn again + //Paint if tree haven't changed and we've got a legal position + if(pLastTreeNode == rDoc.GetFormulaTree() && aCaretPos.IsValid()) + SetCursor(aCaretPos.pSelectedNode); + + /* Disable old cursor synchronization const SmEditWindow *pEdit = pViewShell->GetEditWindow(); if (pEdit) { // get new position for formula-cursor (for possible altered formula) @@ -328,7 +342,7 @@ void SmGraphicWindow::Paint(const Rectangle&) SmModule *pp = SM_MOD1(); if (pFound && pp->GetConfig()->IsShowFormulaCursor()) ShowCursor(TRUE); - } + }*/ } @@ -340,11 +354,101 @@ void SmGraphicWindow::SetTotalSize () ScrollableWindow::SetTotalSize( aTmp ); } +#include +#include +#include "visitors.hxx" void SmGraphicWindow::KeyInput(const KeyEvent& rKEvt) { - if (! (GetView() && GetView()->KeyInput(rKEvt)) ) - ScrollableWindow::KeyInput(rKEvt); + USHORT nCode = rKEvt.GetKeyCode().GetCode(); + + //For more keycodes see: http://docs.go-oo.org/vcl/html/keycodes_8hxx.html + switch(nCode){ + case KEY_ESCAPE:{ + SmVisitorTest* aTest = new SmVisitorTest(); + ((SmNode*)pViewShell->GetDoc()->GetFormulaTree())->accept(aTest); + j_assert(false, "visitor tested"); + }break; + case KEY_RETURN:{ + //Open stream... + std::fstream file("/tmp/smath-dump.gv", std::fstream::out); + //Dump the tree on enter + const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree(); + String label(pViewShell->GetDoc()->GetText()); + pTree->DumpAsDot(file, &label); + file.flush(); + file.close(); + }break; + //Visual logical-predictable movement + case KEY_A:{ + SmNode *pTree = (SmNode*)pViewShell->GetDoc()->GetFormulaTree(); + if(pLastTreeNode == pTree && aCaretPos.pSelectedNode){ + SmMoveLeftVisitor v; + aCaretPos.pSelectedNode->accept(&v); + if(v.result().IsValid()){ + aCaretPos = v.result(); + caretPoint = aCaretPos.pSelectedNode->GetCenter(); + SetCursor(aCaretPos.pSelectedNode); + }else + j_assert(false, "no left found"); + } + }break; + //Visual non-logically-predictable movement + case KEY_LEFT:{ + SmNode *pTree = (SmNode*)pViewShell->GetDoc()->GetFormulaTree(); + SmLeftCaretPosSearchVisitor v(aCaretPos, caretPoint, pTree); + if(v.result().IsValid()){ + aCaretPos = v.result(); + caretPoint = v.resultPos(); + SetCursor(aCaretPos.pSelectedNode); + } + }break; + case KEY_RIGHT:{ + SmNode *pTree = (SmNode*)pViewShell->GetDoc()->GetFormulaTree(); + SmRightCaretPosSearchVisitor v(aCaretPos, caretPoint, pTree); + if(v.result().IsValid()){ + aCaretPos = v.result(); + caretPoint = v.resultPos(); + SetCursor(aCaretPos.pSelectedNode); + } + }break; + case KEY_UP:{ + SmNode *pTree = (SmNode*)pViewShell->GetDoc()->GetFormulaTree(); + SmUpCaretPosSearchVisitor v(aCaretPos, caretPoint, pTree); + if(v.result().IsValid()){ + aCaretPos = v.result(); + caretPoint = v.resultPos(); + SetCursor(aCaretPos.pSelectedNode); + } + }break; + case KEY_DOWN:{ + SmNode *pTree = (SmNode*)pViewShell->GetDoc()->GetFormulaTree(); + SmDownCaretPosSearchVisitor v(aCaretPos, caretPoint, pTree); + if(v.result().IsValid()){ + aCaretPos = v.result(); + caretPoint = v.resultPos(); + SetCursor(aCaretPos.pSelectedNode); + } + }break; + //Naive logically-predictable movement + /*case KEY_LEFT:{ + const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree(); + if(pLastTreeNode == pTree){ + aCaretPos = aCaretPos.pSelectedNode->IntoPrev(); + SetCursor(aCaretPos.pSelectedNode); + } + }break; + case KEY_RIGHT:{ + const SmNode *pTree = pViewShell->GetDoc()->GetFormulaTree(); + if(pLastTreeNode == pTree){ + aCaretPos = aCaretPos.pSelectedNode->IntoNext(); + SetCursor(aCaretPos.pSelectedNode); + } + }break;*/ + default: + if (! (GetView() && GetView()->KeyInput(rKEvt)) ) + ScrollableWindow::KeyInput(rKEvt); + } } diff --git starmath/source/visitors.cxx starmath/source/visitors.cxx new file mode 100644 index 0000000..fa25a65 --- /dev/null +++ starmath/source/visitors.cxx @@ -0,0 +1,954 @@ +#include "visitors.hxx" + +///////////////////////////////////// SmVisitorTest ///////////////////////////////////// + +void SmVisitorTest::visit(SmTableNode* node) { + j_assert(node->GetType() == NTABLE, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmBraceNode* node) { + j_assert(node->GetType() == NBRACE, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmBracebodyNode* node) { + j_assert(node->GetType() == NBRACEBODY, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmOperNode* node) { + j_assert(node->GetType() == NOPER, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmAlignNode* node) { + j_assert(node->GetType() == NALIGN, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmAttributNode* node) { + j_assert(node->GetType() == NATTRIBUT, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmFontNode* node) { + j_assert(node->GetType() == NFONT, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmUnHorNode* node) { + j_assert(node->GetType() == NUNHOR, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmBinHorNode* node) { + j_assert(node->GetType() == NBINHOR, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmBinVerNode* node) { + j_assert(node->GetType() == NBINVER, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmBinDiagonalNode* node) { + j_assert(node->GetType() == NBINDIAGONAL, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmSubSupNode* node) { + j_assert(node->GetType() == NSUBSUP, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmMatrixNode* node) { + j_assert(node->GetType() == NMATRIX, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmPlaceNode* node) { + j_assert(node->GetType() == NPLACE, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmTextNode* node) { + j_assert(node->GetType() == NTEXT, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmSpecialNode* node) { + j_assert(node->GetType() == NSPECIAL, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmGlyphSpecialNode* node) { + j_assert(node->GetType() == NGLYPH_SPECIAL, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmMathSymbolNode* node) { + j_assert(node->GetType() == NMATH, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmBlankNode* node) { + j_assert(node->GetType() == NBLANK, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmErrorNode* node) { + j_assert(node->GetType() == NERROR, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmLineNode* node) { + j_assert(node->GetType() == NLINE, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmExpressionNode* node) { + j_assert(node->GetType() == NEXPRESSION, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmPolyLineNode* node) { + j_assert(node->GetType() == NPOLYLINE, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmRootNode* node) { + j_assert(node->GetType() == NROOT, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmRootSymbolNode* node) { + j_assert(node->GetType() == NROOTSYMBOL, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmRectangleNode* node) { + j_assert(node->GetType() == NRECTANGLE, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +void SmVisitorTest::visit(SmVerticalBraceNode* node) { + j_assert(node->GetType() == NVERTICAL_BRACE, "the visitor-patterns isn't implemented correctly"); + visitChildren(node); +} + +///////////////////////////////////// SmCaretPosSearchVisitor ///////////////////////////////////// + +bool SmCaretPosSearchVisitor::canExclude(SmRect* rect) { + return false; +} + +void SmCaretPosSearchVisitor::visit(SmTableNode* node) { + defaultVisit(node); //Note these will be implemented less general later!!! +} + +void SmCaretPosSearchVisitor::visit(SmBraceNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmBracebodyNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmOperNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmAlignNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmAttributNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmFontNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmUnHorNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmBinHorNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmBinVerNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmBinDiagonalNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmSubSupNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmMatrixNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmPlaceNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmTextNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmSpecialNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmGlyphSpecialNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmMathSymbolNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmBlankNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmErrorNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmLineNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmExpressionNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmPolyLineNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmRootNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmRootSymbolNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmRectangleNode* node) { + defaultVisit(node); +} + +void SmCaretPosSearchVisitor::visit(SmVerticalBraceNode* node) { + defaultVisit(node); +} + +///////////////////////////////////// Concrete Caret Pos search ///////////////////////////////////// + +#define VERTICAL_DISTANCE_FACTOR 3 +#define HORIZONTICAL_DISTANCE_FACTOR 3 + +void SmLeftCaretPosSearchVisitor::suggest(SmCaretPos proposal, Point pos) { + //Check for validity + if(!proposal.IsValid()) return; + if(pos.X() >= from_pos.X()) return; + if(!best.IsValid() && proposal != from) { + best = proposal; + best_pos = pos; + return; + } + + //Delta pos + Point dpos = from_pos - pos; + //Distance squared + long dp_sq = dpos.X() * dpos.X() + + dpos.Y() * dpos.Y() * VERTICAL_DISTANCE_FACTOR; + + //Delta best_pos + Point dbpos = from_pos - best_pos; + long dbp_sq = dbpos.X() * dbpos.X() + + dbpos.Y() * dbpos.Y() * VERTICAL_DISTANCE_FACTOR; + + if(dp_sq < dbp_sq && proposal != from){ + best = proposal; + best_pos = pos; + } +} + +void SmRightCaretPosSearchVisitor::suggest(SmCaretPos proposal, Point pos) { + //Check for validity + if(!proposal.IsValid()) return; + if(pos.X() <= from_pos.X()) return; + if(!best.IsValid() && proposal != from) { + best = proposal; + best_pos = pos; + return; + } + + //Delta pos + Point dpos = from_pos - pos; + //Distance squared + long dp_sq = dpos.X() * dpos.X() + + dpos.Y() * dpos.Y() * VERTICAL_DISTANCE_FACTOR; + + //Delta best_pos + Point dbpos = from_pos - best_pos; + long dbp_sq = dbpos.X() * dbpos.X() + + dbpos.Y() * dbpos.Y() * VERTICAL_DISTANCE_FACTOR; + + if(dp_sq < dbp_sq && proposal != from){ + best = proposal; + best_pos = pos; + } +} + +void SmUpCaretPosSearchVisitor::suggest(SmCaretPos proposal, Point pos) { + //Check for validity + if(!proposal.IsValid()) return; + if(pos.Y() >= from_pos.Y()) return; + if(!best.IsValid() && proposal != from) { + best = proposal; + best_pos = pos; + return; + } + + //Delta pos + Point dpos = from_pos - pos; + //Distance squared + long dp_sq = dpos.X() * dpos.X() * HORIZONTICAL_DISTANCE_FACTOR + + dpos.Y() * dpos.Y(); + + //Delta best_pos + Point dbpos = from_pos - best_pos; + long dbp_sq = dbpos.X() * dbpos.X() * HORIZONTICAL_DISTANCE_FACTOR + + dbpos.Y() * dbpos.Y(); + + if(dp_sq < dbp_sq && proposal != from){ + best = proposal; + best_pos = pos; + } +} + +void SmDownCaretPosSearchVisitor::suggest(SmCaretPos proposal, Point pos) { + //Check for validity + if(!proposal.IsValid()) return; + if(pos.Y() <= from_pos.Y()) return; + if(!best.IsValid() && proposal != from) { + best = proposal; + best_pos = pos; + return; + } + + //Delta pos + Point dpos = from_pos - pos; + //Distance squared + long dp_sq = dpos.X() * dpos.X() * HORIZONTICAL_DISTANCE_FACTOR + + dpos.Y() * dpos.Y(); + + //Delta best_pos + Point dbpos = from_pos - best_pos; + long dbp_sq = dbpos.X() * dbpos.X() * HORIZONTICAL_DISTANCE_FACTOR + + dbpos.Y() * dbpos.Y(); + + if(dp_sq < dbp_sq && proposal != from){ + best = proposal; + best_pos = pos; + } +} + +///////////////////////////////// Initial approach /////////////////////////////////// + +/* +Template for structure nodes: + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + //TODO: Accept first child from given direction, continue while !pCaret.IsValid() + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + pCaret = SmCaretPos(node, -1); + //TODO Call first child after child, contine while !pCaret.IsValid() + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } + +Template for visible nodes: + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +*/ + +void SmMoveLeftVisitor::visit(SmTableNode* node) { + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmBraceNode* node) { + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmBracebodyNode* node) { + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmOperNode* node) { + j_assert(false, "OperNode not implemented yet!"); +} + +void SmMoveLeftVisitor::visit(SmAlignNode* node) { + j_assert(false, "OperNode not implemented yet!"); +} + +void SmMoveLeftVisitor::visit(SmAttributNode* node) { + j_assert(false, "OperNode not implemented yet!"); +} + +void SmMoveLeftVisitor::visit(SmFontNode* node) { + j_assert(false, "OperNode not implemented yet!"); +} + +void SmMoveLeftVisitor::visit(SmUnHorNode* node) { + j_assert(false, "OperNode not implemented yet!"); +} + +void SmMoveLeftVisitor::visit(SmBinHorNode* node) { + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--){ + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if((int)pNode == (int)child) meet = true; + }} + j_assert(meet, "Didn't meet the child!"); + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmBinVerNode* node) { + //Structure, special + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + j_assert(meet, "Didn't meet the child!"); + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmBinDiagonalNode* node) { + j_assert(false, "OperNode not implemented yet!"); +} + +void SmMoveLeftVisitor::visit(SmSubSupNode* node) { + //Special structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + node->GetBody()->accept(this); + }else{ + //Move outof a child of this + pCaret = SmCaretPos(node, -1); + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmMatrixNode* node) { + //Special structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this, pick last child, should be good enough + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmPlaceNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmTextNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + SmNode* p = node->GetParent(); + p->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmSpecialNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmGlyphSpecialNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmMathSymbolNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmBlankNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmErrorNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmLineNode* node) { + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmExpressionNode* node) { + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmPolyLineNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmRootNode* node) { + //Structure + j_assert(pCaret.pSelectedNode != NULL, "An SmStructureNode does not constitue a position, where you can stand."); + if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + }else{ + //Move outof a child of this + SmNode* child = pCaret.pSelectedNode; + bool meet = false; + SmNode *pNode; + pCaret = SmCaretPos(); + USHORT nSize = node->GetNumSubNodes(); + for (int i = nSize-1; i >= 0; i--) + if (NULL != (pNode = node->GetSubNode(i))){ + if(meet){ + pCaret = SmCaretPos(node, -1); + pNode->accept(this); + if(pCaret.IsValid()) break; + } + if(pNode == child) meet = true; + } + if(!pCaret.IsValid() && node->GetParent()){ + //Go outof this + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + } + } +} + +void SmMoveLeftVisitor::visit(SmRootSymbolNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmRectangleNode* node) { + //Visible + if(pCaret.pSelectedNode == NULL){ + //Move out of this, because we don't use index yet + pCaret = SmCaretPos(node, -1); + node->GetParent()->accept(this); + }else if(pCaret.pSelectedNode == node->GetParent()){ + //Move into this + pCaret = SmCaretPos(node, -1); + }else{ + //Move outof a child of this + j_assert(false, "Visible nodes should have children, ths can't move out of them."); + pCaret = SmCaretPos(NULL, -1); + } +} + +void SmMoveLeftVisitor::visit(SmVerticalBraceNode* node) { + j_assert(false, "OperNode not implemented yet!"); +} +