Files
libreoffice/starmath/source/visitors.cxx

2552 lines
70 KiB
C++
Raw Normal View History

2010-10-23 16:39:57 +01:00
/*
* Version: MPL 1.1 / GPLv3+ / LGPLv3+
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Initial Developer of the Original Code is
* Jonas Finnemann Jensen <jopsen@gmail.com>
* Portions created by the Initial Developer are Copyright (C) 2010 the
* Initial Developer. All Rights Reserved.
*
* Contributor(s): Jonas Finnemann Jensen <jopsen@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 3 or later (the "GPLv3+"), or
* the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
* in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
* instead of those above.
*/
#include "visitors.hxx"
#include "cursor.hxx"
///////////////////////////////////// SmVisitorTest /////////////////////////////////////
void SmVisitorTest::Visit( SmTableNode* pNode )
{
j_assert( pNode->GetType( ) == NTABLE, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmBraceNode* pNode )
{
j_assert( pNode->GetType( ) == NBRACE, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmBracebodyNode* pNode )
{
j_assert( pNode->GetType( ) == NBRACEBODY, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmOperNode* pNode )
{
j_assert( pNode->GetType( ) == NOPER, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmAlignNode* pNode )
{
j_assert( pNode->GetType( ) == NALIGN, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmAttributNode* pNode )
{
j_assert( pNode->GetType( ) == NATTRIBUT, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmFontNode* pNode )
{
j_assert( pNode->GetType( ) == NFONT, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmUnHorNode* pNode )
{
j_assert( pNode->GetType( ) == NUNHOR, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmBinHorNode* pNode )
{
j_assert( pNode->GetType( ) == NBINHOR, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmBinVerNode* pNode )
{
j_assert( pNode->GetType( ) == NBINVER, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmBinDiagonalNode* pNode )
{
j_assert( pNode->GetType( ) == NBINDIAGONAL, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmSubSupNode* pNode )
{
j_assert( pNode->GetType( ) == NSUBSUP, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmMatrixNode* pNode )
{
j_assert( pNode->GetType( ) == NMATRIX, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmPlaceNode* pNode )
{
j_assert( pNode->GetType( ) == NPLACE, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmTextNode* pNode )
{
j_assert( pNode->GetType( ) == NTEXT, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmSpecialNode* pNode )
{
j_assert( pNode->GetType( ) == NSPECIAL, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmGlyphSpecialNode* pNode )
{
j_assert( pNode->GetType( ) == NGLYPH_SPECIAL, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmMathSymbolNode* pNode )
{
j_assert( pNode->GetType( ) == NMATH, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmBlankNode* pNode )
{
j_assert( pNode->GetType( ) == NBLANK, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmErrorNode* pNode )
{
j_assert( pNode->GetType( ) == NERROR, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmLineNode* pNode )
{
j_assert( pNode->GetType( ) == NLINE, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmExpressionNode* pNode )
{
j_assert( pNode->GetType( ) == NEXPRESSION, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmPolyLineNode* pNode )
{
j_assert( pNode->GetType( ) == NPOLYLINE, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmRootNode* pNode )
{
j_assert( pNode->GetType( ) == NROOT, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmRootSymbolNode* pNode )
{
j_assert( pNode->GetType( ) == NROOTSYMBOL, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmRectangleNode* pNode )
{
j_assert( pNode->GetType( ) == NRECTANGLE, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::Visit( SmVerticalBraceNode* pNode )
{
j_assert( pNode->GetType( ) == NVERTICAL_BRACE, "the visitor-patterns isn't implemented correctly" );
VisitChildren( pNode );
}
void SmVisitorTest::VisitChildren( SmNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
}
/////////////////////////////// SmDefaultingVisitor ////////////////////////////////
void SmDefaultingVisitor::Visit( SmTableNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmBraceNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmBracebodyNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmOperNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmAlignNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmAttributNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmFontNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmUnHorNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmBinHorNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmBinVerNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmBinDiagonalNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmSubSupNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmMatrixNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmPlaceNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmTextNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmSpecialNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmGlyphSpecialNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmMathSymbolNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmBlankNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmErrorNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmLineNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmExpressionNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmPolyLineNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmRootNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmRootSymbolNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmRectangleNode* pNode )
{
DefaultVisit( pNode );
}
void SmDefaultingVisitor::Visit( SmVerticalBraceNode* pNode )
{
DefaultVisit( pNode );
}
/////////////////////////////// SmCaretDrawingVisitor ////////////////////////////////
SmCaretDrawingVisitor::SmCaretDrawingVisitor( OutputDevice& rDevice,
SmCaretPos position,
Point offset )
: rDev( rDevice )
{
pos = position;
Offset = offset;
j_assert( position.IsValid( ), "Cannot draw invalid position!" );
if( !position.IsValid( ) )
return;
//Save device state
rDev.Push( PUSH_FONT | PUSH_MAPMODE | PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
pos.pSelectedNode->Accept( this );
//Restore device state
rDev.Pop( );
}
void SmCaretDrawingVisitor::Visit( SmTextNode* pNode )
{
long i = pos.Index;
rDev.SetFont( pNode->GetFont( ) );
//Find the line
SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
//Find coordinates
long left = pNode->GetLeft( ) + rDev.GetTextWidth( pNode->GetText( ), 0, i ) + Offset.X( );
long top = pLine->GetTop( ) + Offset.Y( );
long height = pLine->GetHeight( );
//Set color
rDev.SetLineColor( Color( COL_BLACK ) );
//Draw vertical line
Point p1( left, top );
Point p2( left, top + height );
rDev.DrawLine( p1, p2 );
}
void SmCaretDrawingVisitor::DefaultVisit( SmNode* pNode )
{
rDev.SetLineColor( Color( COL_BLACK ) );
//Find the line
SmNode* pLine = SmCursor::FindTopMostNodeInLine( pNode );
//Find coordinates
long left = pNode->GetLeft( ) + Offset.X( ) + ( pos.Index == 1 ? pNode->GetWidth( ) : 0 );
long top = pLine->GetTop( ) + Offset.Y( );
long height = pLine->GetHeight( );
//Set color
rDev.SetLineColor( Color( COL_BLACK ) );
//Draw vertical line
Point p1( left, top );
Point p2( left, top + height );
rDev.DrawLine( p1, p2 );
}
/////////////////////////////// SmCaretPos2LineVisitor ////////////////////////////////
void SmCaretPos2LineVisitor::Visit( SmTextNode* pNode )
{
//Save device state
pDev->Push( PUSH_FONT | PUSH_TEXTCOLOR );
long i = pos.Index;
pDev->SetFont( pNode->GetFont( ) );
//Find coordinates
long left = pNode->GetLeft( ) + pDev->GetTextWidth( pNode->GetText( ), 0, i );
long top = pNode->GetTop( );
long height = pNode->GetHeight( );
line = SmCaretLine( left, top, height );
//Restore device state
pDev->Pop( );
}
void SmCaretPos2LineVisitor::DefaultVisit( SmNode* pNode )
{
//Vertical line ( code from SmCaretDrawingVisitor )
Point p1 = pNode->GetTopLeft( );
if( pos.Index == 1 )
p1.Move( pNode->GetWidth( ), 0 );
line = SmCaretLine( p1.X( ), p1.Y( ), pNode->GetHeight( ) );
}
/////////////////////////////// Nasty temporary device!!! ////////////////////////////////
#include <tools/gen.hxx>
#include <tools/fract.hxx>
#include <rtl/math.hxx>
#include <tools/color.hxx>
#include <vcl/metric.hxx>
#include <vcl/lineinfo.hxx>
#include <vcl/outdev.hxx>
#include <sfx2/module.hxx>
#include "symbol.hxx"
#include "smmod.hxx"
class SmTmpDevice2
{
OutputDevice &rOutDev;
// disallow use of copy-constructor and assignment-operator
SmTmpDevice2( const SmTmpDevice2 &rTmpDev );
SmTmpDevice2 & operator = ( const SmTmpDevice2 &rTmpDev );
Color Impl_GetColor( const Color& rColor );
public:
SmTmpDevice2( OutputDevice &rTheDev, bool bUseMap100th_mm );
~SmTmpDevice2( ) { rOutDev.Pop( ); }
void SetFont( const Font &rNewFont );
void SetLineColor( const Color& rColor ) { rOutDev.SetLineColor( Impl_GetColor( rColor ) ); }
void SetFillColor( const Color& rColor ) { rOutDev.SetFillColor( Impl_GetColor( rColor ) ); }
void SetTextColor( const Color& rColor ) { rOutDev.SetTextColor( Impl_GetColor( rColor ) ); }
operator OutputDevice & ( ) { return rOutDev; }
};
SmTmpDevice2::SmTmpDevice2( OutputDevice &rTheDev, bool bUseMap100th_mm ) :
rOutDev( rTheDev )
{
rOutDev.Push( PUSH_FONT | PUSH_MAPMODE |
PUSH_LINECOLOR | PUSH_FILLCOLOR | PUSH_TEXTCOLOR );
if ( bUseMap100th_mm && MAP_100TH_MM != rOutDev.GetMapMode( ).GetMapUnit( ) )
{
DBG_ERROR( "incorrect MapMode?" );
rOutDev.SetMapMode( MAP_100TH_MM ); //Immer fuer 100% fomatieren
}
}
Color SmTmpDevice2::Impl_GetColor( const Color& rColor )
{
ColorData nNewCol = rColor.GetColor( );
if ( COL_AUTO == nNewCol )
{
if ( OUTDEV_PRINTER == rOutDev.GetOutDevType( ) )
nNewCol = COL_BLACK;
else
{
Color aBgCol( rOutDev.GetBackground( ).GetColor( ) );
if ( OUTDEV_WINDOW == rOutDev.GetOutDevType( ) )
aBgCol = ( ( Window & ) rOutDev ).GetDisplayBackground( ).GetColor( );
nNewCol = SM_MOD( )->GetColorConfig( ).GetColorValue( svtools::FONTCOLOR ).nColor;
Color aTmpColor( nNewCol );
if ( aBgCol.IsDark( ) && aTmpColor.IsDark( ) )
nNewCol = COL_WHITE;
else if ( aBgCol.IsBright( ) && aTmpColor.IsBright( ) )
nNewCol = COL_BLACK;
}
}
return Color( nNewCol );
}
void SmTmpDevice2::SetFont( const Font &rNewFont )
{
rOutDev.SetFont( rNewFont );
rOutDev.SetTextColor( Impl_GetColor( rNewFont.GetColor( ) ) );
}
/////////////////////////////// SmDrawingVisitor ////////////////////////////////
void SmDrawingVisitor::Visit( SmTableNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmBraceNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmBracebodyNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmOperNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmAlignNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmAttributNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmFontNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmUnHorNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmBinHorNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmBinVerNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmBinDiagonalNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmSubSupNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmMatrixNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmPlaceNode* pNode )
{
DrawSpecialNode( pNode );
}
void SmDrawingVisitor::Visit( SmTextNode* pNode )
{
DrawTextNode( pNode );
}
void SmDrawingVisitor::Visit( SmSpecialNode* pNode )
{
DrawSpecialNode( pNode );
}
void SmDrawingVisitor::Visit( SmGlyphSpecialNode* pNode )
{
DrawSpecialNode( pNode );
}
void SmDrawingVisitor::Visit( SmMathSymbolNode* pNode )
{
DrawSpecialNode( pNode );
}
void SmDrawingVisitor::Visit( SmBlankNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmErrorNode* pNode )
{
DrawSpecialNode( pNode );
}
void SmDrawingVisitor::Visit( SmLineNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmExpressionNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmRootNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmVerticalBraceNode* pNode )
{
DrawChildren( pNode );
}
void SmDrawingVisitor::Visit( SmRootSymbolNode* pNode )
{
if ( pNode->IsPhantom( ) )
return;
// draw root-sign itself
DrawSpecialNode( pNode );
SmTmpDevice2 aTmpDev( ( OutputDevice & ) rDev, true );
aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
rDev.SetLineColor( );
aTmpDev.SetFont( pNode->GetFont( ) );
// since the width is always unscaled it corresponds ot the _original_
// _unscaled_ font height to be used, we use that to calculate the
// bar height. Thus it is independent of the arguments height.
// ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
long nBarHeight = pNode->GetWidth( ) * 7L / 100L;
long nBarWidth = pNode->GetBodyWidth( ) + pNode->GetBorderWidth( );
Point aBarOffset( pNode->GetWidth( ), +pNode->GetBorderWidth( ) );
Point aBarPos( Position + aBarOffset );
Rectangle aBar( aBarPos, Size( nBarWidth, nBarHeight ) );
//! avoid GROWING AND SHRINKING of drawn rectangle when constantly
//! increasing zoomfactor.
// This is done by shifting it's output-position to a point that
// corresponds exactly to a pixel on the output device.
Point aDrawPos( rDev.PixelToLogic( rDev.LogicToPixel( aBar.TopLeft( ) ) ) );
//aDrawPos.X( ) = aBar.Left( ); //! don't change X position
aBar.SetPos( aDrawPos );
rDev.DrawRect( aBar );
#ifdef SM_RECT_DEBUG
if ( !pNode->IsDebug( ) )
return;
int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
pNode->SmRect::Draw( rDev, Position, nRFlags );
#endif
}
void SmDrawingVisitor::Visit( SmPolyLineNode* pNode )
{
if ( pNode->IsPhantom( ) )
return;
long nBorderwidth = pNode->GetFont( ).GetBorderWidth( );
LineInfo aInfo;
aInfo.SetWidth( pNode->GetWidth( ) - 2 * nBorderwidth );
Point aOffset ( Point( ) - pNode->GetPolygon( ).GetBoundRect( ).TopLeft( )
+ Point( nBorderwidth, nBorderwidth ) ),
aPos ( Position + aOffset );
pNode->GetPolygon( ).Move( aPos.X( ), aPos.Y( ) ); //Works because Polygon wraps a pointer
SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
aTmpDev.SetLineColor( pNode->GetFont( ).GetColor( ) );
rDev.DrawPolyLine( pNode->GetPolygon( ), aInfo );
#ifdef SM_RECT_DEBUG
if ( !pNode->IsDebug( ) )
return;
int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
pNode->SmRect::Draw( rDev, Position, nRFlags );
#endif
}
void SmDrawingVisitor::Visit( SmRectangleNode* pNode )
{
if ( pNode->IsPhantom( ) )
return;
SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
aTmpDev.SetFillColor( pNode->GetFont( ).GetColor( ) );
rDev.SetLineColor( );
aTmpDev.SetFont( pNode->GetFont( ) );
ULONG nTmpBorderWidth = pNode->GetFont( ).GetBorderWidth( );
// get rectangle and remove borderspace
Rectangle aTmp ( pNode->AsRectangle( ) + Position - pNode->GetTopLeft( ) );
aTmp.Left( ) += nTmpBorderWidth;
aTmp.Right( ) -= nTmpBorderWidth;
aTmp.Top( ) += nTmpBorderWidth;
aTmp.Bottom( ) -= nTmpBorderWidth;
DBG_ASSERT( aTmp.GetHeight( ) > 0 && aTmp.GetWidth( ) > 0,
"Sm: leeres Rechteck" );
//! avoid GROWING AND SHRINKING of drawn rectangle when constantly
//! increasing zoomfactor.
// This is done by shifting it's output-position to a point that
// corresponds exactly to a pixel on the output device.
Point aPos ( rDev.PixelToLogic( rDev.LogicToPixel( aTmp.TopLeft( ) ) ) );
aTmp.SetPos( aPos );
rDev.DrawRect( aTmp );
#ifdef SM_RECT_DEBUG
if ( !pNode->IsDebug( ) )
return;
int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
pNode->SmRect::Draw( rDev, rPosition, nRFlags );
#endif
}
void SmDrawingVisitor::DrawTextNode( SmTextNode* pNode )
{
if ( pNode->IsPhantom( ) || pNode->GetText( ).Len( ) == 0 || pNode->GetText( ).GetChar( 0 ) == xub_Unicode( '\0' ) )
return;
SmTmpDevice2 aTmpDev ( ( OutputDevice & ) rDev, false );
aTmpDev.SetFont( pNode->GetFont( ) );
Point aPos ( Position );
aPos.Y( ) += pNode->GetBaselineOffset( );
// auf Pixelkoordinaten runden
aPos = rDev.PixelToLogic( rDev.LogicToPixel( aPos ) );
rDev.DrawStretchText( aPos, pNode->GetWidth( ), pNode->GetText( ) );
#ifdef SM_RECT_DEBUG
if ( !pNode->IsDebug( ) )
return;
int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
pNode->SmRect::Draw( rDev, Position, nRFlags );
#endif
}
void SmDrawingVisitor::DrawSpecialNode( SmSpecialNode* pNode )
{
//! since this chars might come from any font, that we may not have
//! set to ALIGN_BASELINE yet, we do it now.
pNode->GetFont( ).SetAlign( ALIGN_BASELINE );
DrawTextNode( pNode );
}
void SmDrawingVisitor::DrawChildren( SmNode* pNode )
{
if ( pNode->IsPhantom( ) )
return;
Point rPosition = Position;
SmNodeIterator it( pNode );
while( it.Next( ) )
{
Point aOffset ( it->GetTopLeft( ) - pNode->GetTopLeft( ) );
Position = rPosition + aOffset;
it->Accept( this );
}
#ifdef SM_RECT_DEBUG
if ( !pNode->IsDebug( ) )
return;
int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
pNode->SmRect::Draw( rDev, rPosition, nRFlags );
#endif
}
/////////////////////////////// SmSetSelectionVisitor ////////////////////////////////
SmSetSelectionVisitor::SmSetSelectionVisitor( SmCaretPos startPos, SmCaretPos endPos, SmNode* pTree) {
StartPos = startPos;
EndPos = endPos;
IsSelecting = false;
//Assume that pTree is a SmTableNode
j_assert(pTree->GetType() == NTABLE, "pTree should be a SmTableNode!");
//Visit root node, this is special as this node cannot be selected, but it's children can!
if(pTree->GetType() == NTABLE){
//Change state if StartPos is infront of this node
if( StartPos.pSelectedNode == pTree && StartPos.Index == 0 )
IsSelecting = !IsSelecting;
//Change state if EndPos is infront of this node
if( EndPos.pSelectedNode == pTree && EndPos.Index == 0 )
IsSelecting = !IsSelecting;
j_assert(!IsSelecting, "Caret positions needed to set IsSelecting about, shouldn't be possible!");
//Visit lines
SmNodeIterator it( pTree );
while( it.Next( ) ) {
it->Accept( this );
//If we started a selection in this line and it haven't ended, we do that now!
if(IsSelecting) {
IsSelecting = false;
SetSelectedOnAll(it.Current(), true);
//Set StartPos and EndPos to invalid positions, this ensures that an unused
//start or end (because we forced end above), doesn't start a new selection.
StartPos = EndPos = SmCaretPos();
}
}
//Check if pTree isn't selected
j_assert(!pTree->IsSelected(), "pTree should never be selected!");
//Discard the selection if there's a bug (it's better than crashing)
if(pTree->IsSelected())
SetSelectedOnAll(pTree, false);
}else //This shouldn't happen, but I don't see any reason to die if it does
pTree->Accept(this);
}
void SmSetSelectionVisitor::SetSelectedOnAll( SmNode* pSubTree, bool IsSelected ) {
pSubTree->SetSelected( IsSelected );
//Quick BFS to set all selections
SmNodeIterator it( pSubTree );
while( it.Next( ) )
SetSelectedOnAll( it.Current( ), IsSelected );
}
void SmSetSelectionVisitor::DefaultVisit( SmNode* pNode ) {
//Change state if StartPos is infront of this node
if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
IsSelecting = !IsSelecting;
//Change state if EndPos is infront of this node
if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
IsSelecting = !IsSelecting;
//Cache current state
bool WasSelecting = IsSelecting;
bool ChangedState = false;
//Set selected
pNode->SetSelected( IsSelecting );
//Visit children
SmNodeIterator it( pNode );
while( it.Next( ) )
{
it->Accept( this );
ChangedState = ( WasSelecting != IsSelecting ) || ChangedState;
}
//If state changed
if( ChangedState )
{
//Select this node and all of it's children
//(Make exception for SmBracebodyNode)
if( pNode->GetType() != NBRACEBODY ||
!pNode->GetParent() ||
pNode->GetParent()->GetType() != NBRACE )
SetSelectedOnAll( pNode, true );
else
SetSelectedOnAll( pNode->GetParent(), true );
/* If the equation is: sqrt{2 + 4} + 5
* And the selection is: sqrt{2 + [4} +] 5
* Where [ denotes StartPos and ] denotes EndPos
* Then the sqrt node should be selected, so that the
* effective selection is: [sqrt{2 + 4} +] 5
* The same is the case if we swap StartPos and EndPos.
*/
}
//Change state if StartPos is after this node
if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
{
IsSelecting = !IsSelecting;
}
//Change state if EndPos is after of this node
if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
{
IsSelecting = !IsSelecting;
}
}
void SmSetSelectionVisitor::VisitCompositionNode( SmNode* pNode ) {
//Change state if StartPos is infront of this node
if( StartPos.pSelectedNode == pNode && StartPos.Index == 0 )
IsSelecting = !IsSelecting;
//Change state if EndPos is infront of this node
if( EndPos.pSelectedNode == pNode && EndPos.Index == 0 )
IsSelecting = !IsSelecting;
//Cache current state
bool WasSelecting = IsSelecting;
//Visit children
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
//Set selected, if everything was selected
pNode->SetSelected( WasSelecting && IsSelecting );
//Change state if StartPos is after this node
if( StartPos.pSelectedNode == pNode && StartPos.Index == 1 )
IsSelecting = !IsSelecting;
//Change state if EndPos is after of this node
if( EndPos.pSelectedNode == pNode && EndPos.Index == 1 )
IsSelecting = !IsSelecting;
}
void SmSetSelectionVisitor::Visit( SmTextNode* pNode ) {
long i1 = -1,
i2 = -1;
if( StartPos.pSelectedNode == pNode )
i1 = StartPos.Index;
if( EndPos.pSelectedNode == pNode )
i2 = EndPos.Index;
long start, end;
pNode->SetSelected( true );
if( i1 != -1 && i2 != -1 ) {
start = i1 < i2 ? i1 : i2; //MIN
end = i1 > i2 ? i1 : i2; //MAX
} else if( IsSelecting && i1 != -1 ) {
start = 0;
end = i1;
IsSelecting = false;
} else if( IsSelecting && i2 != -1 ) {
start = 0;
end = i2;
IsSelecting = false;
} else if( !IsSelecting && i1 != -1 ) {
start = i1;
end = pNode->GetText( ).Len( );
IsSelecting = true;
} else if( !IsSelecting && i2 != -1 ) {
start = i2;
end = pNode->GetText( ).Len( );
IsSelecting = true;
} else if( IsSelecting ) {
start = 0;
end = pNode->GetText( ).Len( );
} else {
pNode->SetSelected( false );
start = 0;
end = 0;
}
pNode->SetSelected( start != end );
pNode->SetSelectionStart( start );
pNode->SetSelectionEnd( end );
}
void SmSetSelectionVisitor::Visit( SmExpressionNode* pNode ) {
VisitCompositionNode( pNode );
}
void SmSetSelectionVisitor::Visit( SmLineNode* pNode ) {
VisitCompositionNode( pNode );
}
void SmSetSelectionVisitor::Visit( SmAlignNode* pNode ) {
VisitCompositionNode( pNode );
}
void SmSetSelectionVisitor::Visit( SmBinHorNode* pNode ) {
VisitCompositionNode( pNode );
}
void SmSetSelectionVisitor::Visit( SmUnHorNode* pNode ) {
VisitCompositionNode( pNode );
}
void SmSetSelectionVisitor::Visit( SmFontNode* pNode ) {
VisitCompositionNode( pNode );
}
/////////////////////////////// SmCaretPosGraphBuildingVisitor ////////////////////////////////
SmCaretPosGraphBuildingVisitor::SmCaretPosGraphBuildingVisitor( SmNode* pRootNode ) {
pRightMost = NULL;
pGraph = new SmCaretPosGraph( );
//pRootNode should always be a table
j_assert( pRootNode->GetType( ) == NTABLE, "pRootNode must be a table node");
//Handle the special case where NTABLE is used a rootnode
if( pRootNode->GetType( ) == NTABLE ){
//Children are SmLineNodes
//Or so I thought... Aparently, the children can be instances of SmExpression
//especially if there's a error in the formula... So he we go, a simple work around.
SmNodeIterator it( pRootNode );
while( it.Next( ) ){
//There's a special invariant between this method and the Visit( SmLineNode* )
//Usually pRightMost may not be NULL, to avoid this pRightMost should here be
//set to a new SmCaretPos infront of it.Current( ), however, if it.Current( ) is
//an instance of SmLineNode we let SmLineNode create this position infront of
//the visual line.
//The argument for doing this is that we now don't have to worry about SmLineNode
//being a visual line composition node. Thus, no need for yet another special case
//in SmCursor::IsLineCompositionNode and everywhere this method is used.
//if( it->GetType( ) != NLINE )
pRightMost = pGraph->Add( SmCaretPos( it.Current( ), 0 ) );
it->Accept( this );
}
}else
pRootNode->Accept(this);
}
void SmCaretPosGraphBuildingVisitor::Visit( SmLineNode* pNode ){
//pRightMost = NULL;
SmNodeIterator it( pNode );
while( it.Next( ) ){
//if( !pRightMost )
// pRightMost = pGraph->Add( SmCaretPos( it.Current( ), 0 ) );
it->Accept( this );
}
}
/** Build SmCaretPosGraph for SmTableNode
* This method covers cases where SmTableNode is used in a binom or stack,
* the special case where it is used as root node for the entire formula is
* handled in the constructor.
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmTableNode* pNode ){
SmCaretPosGraphEntry *left = pRightMost,
*right = pGraph->Add( SmCaretPos( pNode, 1) );
bool bIsFirst = true;
SmNodeIterator it( pNode );
while( it.Next() ){
pRightMost = pGraph->Add( SmCaretPos( it.Current(), 0 ), left);
if(bIsFirst)
left->SetRight(pRightMost);
it->Accept( this );
pRightMost->SetRight(right);
if(bIsFirst)
right->SetLeft(pRightMost);
bIsFirst = false;
}
pRightMost = right;
}
/** Build SmCaretPosGraph for SmSubSupNode
*
* The child positions in a SubSupNode, where H is the body:
* \code
* CSUP
*
* LSUP H H RSUP
* H H
* HHHH
* H H
* LSUB H H RSUB
*
* CSUB
* \endcode
*
* Graph over these, where "left" is before the SmSubSupNode and "right" is after:
* \dot
* digraph Graph{
* left -> H;
* H -> right;
* LSUP -> H;
* LSUB -> H;
* CSUP -> right;
* CSUB -> right;
* RSUP -> right;
* RSUB -> right;
* };
* \enddot
*
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmSubSupNode* pNode )
{
SmCaretPosGraphEntry *left,
*right,
*bodyLeft,
*bodyRight;
left = pRightMost;
j_assert( pRightMost, "pRightMost shouldn't be NULL here!" );
//Create bodyLeft
j_assert( pNode->GetBody( ), "SmSubSupNode Doesn't have a body!" );
bodyLeft = pGraph->Add( SmCaretPos( pNode->GetBody( ), 0 ), left );
left->SetRight( bodyLeft ); //TODO: Don't make this if LSUP or LSUB are NULL ( not sure??? )
//Create right
right = pGraph->Add( SmCaretPos( pNode, 1 ) );
//Visit the body, to get bodyRight
pRightMost = bodyLeft;
pNode->GetBody( )->Accept( this );
bodyRight = pRightMost;
bodyRight->SetRight( right );
right->SetLeft( bodyRight );
SmNode* pChild;
//If there's an LSUP
if( ( pChild = pNode->GetSubSup( LSUP ) ) ){
SmCaretPosGraphEntry *cLeft; //Child left
cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
pRightMost = cLeft;
pChild->Accept( this );
pRightMost->SetRight( bodyLeft );
}
//If there's an LSUB
if( ( pChild = pNode->GetSubSup( LSUB ) ) ){
SmCaretPosGraphEntry *cLeft; //Child left
cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
pRightMost = cLeft;
pChild->Accept( this );
pRightMost->SetRight( bodyLeft );
}
//If there's an CSUP
if( ( pChild = pNode->GetSubSup( CSUP ) ) ){
SmCaretPosGraphEntry *cLeft; //Child left
cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
pRightMost = cLeft;
pChild->Accept( this );
pRightMost->SetRight( right );
}
//If there's an CSUB
if( ( pChild = pNode->GetSubSup( CSUB ) ) ){
SmCaretPosGraphEntry *cLeft; //Child left
cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
pRightMost = cLeft;
pChild->Accept( this );
pRightMost->SetRight( right );
}
//If there's an RSUP
if( ( pChild = pNode->GetSubSup( RSUP ) ) ){
SmCaretPosGraphEntry *cLeft; //Child left
cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
pRightMost = cLeft;
pChild->Accept( this );
pRightMost->SetRight( right );
}
//If there's an RSUB
if( ( pChild = pNode->GetSubSup( RSUB ) ) ){
SmCaretPosGraphEntry *cLeft; //Child left
cLeft = pGraph->Add( SmCaretPos( pChild, 0 ), bodyRight );
pRightMost = cLeft;
pChild->Accept( this );
pRightMost->SetRight( right );
}
//Set return parameters
pRightMost = right;
}
/** Build caret position for SmOperNode
*
* If first child is an SmSubSupNode we will ignore it's
* body, as this body is a SmMathSymbol, for SUM, INT or similar
* that shouldn't be subject to modification.
* If first child is not a SmSubSupNode, ignore it completely
* as it is a SmMathSymbol.
*
* The child positions in a SmOperNode, where H is symbol, e.g. int, sum or similar:
* \code
* TO
*
* LSUP H H RSUP BBB BB BBB B B
* H H B B B B B B B B
* HHHH BBB B B B B B
* H H B B B B B B B
* LSUB H H RSUB BBB BB BBB B
*
* FROM
* \endcode
* Notice, CSUP, etc. are actually granchildren, but inorder to ignore H, these are visited
* from here. If they are present, that is if pOper is an instance of SmSubSupNode.
*
* Graph over these, where "left" is before the SmOperNode and "right" is after:
* \dot
* digraph Graph{
* left -> BODY;
* BODY -> right;
* LSUP -> BODY;
* LSUB -> BODY;
* TO -> BODY;
* FROM -> BODY;
* RSUP -> BODY;
* RSUB -> BODY;
* };
* \enddot
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmOperNode* pNode )
{
SmNode *pOper = pNode->GetSubNode( 0 ),
*pBody = pNode->GetSubNode( 1 );
SmCaretPosGraphEntry *left = pRightMost,
*bodyLeft,
*bodyRight,
*right;
//Create body left
bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
left->SetRight( bodyLeft );
//Visit body, get bodyRight
pRightMost = bodyLeft;
pBody->Accept( this );
bodyRight = pRightMost;
//Create right
right = pGraph->Add( SmCaretPos( pNode, 1 ), bodyRight );
bodyRight->SetRight( right );
//Get subsup pNode if any
SmSubSupNode* pSubSup = pOper->GetType( ) == NSUBSUP ? ( SmSubSupNode* )pOper : NULL;
SmNode* pChild;
SmCaretPosGraphEntry *childLeft;
if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
//Create position infront of pChild
childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
//Visit pChild
pRightMost = childLeft;
pChild->Accept( this );
//Set right on pRightMost from pChild
pRightMost->SetRight( bodyLeft );
}
if( pSubSup && ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
//Create position infront of pChild
childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
//Visit pChild
pRightMost = childLeft;
pChild->Accept( this );
//Set right on pRightMost from pChild
pRightMost->SetRight( bodyLeft );
}
if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {//TO
//Create position infront of pChild
childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
//Visit pChild
pRightMost = childLeft;
pChild->Accept( this );
//Set right on pRightMost from pChild
pRightMost->SetRight( bodyLeft );
}
if( pSubSup && ( pChild = pSubSup->GetSubSup( CSUB ) ) ) { //FROM
//Create position infront of pChild
childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
//Visit pChild
pRightMost = childLeft;
pChild->Accept( this );
//Set right on pRightMost from pChild
pRightMost->SetRight( bodyLeft );
}
if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
//Create position infront of pChild
childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
//Visit pChild
pRightMost = childLeft;
pChild->Accept( this );
//Set right on pRightMost from pChild
pRightMost->SetRight( bodyLeft );
}
if( pSubSup && ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
//Create position infront of pChild
childLeft = pGraph->Add( SmCaretPos( pChild, 0 ), left );
//Visit pChild
pRightMost = childLeft;
pChild->Accept( this );
//Set right on pRightMost from pChild
pRightMost->SetRight( bodyLeft );
}
//Return right
pRightMost = right;
}
void SmCaretPosGraphBuildingVisitor::Visit( SmMatrixNode* pNode )
{
SmCaretPosGraphEntry *left = pRightMost,
*right = pGraph->Add( SmCaretPos( pNode, 1 ) );
for ( USHORT i = 0; i < pNode->GetNumRows( ); i++ ) {
SmCaretPosGraphEntry* r = left;
for ( USHORT j = 0; j < pNode->GetNumCols( ); j++ ){
SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
pRightMost = pGraph->Add( SmCaretPos( pSubNode, 0 ), r );
if( j != 0 || ( pNode->GetNumRows( ) - 1 ) / 2 == i )
r->SetRight( pRightMost );
pSubNode->Accept( this );
r = pRightMost;
}
pRightMost->SetRight( right );
if( ( pNode->GetNumRows( ) - 1 ) / 2 == i )
right->SetLeft( pRightMost );
}
pRightMost = right;
}
/** Build SmCaretPosGraph for SmTextNode
*
* Lines in an SmTextNode:
* \code
* A B C
* \endcode
* Where A B and C are characters in the text.
*
* Graph over these, where "left" is before the SmTextNode and "right" is after:
* \dot
* digraph Graph{
* left -> A;
* A -> B
* B -> right;
* };
* \enddot
* Notice that C and right is the same position here.
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmTextNode* pNode )
{
j_assert( pNode->GetText( ).Len( ) > 0, "Empty SmTextNode is bad" );
int size = pNode->GetText( ).Len( );
for( int i = 1; i <= size; i++ ){
SmCaretPosGraphEntry* pRight = pRightMost;
pRightMost = pGraph->Add( SmCaretPos( pNode, i ), pRight );
pRight->SetRight( pRightMost );
}
}
/** Build SmCaretPosGraph for SmBinVerNode
*
* Lines in an SmBinVerNode:
* \code
* A
* -----
* B
* \endcode
*
* Graph over these, where "left" is before the SmBinVerNode and "right" is after:
* \dot
* digraph Graph{
* left -> A;
* A -> right;
* B -> right;
* };
* \enddot
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmBinVerNode* pNode )
{
//None if these children can be NULL, see SmBinVerNode::Arrange
SmNode *pNum = pNode->GetSubNode( 0 ),
*pDenom = pNode->GetSubNode( 2 );
SmCaretPosGraphEntry *left,
*right,
*numLeft,
*denomLeft;
//Set left
left = pRightMost;
j_assert( pRightMost, "There must be a position infront of this" );
//Create right
right = pGraph->Add( SmCaretPos( pNode, 1 ) );
//Create numLeft
numLeft = pGraph->Add( SmCaretPos( pNum, 0 ), left );
left->SetRight( numLeft );
//Visit pNum
pRightMost = numLeft;
pNum->Accept( this );
pRightMost->SetRight( right );
right->SetLeft( pRightMost );
//Create denomLeft
denomLeft = pGraph->Add( SmCaretPos( pDenom, 0 ), left );
//Visit pDenom
pRightMost = denomLeft;
pDenom->Accept( this );
pRightMost->SetRight( right );
//Set return parameter
pRightMost = right;
}
/** Build SmCaretPosGraph for SmVerticalBraceNode
*
* Lines in an SmVerticalBraceNode:
* \code
* pScript
* ________
* / \
* pBody
* \endcode
*
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmVerticalBraceNode* pNode )
{
SmNode *pBody = pNode->GetSubNode( 0 ),
*pScript = pNode->GetSubNode( 2 );
//None of these children can be NULL
SmCaretPosGraphEntry *left,
*bodyLeft,
*scriptLeft,
*right;
left = pRightMost;
//Create right
right = pGraph->Add( SmCaretPos( pNode, 1 ) );
//Create bodyLeft
bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
left->SetRight( bodyLeft );
pRightMost = bodyLeft;
pBody->Accept( this );
pRightMost->SetRight( right );
right->SetLeft( pRightMost );
//Create script
scriptLeft = pGraph->Add( SmCaretPos( pScript, 0 ), left );
pRightMost = scriptLeft;
pScript->Accept( this );
pRightMost->SetRight( right );
//Set return value
pRightMost = right;
}
/** Build SmCaretPosGraph for SmBinDiagonalNode
*
* Lines in an SmBinDiagonalNode:
* \code
* A /
* /
* / B
* \endcode
* Where A and B are lines.
*
* Used in formulas such as "A wideslash B"
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmBinDiagonalNode* pNode )
{
SmNode *A = pNode->GetSubNode( 0 ),
*B = pNode->GetSubNode( 1 );
SmCaretPosGraphEntry *left,
*leftA,
*rightA,
*leftB,
*right;
left = pRightMost;
//Create right
right = pGraph->Add( SmCaretPos( pNode, 1 ) );
//Create left A
leftA = pGraph->Add( SmCaretPos( A, 0 ), left );
left->SetRight( leftA );
//Visit A
pRightMost = leftA;
A->Accept( this );
rightA = pRightMost;
//Create left B
leftB = pGraph->Add( SmCaretPos( B, 0 ), rightA );
rightA->SetRight( leftB );
//Visit B
pRightMost = leftB;
B->Accept( this );
pRightMost->SetRight( right );
right->SetLeft( pRightMost );
//Set return value
pRightMost = right;
}
//Straigt forward ( I think )
void SmCaretPosGraphBuildingVisitor::Visit( SmBinHorNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
}
void SmCaretPosGraphBuildingVisitor::Visit( SmUnHorNode* pNode )
{
// Unary operator node
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
}
void SmCaretPosGraphBuildingVisitor::Visit( SmExpressionNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
}
void SmCaretPosGraphBuildingVisitor::Visit( SmFontNode* pNode )
{
//Has only got one child, should act as an expression if possible
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
}
/** Build SmCaretPosGraph for SmBracebodyNode
* Acts as an SmExpressionNode
*
* Below is an example of a formula tree that has multiple children for SmBracebodyNode
* \dot
* digraph {
* labelloc = "t";
* label= "Equation: \"lbrace i mline i in setZ rbrace\"";
* n0 [label="SmTableNode"];
* n0 -> n1 [label="0"];
* n1 [label="SmLineNode"];
* n1 -> n2 [label="0"];
* n2 [label="SmExpressionNode"];
* n2 -> n3 [label="0"];
* n3 [label="SmBraceNode"];
* n3 -> n4 [label="0"];
* n4 [label="SmMathSymbolNode: {"];
* n3 -> n5 [label="1"];
* n5 [label="SmBracebodyNode"];
* n5 -> n6 [label="0"];
* n6 [label="SmExpressionNode"];
* n6 -> n7 [label="0"];
* n7 [label="SmTextNode: i"];
* n5 -> n8 [label="1"];
* n8 [label="SmMathSymbolNode: "];
* n5 -> n9 [label="2"];
* n9 [label="SmExpressionNode"];
* n9 -> n10 [label="0"];
* n10 [label="SmBinHorNode"];
* n10 -> n11 [label="0"];
* n11 [label="SmTextNode: i"];
* n10 -> n12 [label="1"];
* n12 [label="SmMathSymbolNode: ∈"];
* n10 -> n13 [label="2"];
* n13 [label="SmMathSymbolNode: "];
* n3 -> n14 [label="2"];
* n14 [label="SmMathSymbolNode: }"];
* }
* \enddot
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmBracebodyNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) ) {
SmCaretPosGraphEntry* pStart = pGraph->Add( SmCaretPos( it.Current(), 0), pRightMost );
pRightMost->SetRight( pStart );
pRightMost = pStart;
it->Accept( this );
}
}
/** Build SmCaretPosGraph for SmAlignNode
* Acts as an SmExpressionNode, as it only has one child this okay
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmAlignNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
}
/** Build SmCaretPosGraph for SmRootNode
*
* Lines in an SmRootNode:
* \code
* _________
* A/
* \/ B
*
* \endcode
* A: pExtra ( optional, can be NULL ),
* B: pBody
*
* Graph over these, where "left" is before the SmRootNode and "right" is after:
* \dot
* digraph Graph{
* left -> B;
* B -> right;
* A -> B;
* }
* \enddot
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmRootNode* pNode )
{
SmNode *pExtra = pNode->GetSubNode( 0 ), //Argument, NULL for sqrt, and SmTextNode if cubicroot
*pBody = pNode->GetSubNode( 2 ); //Body of the root
j_assert( pBody, "pBody cannot be NULL" );
SmCaretPosGraphEntry *left,
*right,
*bodyLeft,
*bodyRight;
//Get left and save it
j_assert( pRightMost, "There must be a position infront of this" );
left = pRightMost;
//Create body left
bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
left->SetRight( bodyLeft );
//Create right
right = pGraph->Add( SmCaretPos( pNode, 1 ) );
//Visit body
pRightMost = bodyLeft;
pBody->Accept( this );
bodyRight = pRightMost;
bodyRight->SetRight( right );
right->SetLeft( bodyRight );
//Visit pExtra
if( pExtra ){
pRightMost = pGraph->Add( SmCaretPos( pExtra, 0 ), left );
pExtra->Accept( this );
pRightMost->SetRight( bodyLeft );
}
pRightMost = right;
}
/** Build SmCaretPosGraph for SmPlaceNode
* Consider this a single character.
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmPlaceNode* pNode )
{
SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
pRightMost->SetRight( right );
pRightMost = right;
}
/** SmErrorNode is context dependent metadata, it can't be selected
*
* @remarks There's no point in deleting, copying and/or moving an instance
* of SmErrorNode as it may not exist in an other context! Thus there are no
* positions to select an SmErrorNode.
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmErrorNode* )
{
}
/** Build SmCaretPosGraph for SmBlankNode
* Consider this a single character, as it is only a blank space
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmBlankNode* pNode )
{
SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
pRightMost->SetRight( right );
pRightMost = right;
}
/** Build SmCaretPosGraph for SmBraceNode
*
* Lines in an SmBraceNode:
* \code
* | |
* | B |
* | |
* \endcode
* B: Body
*
* Graph over these, where "left" is before the SmBraceNode and "right" is after:
* \dot
* digraph Graph{
* left -> B;
* B -> right;
* }
* \enddot
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmBraceNode* pNode )
{
SmNode* pBody = pNode->GetSubNode( 1 );
SmCaretPosGraphEntry *left = pRightMost,
*right = pGraph->Add( SmCaretPos( pNode, 1 ) );
if( pBody->GetType() != NBRACEBODY ) {
pRightMost = pGraph->Add( SmCaretPos( pBody, 0 ), left );
left->SetRight( pRightMost );
}else
pRightMost = left;
pBody->Accept( this );
pRightMost->SetRight( right );
right->SetLeft( pRightMost );
pRightMost = right;
}
/** Build SmCaretPosGraph for SmAttributNode
*
* Lines in an SmAttributNode:
* \code
* Attr
* Body
* \endcode
*
* There's a body and an attribute, the construction is used for "widehat A", where "A" is the body
* and "^" is the attribute ( note GetScaleMode( ) on SmAttributNode tells how the attribute should be
* scaled ).
*/
void SmCaretPosGraphBuildingVisitor::Visit( SmAttributNode* pNode )
{
SmNode *pAttr = pNode->GetSubNode( 0 ),
*pBody = pNode->GetSubNode( 1 );
//None of the children can be NULL
SmCaretPosGraphEntry *left = pRightMost,
*attrLeft,
*bodyLeft,
*bodyRight,
*right;
//Creating bodyleft
bodyLeft = pGraph->Add( SmCaretPos( pBody, 0 ), left );
left->SetRight( bodyLeft );
//Creating right
right = pGraph->Add( SmCaretPos( pNode, 1 ) );
//Visit the body
pRightMost = bodyLeft;
pBody->Accept( this );
bodyRight = pRightMost;
bodyRight->SetRight( right );
right->SetLeft( bodyRight );
//Create attrLeft
attrLeft = pGraph->Add( SmCaretPos( pAttr, 0 ), left );
//Visit attribute
pRightMost = attrLeft;
pAttr->Accept( this );
pRightMost->SetRight( right );
//Set return value
pRightMost = right;
}
//Consider these single symboles
void SmCaretPosGraphBuildingVisitor::Visit( SmSpecialNode* pNode )
{
SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
pRightMost->SetRight( right );
pRightMost = right;
}
void SmCaretPosGraphBuildingVisitor::Visit( SmGlyphSpecialNode* pNode )
{
SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
pRightMost->SetRight( right );
pRightMost = right;
}
void SmCaretPosGraphBuildingVisitor::Visit( SmMathSymbolNode* pNode )
{
SmCaretPosGraphEntry* right = pGraph->Add( SmCaretPos( pNode, 1 ), pRightMost );
pRightMost->SetRight( right );
pRightMost = right;
}
void SmCaretPosGraphBuildingVisitor::Visit( SmRootSymbolNode* )
{
//Do nothing
}
void SmCaretPosGraphBuildingVisitor::Visit( SmRectangleNode* )
{
//Do nothing
}
void SmCaretPosGraphBuildingVisitor::Visit( SmPolyLineNode* )
{
//Do nothing
}
/////////////////////////////// SmCloningVisitor ///////////////////////////////
SmNode* SmCloningVisitor::Clone( SmNode* pNode )
{
SmNode* pCurrResult = pResult;
pNode->Accept( this );
SmNode* pClone = pResult;
pResult = pCurrResult;
return pClone;
}
void SmCloningVisitor::CloneNodeAttr( SmNode* pSource, SmNode* pTarget )
{
pTarget->SetScaleMode( pSource->GetScaleMode( ) );
//Other attributes are set when prepare or arrange is executed
//and may depend on stuff not being cloned here.
}
void SmCloningVisitor::CloneKids( SmStructureNode* pSource, SmStructureNode* pTarget )
{
//Cache current result
SmNode* pCurrResult = pResult;
//Create array for holding clones
USHORT nSize = pSource->GetNumSubNodes( );
SmNodeArray aNodes( nSize );
//Clone children
SmNode* pKid;
for( USHORT i = 0; i < nSize; i++ ){
if( NULL != ( pKid = pSource->GetSubNode( i ) ) )
pKid->Accept( this );
else
pResult = NULL;
aNodes[i] = pResult;
}
//Set subnodes of pTarget
pTarget->SetSubNodes( aNodes );
//Restore result as where prior to call
pResult = pCurrResult;
}
void SmCloningVisitor::Visit( SmTableNode* pNode )
{
SmTableNode* pClone = new SmTableNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmBraceNode* pNode )
{
SmBraceNode* pClone = new SmBraceNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmBracebodyNode* pNode )
{
SmBracebodyNode* pClone = new SmBracebodyNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmOperNode* pNode )
{
SmOperNode* pClone = new SmOperNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmAlignNode* pNode )
{
SmAlignNode* pClone = new SmAlignNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmAttributNode* pNode )
{
SmAttributNode* pClone = new SmAttributNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmFontNode* pNode )
{
SmFontNode* pClone = new SmFontNode( pNode->GetToken( ) );
pClone->SetSizeParameter( pNode->GetSizeParameter( ), pNode->GetSizeType( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmUnHorNode* pNode )
{
SmUnHorNode* pClone = new SmUnHorNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmBinHorNode* pNode )
{
SmBinHorNode* pClone = new SmBinHorNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmBinVerNode* pNode )
{
SmBinVerNode* pClone = new SmBinVerNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmBinDiagonalNode* pNode )
{
SmBinDiagonalNode *pClone = new SmBinDiagonalNode( pNode->GetToken( ) );
pClone->SetAscending( pNode->IsAscending( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmSubSupNode* pNode )
{
SmSubSupNode *pClone = new SmSubSupNode( pNode->GetToken( ) );
pClone->SetUseLimits( pNode->IsUseLimits( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmMatrixNode* pNode )
{
SmMatrixNode *pClone = new SmMatrixNode( pNode->GetToken( ) );
pClone->SetRowCol( pNode->GetNumRows( ), pNode->GetNumCols( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmPlaceNode* pNode )
{
pResult = new SmPlaceNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmTextNode* pNode )
{
SmTextNode* pClone = new SmTextNode( pNode->GetToken( ), pNode->GetFontDesc( ) );
pClone->ChangeText( pNode->GetText( ) );
CloneNodeAttr( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmSpecialNode* pNode )
{
pResult = new SmSpecialNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmGlyphSpecialNode* pNode )
{
pResult = new SmGlyphSpecialNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmMathSymbolNode* pNode )
{
pResult = new SmMathSymbolNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmBlankNode* pNode )
{
SmBlankNode* pClone = new SmBlankNode( pNode->GetToken( ) );
pClone->SetBlankNum( pNode->GetBlankNum( ) );
pResult = pClone;
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmErrorNode* pNode )
{
//PE_NONE is used the information have been discarded and isn't used
pResult = new SmErrorNode( PE_NONE, pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmLineNode* pNode )
{
SmLineNode* pClone = new SmLineNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmExpressionNode* pNode )
{
SmExpressionNode* pClone = new SmExpressionNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmPolyLineNode* pNode )
{
pResult = new SmPolyLineNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmRootNode* pNode )
{
SmRootNode* pClone = new SmRootNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
void SmCloningVisitor::Visit( SmRootSymbolNode* pNode )
{
pResult = new SmRootSymbolNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmRectangleNode* pNode )
{
pResult = new SmRectangleNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pResult );
}
void SmCloningVisitor::Visit( SmVerticalBraceNode* pNode )
{
SmVerticalBraceNode* pClone = new SmVerticalBraceNode( pNode->GetToken( ) );
CloneNodeAttr( pNode, pClone );
CloneKids( pNode, pClone );
pResult = pClone;
}
/////////////////////////////// SmSelectionDrawingVisitor ///////////////////////////////
SmSelectionDrawingVisitor::SmSelectionDrawingVisitor( OutputDevice& rDevice, SmNode* pTree, Point Offset )
: rDev( rDevice ) {
bHasSelectionArea = false;
//Visit everything
j_assert( pTree, "pTree can't be null!" );
if( pTree )
pTree->Accept( this );
//Draw selection if there's any
if( bHasSelectionArea ){
aSelectionArea.Move( Offset.X( ), Offset.Y( ) );
//Save device state
rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
//Change colors
rDev.SetLineColor( );
rDev.SetFillColor( Color( COL_LIGHTGRAY ) );
//Draw rectangle
rDev.DrawRect( aSelectionArea );
//Restore device state
rDev.Pop( );
}
}
void SmSelectionDrawingVisitor::ExtendSelectionArea( Rectangle aArea )
{
if ( ! bHasSelectionArea ) {
aSelectionArea = aArea;
bHasSelectionArea = true;
} else
aSelectionArea.Union( aArea );
}
void SmSelectionDrawingVisitor::DefaultVisit( SmNode* pNode )
{
if( pNode->IsSelected( ) )
ExtendSelectionArea( pNode->AsRectangle( ) );
VisitChildren( pNode );
}
void SmSelectionDrawingVisitor::VisitChildren( SmNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) )
it->Accept( this );
}
void SmSelectionDrawingVisitor::Visit( SmTextNode* pNode )
{
if( pNode->IsSelected( ) ){
rDev.Push( PUSH_TEXTCOLOR | PUSH_FONT );
rDev.SetFont( pNode->GetFont( ) );
Point Position = pNode->GetTopLeft( );
long left = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionStart( ) );
long right = Position.getX( ) + rDev.GetTextWidth( pNode->GetText( ), 0, pNode->GetSelectionEnd( ) );
long top = Position.getY( );
long bottom = top + pNode->GetHeight( );
Rectangle rect( left, top, right, bottom );
ExtendSelectionArea( rect );
rDev.Pop( );
}
}
/////////////////////////////// SmNodeToTextVisitor ///////////////////////////////
void SmNodeToTextVisitor::Visit( SmTableNode* pNode )
{
if( pNode->GetToken( ).eType == TBINOM ) {
Append( "binom" );
LineToText( pNode->GetSubNode( 0 ) );
LineToText( pNode->GetSubNode( 1 ) );
} else if( pNode->GetToken( ).eType == TSTACK ) {
Append( "stack{ " );
SmNodeIterator it( pNode );
it.Next( );
while( true ) {
LineToText( it.Current( ) );
if( it.Next( ) ) {
Separate( );
Append( "## " );
}else
break;
}
Separate( );
Append( "}" );
} else { //Assume it's a toplevel table, containing lines
SmNodeIterator it( pNode );
it.Next( );
while( true ) {
Separate( );
it->Accept( this );
if( it.Next( ) ) {
Separate( );
Append( "newline" );
}else
break;
}
}
}
void SmNodeToTextVisitor::Visit( SmBraceNode* pNode )
{
SmNode *pLeftBrace = pNode->GetSubNode( 0 ),
*pBody = pNode->GetSubNode( 1 ),
*pRightBrace = pNode->GetSubNode( 2 );
//Handle special case where it's absolute function
if( pNode->GetToken( ).eType == TABS ) {
Append( "abs" );
LineToText( pBody );
} else {
if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
Append( "left " );
pLeftBrace->Accept( this );
Separate( );
pBody->Accept( this );
Separate( );
if( pNode->GetScaleMode( ) == SCALE_HEIGHT )
Append( "right " );
pRightBrace->Accept( this );
}
}
void SmNodeToTextVisitor::Visit( SmBracebodyNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) ){
Separate( );
it->Accept( this );
}
}
void SmNodeToTextVisitor::Visit( SmOperNode* pNode )
{
Append( pNode->GetToken( ).aText );
Separate( );
if( pNode->GetToken( ).eType == TOPER ){
//There's an SmGlyphSpecialNode if eType == TOPER
if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP )
Append( pNode->GetSubNode( 0 )->GetSubNode( 0 )->GetToken( ).aText );
else
Append( pNode->GetSubNode( 0 )->GetToken( ).aText );
}
if( pNode->GetSubNode( 0 )->GetType( ) == NSUBSUP ) {
SmSubSupNode *pSubSup = ( SmSubSupNode* )pNode->GetSubNode( 0 );
SmNode* pChild;
if( ( pChild = pSubSup->GetSubSup( LSUP ) ) ) {
Separate( );
Append( "lsup " );
LineToText( pChild );
}
if( ( pChild = pSubSup->GetSubSup( LSUB ) ) ) {
Separate( );
Append( "lsub " );
LineToText( pChild );
}
if( ( pChild = pSubSup->GetSubSup( RSUP ) ) ) {
Separate( );
Append( "rsup " );
LineToText( pChild );
}
if( ( pChild = pSubSup->GetSubSup( RSUB ) ) ) {
Separate( );
Append( "rsub " );
LineToText( pChild );
}
if( ( pChild = pSubSup->GetSubSup( CSUP ) ) ) {
Separate( );
Append( "csup " );
LineToText( pChild );
}
if( ( pChild = pSubSup->GetSubSup( CSUB ) ) ) {
Separate( );
Append( "csub " );
LineToText( pChild );
}
}
LineToText( pNode->GetSubNode( 1 ) );
}
void SmNodeToTextVisitor::Visit( SmAlignNode* pNode )
{
Append( pNode->GetToken( ).aText );
LineToText( pNode->GetSubNode( 0 ) );
}
void SmNodeToTextVisitor::Visit( SmAttributNode* pNode )
{
Append( pNode->GetToken( ).aText );
LineToText( pNode->GetSubNode( 1 ) );
}
void SmNodeToTextVisitor::Visit( SmFontNode* pNode )
{
switch ( pNode->GetToken( ).eType )
{
case TBOLD:
Append( "bold " );
break;
case TNBOLD:
Append( "nbold " );
break;
case TITALIC:
Append( "italic " );
break;
case TNITALIC:
Append( "nitalic " );
break;
case TPHANTOM:
Append( "phantom " );
break;
case TSIZE:
{
Append( "size " );
switch ( pNode->GetSizeType( ) )
{
case FNTSIZ_PLUS:
Append( "+" );
break;
case FNTSIZ_MINUS:
Append( "-" );
break;
case FNTSIZ_MULTIPLY:
Append( "*" );
break;
case FNTSIZ_DIVIDE:
Append( "/" );
break;
case FNTSIZ_ABSOLUT:
default:
break;
}
Append( String( ::rtl::math::doubleToUString(
static_cast<double>( pNode->GetSizeParameter( ) ),
rtl_math_StringFormat_Automatic,
rtl_math_DecimalPlaces_Max, '.', sal_True ) ) );
Append( " " );
}
break;
case TBLACK:
Append( "color black " );
break;
case TWHITE:
Append( "color white " );
break;
case TRED:
Append( "color red " );
break;
case TGREEN:
Append( "color green " );
break;
case TBLUE:
Append( "color blue " );
break;
case TCYAN:
Append( "color cyan " );
break;
case TMAGENTA:
Append( "color magenta " );
break;
case TYELLOW:
Append( "color yellow " );
break;
case TSANS:
Append( "font sans " );
break;
case TSERIF:
Append( "font serif " );
break;
case TFIXED:
Append( "font fixed " );
break;
default:
break;
}
LineToText( pNode->GetSubNode( 1 ) );
}
void SmNodeToTextVisitor::Visit( SmUnHorNode* pNode )
{
Append( "{" );
SmNodeIterator it( pNode, pNode->GetSubNode( 1 )->GetToken( ).eType == TFACT );
while( it.Next( ) ) {
Separate( );
it->Accept( this );
}
Append( " }" );
}
void SmNodeToTextVisitor::Visit( SmBinHorNode* pNode )
{
Append( "{" );
SmNode *pLeft = pNode->GetSubNode( 0 ),
*pOper = pNode->GetSubNode( 1 ),
*pRight = pNode->GetSubNode( 2 );
Separate( );
pLeft->Accept( this );
Separate( );
pOper->Accept( this );
Separate( );
pRight->Accept( this );
Separate( );
Append( "}" );
}
void SmNodeToTextVisitor::Visit( SmBinVerNode* pNode )
{
SmNode *pNum = pNode->GetSubNode( 0 ),
*pDenom = pNode->GetSubNode( 2 );
LineToText( pNum );
Append( "over" );
LineToText( pDenom );
}
void SmNodeToTextVisitor::Visit( SmBinDiagonalNode* pNode )
{
SmNode *pLeftOperand = pNode->GetSubNode( 0 ),
*pRightOperand = pNode->GetSubNode( 1 );
LineToText( pLeftOperand );
Separate( );
Append( "wideslash " );
LineToText( pRightOperand );
}
void SmNodeToTextVisitor::Visit( SmSubSupNode* pNode )
{
LineToText( pNode->GetBody( ) );
SmNode *pChild;
if( ( pChild = pNode->GetSubSup( LSUP ) ) ) {
Separate( );
Append( "lsup " );
LineToText( pChild );
}
if( ( pChild = pNode->GetSubSup( LSUB ) ) ) {
Separate( );
Append( "lsub " );
LineToText( pChild );
}
if( ( pChild = pNode->GetSubSup( RSUP ) ) ) {
Separate( );
Append( "rsup " );
LineToText( pChild );
}
if( ( pChild = pNode->GetSubSup( RSUB ) ) ) {
Separate( );
Append( "rsub " );
LineToText( pChild );
}
if( ( pChild = pNode->GetSubSup( CSUP ) ) ) {
Separate( );
Append( "csup " );
LineToText( pChild );
}
if( ( pChild = pNode->GetSubSup( CSUB ) ) ) {
Separate( );
Append( "csub " );
LineToText( pChild );
}
}
void SmNodeToTextVisitor::Visit( SmMatrixNode* pNode )
{
Append( "matrix{" );
for ( USHORT i = 0; i < pNode->GetNumRows( ); i++ ) {
for ( USHORT j = 0; j < pNode->GetNumCols( ); j++ ) {
SmNode* pSubNode = pNode->GetSubNode( i * pNode->GetNumCols( ) + j );
Separate( );
pSubNode->Accept( this );
Separate( );
if( j != pNode->GetNumCols( ) - 1 )
Append( "#" );
}
Separate( );
if( i != pNode->GetNumRows( ) - 1 )
Append( "##" );
}
Append( "}" );
}
void SmNodeToTextVisitor::Visit( SmPlaceNode* )
{
Append( "<?>" );
}
void SmNodeToTextVisitor::Visit( SmTextNode* pNode )
{
//TODO: This method might need improvements, see SmTextNode::CreateTextFromNode
if( pNode->GetToken( ).eType == TTEXT )
Append( "\"" );
Append( pNode->GetText( ) );
if( pNode->GetToken( ).eType == TTEXT )
Append( "\"" );
}
void SmNodeToTextVisitor::Visit( SmSpecialNode* pNode )
{
Append( "%" );
Append( pNode->GetToken( ).aText );
}
void SmNodeToTextVisitor::Visit( SmGlyphSpecialNode* pNode )
{
if( pNode->GetToken( ).eType == TBOPER )
Append( "boper " );
else
Append( "uoper " );
Append( pNode->GetToken( ).aText );
}
void SmNodeToTextVisitor::Visit( SmMathSymbolNode* pNode )
{
Append( pNode->GetToken( ).aText );
}
void SmNodeToTextVisitor::Visit( SmBlankNode* pNode )
{
Append( pNode->GetToken( ).aText );
}
void SmNodeToTextVisitor::Visit( SmErrorNode* )
{
}
void SmNodeToTextVisitor::Visit( SmLineNode* pNode )
{
SmNodeIterator it( pNode );
while( it.Next( ) ){
Separate( );
it->Accept( this );
}
}
void SmNodeToTextVisitor::Visit( SmExpressionNode* pNode )
{
Append( "{ " );
SmNodeIterator it( pNode );
while( it.Next( ) ) {
it->Accept( this );
Separate( );
}
Append( "}" );
}
void SmNodeToTextVisitor::Visit( SmPolyLineNode* )
{
}
void SmNodeToTextVisitor::Visit( SmRootNode* pNode )
{
SmNode *pExtra = pNode->GetSubNode( 0 ),
*pBody = pNode->GetSubNode( 2 );
if( pExtra ) {
Append( "nroot" );
LineToText( pExtra );
} else
Append( "sqrt" );
LineToText( pBody );
}
void SmNodeToTextVisitor::Visit( SmRootSymbolNode* )
{
}
void SmNodeToTextVisitor::Visit( SmRectangleNode* )
{
}
void SmNodeToTextVisitor::Visit( SmVerticalBraceNode* pNode )
{
SmNode *pBody = pNode->GetSubNode( 0 ),
*pScript = pNode->GetSubNode( 2 );
LineToText( pBody );
Append( pNode->GetToken( ).aText );
LineToText( pScript );
}