1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: node.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_starmath.hxx"
34 #define APPEND(str,ascii) str.AppendAscii(RTL_CONSTASCII_STRINGPARAM(ascii))
35 #include <tools/gen.hxx>
36 #include <tools/fract.hxx>
37 #include <rtl/math.hxx>
38 #include <tools/color.hxx>
39 #include <vcl/metric.hxx>
40 #include <vcl/lineinfo.hxx>
41 #include <vcl/outdev.hxx>
42 #include <sfx2/module.hxx>
49 #include <document.hxx>
52 #include "mathtype.hxx"
58 // define this to draw rectangles for debugging
59 //#define SM_RECT_DEBUG
61 ////////////////////////////////////////
63 // Allows for font and color changes. The original settings will be restored
65 // It's main purpose is to allow for the "const" in the 'OutputDevice'
66 // argument in the 'Arrange' functions and restore changes made in the 'Draw'
68 // Usually a MapMode of 1/100th mm will be used.
73 OutputDevice
&rOutDev
;
75 // disallow use of copy-constructor and assignment-operator
76 SmTmpDevice(const SmTmpDevice
&rTmpDev
);
77 SmTmpDevice
& operator = (const SmTmpDevice
&rTmpDev
);
79 Color
Impl_GetColor( const Color
& rColor
);
82 SmTmpDevice(OutputDevice
&rTheDev
, BOOL bUseMap100th_mm
);
83 ~SmTmpDevice() { rOutDev
.Pop(); }
85 void SetFont(const Font
&rNewFont
);
87 void SetLineColor( const Color
& rColor
) { rOutDev
.SetLineColor( Impl_GetColor(rColor
) ); }
88 void SetFillColor( const Color
& rColor
) { rOutDev
.SetFillColor( Impl_GetColor(rColor
) ); }
89 void SetTextColor( const Color
& rColor
) { rOutDev
.SetTextColor( Impl_GetColor(rColor
) ); }
91 operator OutputDevice
& () { return rOutDev
; }
95 SmTmpDevice::SmTmpDevice(OutputDevice
&rTheDev
, BOOL bUseMap100th_mm
) :
98 rOutDev
.Push( PUSH_FONT
| PUSH_MAPMODE
|
99 PUSH_LINECOLOR
| PUSH_FILLCOLOR
| PUSH_TEXTCOLOR
);
100 if (bUseMap100th_mm
&& MAP_100TH_MM
!= rOutDev
.GetMapMode().GetMapUnit())
102 DBG_ERROR( "incorrect MapMode?" );
103 rOutDev
.SetMapMode( MAP_100TH_MM
); //Immer fuer 100% fomatieren
108 Color
SmTmpDevice::Impl_GetColor( const Color
& rColor
)
110 ColorData nNewCol
= rColor
.GetColor();
111 if (COL_AUTO
== nNewCol
)
113 if (OUTDEV_PRINTER
== rOutDev
.GetOutDevType())
117 Color
aBgCol( rOutDev
.GetBackground().GetColor() );
118 if (OUTDEV_WINDOW
== rOutDev
.GetOutDevType())
119 aBgCol
= ((Window
&) rOutDev
).GetDisplayBackground().GetColor();
121 nNewCol
= SM_MOD1()->GetColorConfig().GetColorValue(svtools::FONTCOLOR
).nColor
;
123 Color
aTmpColor( nNewCol
);
124 if (aBgCol
.IsDark() && aTmpColor
.IsDark())
126 else if (aBgCol
.IsBright() && aTmpColor
.IsBright())
130 return Color( nNewCol
);
134 void SmTmpDevice::SetFont(const Font
&rNewFont
)
136 rOutDev
.SetFont( rNewFont
);
137 rOutDev
.SetTextColor( Impl_GetColor( rNewFont
.GetColor() ) );
141 ///////////////////////////////////////////////////////////////////////////
144 SmNode::SmNode(SmNodeType eNodeType
, const SmToken
&rNodeToken
)
147 eScaleMode
= SCALE_NONE
;
148 aNodeToken
= rNodeToken
;
158 BOOL
SmNode::IsVisible() const
164 USHORT
SmNode::GetNumSubNodes() const
170 SmNode
* SmNode::GetSubNode(USHORT
/*nIndex*/)
176 SmNode
* SmNode::GetLeftMost()
177 // returns leftmost node of current subtree.
178 //! (this assumes the one with index 0 is always the leftmost subnode
179 //! for the current node).
181 SmNode
*pNode
= GetNumSubNodes() > 0 ?
182 GetSubNode(0) : NULL
;
184 return pNode
? pNode
->GetLeftMost() : this;
188 void SmNode::SetPhantom(BOOL bIsPhantomP
)
190 if (! (Flags() & FLG_VISIBLE
))
191 bIsPhantom
= bIsPhantomP
;
194 USHORT nSize
= GetNumSubNodes();
195 for (USHORT i
= 0; i
< nSize
; i
++)
196 if (NULL
!= (pNode
= GetSubNode(i
)))
197 pNode
->SetPhantom(bIsPhantom
);
201 void SmNode::SetColor(const Color
& rColor
)
203 if (! (Flags() & FLG_COLOR
))
204 GetFont().SetColor(rColor
);
207 USHORT nSize
= GetNumSubNodes();
208 for (USHORT i
= 0; i
< nSize
; i
++)
209 if (NULL
!= (pNode
= GetSubNode(i
)))
210 pNode
->SetColor(rColor
);
214 void SmNode::SetAttribut(USHORT nAttrib
)
217 (nAttrib
== ATTR_BOLD
&& !(Flags() & FLG_BOLD
)) ||
218 (nAttrib
== ATTR_ITALIC
&& !(Flags() & FLG_ITALIC
))
221 nAttributes
|= nAttrib
;
225 USHORT nSize
= GetNumSubNodes();
226 for (USHORT i
= 0; i
< nSize
; i
++)
227 if (NULL
!= (pNode
= GetSubNode(i
)))
228 pNode
->SetAttribut(nAttrib
);
232 void SmNode::ClearAttribut(USHORT nAttrib
)
235 (nAttrib
== ATTR_BOLD
&& !(Flags() & FLG_BOLD
)) ||
236 (nAttrib
== ATTR_ITALIC
&& !(Flags() & FLG_ITALIC
))
239 nAttributes
&= ~nAttrib
;
243 USHORT nSize
= GetNumSubNodes();
244 for (USHORT i
= 0; i
< nSize
; i
++)
245 if (NULL
!= (pNode
= GetSubNode(i
)))
246 pNode
->ClearAttribut(nAttrib
);
250 void SmNode::SetFont(const SmFace
&rFace
)
252 if (!(Flags() & FLG_FONT
))
256 USHORT nSize
= GetNumSubNodes();
257 for (USHORT i
= 0; i
< nSize
; i
++)
258 if (NULL
!= (pNode
= GetSubNode(i
)))
259 pNode
->SetFont(rFace
);
263 void SmNode::SetFontSize(const Fraction
&rSize
, USHORT nType
)
264 //! 'rSize' is in units of pts
268 if (!(Flags() & FLG_SIZE
))
270 Fraction
aVal (SmPtsTo100th_mm(rSize
.GetNumerator()),
271 rSize
.GetDenominator());
272 //long nHeight = ::rtl::math::round(aVal);
273 long nHeight
= (long)aVal
;
275 aFntSize
= GetFont().GetSize();
276 aFntSize
.Width() = 0;
280 aFntSize
.Height() = nHeight
;
284 aFntSize
.Height() += nHeight
;
288 aFntSize
.Height() -= nHeight
;
291 case FNTSIZ_MULTIPLY
:
292 aFntSize
.Height() = (long) (Fraction(aFntSize
.Height()) * rSize
);
296 if (rSize
!= Fraction(0L))
297 aFntSize
.Height() = (long) (Fraction(aFntSize
.Height()) / rSize
);
303 // check the requested size against maximum value
304 static int __READONLY_DATA nMaxVal
= SmPtsTo100th_mm(128);
305 if (aFntSize
.Height() > nMaxVal
)
306 aFntSize
.Height() = nMaxVal
;
308 GetFont().SetSize(aFntSize
);
312 USHORT nSize
= GetNumSubNodes();
313 for (USHORT i
= 0; i
< nSize
; i
++)
314 if (NULL
!= (pNode
= GetSubNode(i
)))
315 pNode
->SetFontSize(rSize
, nType
);
319 void SmNode::SetSize(const Fraction
&rSize
)
324 USHORT nSize
= GetNumSubNodes();
325 for (USHORT i
= 0; i
< nSize
; i
++)
326 if (NULL
!= (pNode
= GetSubNode(i
)))
327 pNode
->SetSize(rSize
);
331 void SmNode::SetRectHorAlign(RectHorAlign eHorAlign
, BOOL bApplyToSubTree
)
333 if (!(Flags() & FLG_HORALIGN
))
334 eRectHorAlign
= eHorAlign
;
339 USHORT nSize
= GetNumSubNodes();
340 for (USHORT i
= 0; i
< nSize
; i
++)
341 if (NULL
!= (pNode
= GetSubNode(i
)))
342 pNode
->SetRectHorAlign(eHorAlign
);
347 void SmNode::PrepareAttributes()
349 GetFont().SetWeight((Attributes() & ATTR_BOLD
) ? WEIGHT_BOLD
: WEIGHT_NORMAL
);
350 GetFont().SetItalic((Attributes() & ATTR_ITALIC
) ? ITALIC_NORMAL
: ITALIC_NONE
);
354 void SmNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
356 #if OSL_DEBUG_LEVEL > 1
365 switch (rFormat
.GetHorAlign())
366 { case AlignLeft
: eRectHorAlign
= RHA_LEFT
; break;
367 case AlignCenter
: eRectHorAlign
= RHA_CENTER
; break;
368 case AlignRight
: eRectHorAlign
= RHA_RIGHT
; break;
371 GetFont() = rFormat
.GetFont(FNT_MATH
);
372 //GetFont().SetCharSet(RTL_TEXTENCODING_SYMBOL);
373 DBG_ASSERT( GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE
,
374 "unexpected CharSet" );
375 GetFont().SetWeight(WEIGHT_NORMAL
);
376 GetFont().SetItalic(ITALIC_NONE
);
379 USHORT nSize
= GetNumSubNodes();
380 for (USHORT i
= 0; i
< nSize
; i
++)
381 if (NULL
!= (pNode
= GetSubNode(i
)))
382 pNode
->Prepare(rFormat
, rDocShell
);
386 #if OSL_DEBUG_LEVEL > 1
387 void SmNode::ToggleDebug() const
388 // toggle 'bIsDebug' in current subtree
390 SmNode
*pThis
= (SmNode
*) this;
392 pThis
->bIsDebug
= bIsDebug
? FALSE
: TRUE
;
395 USHORT nSize
= GetNumSubNodes();
396 for (USHORT i
= 0; i
< nSize
; i
++)
397 if (NULL
!= (pNode
= pThis
->GetSubNode(i
)))
398 pNode
->ToggleDebug();
403 void SmNode::Move(const Point
& rPosition
)
405 if (rPosition
.X() == 0 && rPosition
.Y() == 0)
408 SmRect::Move(rPosition
);
411 USHORT nSize
= GetNumSubNodes();
412 for (USHORT i
= 0; i
< nSize
; i
++)
413 if (NULL
!= (pNode
= GetSubNode(i
)))
414 pNode
->Move(rPosition
);
418 void SmNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
421 USHORT nSize
= GetNumSubNodes();
422 for (USHORT i
= 0; i
< nSize
; i
++)
423 if (NULL
!= (pNode
= GetSubNode(i
)))
424 pNode
->Arrange(rDev
, rFormat
);
427 void SmNode::CreateTextFromNode(String
&rText
)
430 USHORT nSize
= GetNumSubNodes();
433 for (USHORT i
= 0; i
< nSize
; i
++)
434 if (NULL
!= (pNode
= GetSubNode(i
)))
435 pNode
->CreateTextFromNode(rText
);
438 rText
.EraseTrailingChars();
444 void SmNode::AdaptToX(const OutputDevice
&/*rDev*/, ULONG
/*nWidth*/)
449 void SmNode::AdaptToY(const OutputDevice
&/*rDev*/, ULONG
/*nHeight*/)
454 void SmNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
460 USHORT nSize
= GetNumSubNodes();
461 for (USHORT i
= 0; i
< nSize
; i
++)
462 if (NULL
!= (pNode
= GetSubNode(i
)))
463 { Point
aOffset (pNode
->GetTopLeft() - GetTopLeft());
464 pNode
->Draw(rDev
, rPosition
+ aOffset
);
471 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
472 SmRect::Draw(rDev
, rPosition
, nRFlags
);
476 const SmNode
* SmNode::FindTokenAt(USHORT nRow
, USHORT nCol
) const
477 // returns (first) ** visible ** (sub)node with the tokens text at
478 // position 'nRow', 'nCol'.
479 //! (there should be exactly one such node if any)
482 && nRow
== GetToken().nRow
483 && nCol
>= GetToken().nCol
&& nCol
< GetToken().nCol
+ GetToken().aText
.Len())
487 USHORT nNumSubNodes
= GetNumSubNodes();
488 for (USHORT i
= 0; i
< nNumSubNodes
; i
++)
489 { const SmNode
*pNode
= GetSubNode(i
);
494 const SmNode
*pResult
= pNode
->FindTokenAt(nRow
, nCol
);
504 const SmNode
* SmNode::FindRectClosestTo(const Point
&rPoint
) const
506 long nDist
= LONG_MAX
;
507 const SmNode
*pResult
= 0;
513 USHORT nNumSubNodes
= GetNumSubNodes();
514 for (USHORT i
= 0; i
< nNumSubNodes
; i
++)
515 { const SmNode
*pNode
= GetSubNode(i
);
521 const SmNode
*pFound
= pNode
->FindRectClosestTo(rPoint
);
522 if (pFound
&& (nTmp
= pFound
->OrientedDist(rPoint
)) < nDist
)
526 // quit immediately if 'rPoint' is inside the *should not
527 // overlap with other rectangles* part.
528 // This (partly) serves for getting the attributes in eg
529 // "bar overstrike a".
530 // ('nDist < 0' is used as *quick shot* to avoid evaluation of
531 // the following expression, where the result is already determined)
532 if (nDist
< 0 && pFound
->IsInsideRect(rPoint
))
541 void SmNode::GetAccessibleText( String
&/*rText*/ ) const
543 DBG_ERROR( "SmNode: GetAccessibleText not overloaded" );
546 const SmNode
* SmNode::FindNodeWithAccessibleIndex(xub_StrLen nAccIdx
) const
548 const SmNode
*pResult
= 0;
550 sal_Int32 nIdx
= GetAccessibleIndex();
553 GetAccessibleText( aTxt
); // get text if used in following 'if' statement
556 && nIdx
<= nAccIdx
&& nAccIdx
< nIdx
+ aTxt
.Len())
560 USHORT nNumSubNodes
= GetNumSubNodes();
561 for (USHORT i
= 0; i
< nNumSubNodes
; i
++)
563 const SmNode
*pNode
= GetSubNode(i
);
567 pResult
= pNode
->FindNodeWithAccessibleIndex(nAccIdx
);
576 ///////////////////////////////////////////////////////////////////////////
578 SmStructureNode::SmStructureNode( const SmStructureNode
&rNode
) :
579 SmNode( rNode
.GetType(), rNode
.GetToken() )
582 for (i
= 0; i
< aSubNodes
.size(); i
++)
586 ULONG nSize
= rNode
.aSubNodes
.size();
587 aSubNodes
.resize( nSize
);
588 for (i
= 0; i
< nSize
; ++i
)
590 SmNode
*pNode
= rNode
.aSubNodes
[i
];
591 aSubNodes
[i
] = pNode
? new SmNode( *pNode
) : 0;
596 SmStructureNode::~SmStructureNode()
600 for (USHORT i
= 0; i
< GetNumSubNodes(); i
++)
601 if (NULL
!= (pNode
= GetSubNode(i
)))
606 SmStructureNode
& SmStructureNode::operator = ( const SmStructureNode
&rNode
)
608 SmNode::operator = ( rNode
);
611 for (i
= 0; i
< aSubNodes
.size(); i
++)
615 ULONG nSize
= rNode
.aSubNodes
.size();
616 aSubNodes
.resize( nSize
);
617 for (i
= 0; i
< nSize
; ++i
)
619 SmNode
*pNode
= rNode
.aSubNodes
[i
];
620 aSubNodes
[i
] = pNode
? new SmNode( *pNode
) : 0;
627 void SmStructureNode::SetSubNodes(SmNode
*pFirst
, SmNode
*pSecond
, SmNode
*pThird
)
629 size_t nSize
= pThird
? 3 : (pSecond
? 2 : (pFirst
? 1 : 0));
630 aSubNodes
.resize( nSize
);
632 aSubNodes
[0] = pFirst
;
634 aSubNodes
[1] = pSecond
;
636 aSubNodes
[2] = pThird
;
640 void SmStructureNode::SetSubNodes(const SmNodeArray
&rNodeArray
)
642 aSubNodes
= rNodeArray
;
646 BOOL
SmStructureNode::IsVisible() const
652 USHORT
SmStructureNode::GetNumSubNodes() const
654 return (USHORT
) aSubNodes
.size();
658 SmNode
* SmStructureNode::GetSubNode(USHORT nIndex
)
660 return aSubNodes
[nIndex
];
664 void SmStructureNode::GetAccessibleText( String
&rText
) const
666 USHORT nNodes
= GetNumSubNodes();
667 for (USHORT i
= 0; i
< nNodes
; ++i
)
669 const SmNode
*pNode
= ((SmStructureNode
*) this)->GetSubNode(i
);
672 if (pNode
->IsVisible())
673 ((SmStructureNode
*) pNode
)->nAccIndex
= rText
.Len();
674 pNode
->GetAccessibleText( rText
);
675 // if (rText.Len() && ' ' != rText.GetChar( rText.Len() - 1 ))
676 // rText += String::CreateFromAscii( " " );
681 ///////////////////////////////////////////////////////////////////////////
684 BOOL
SmVisibleNode::IsVisible() const
690 USHORT
SmVisibleNode::GetNumSubNodes() const
696 SmNode
* SmVisibleNode::GetSubNode(USHORT
/*nIndex*/)
702 ///////////////////////////////////////////////////////////////////////////
704 void SmGraphicNode::GetAccessibleText( String
&rText
) const
706 rText
+= GetToken().aText
;
709 ///////////////////////////////////////////////////////////////////////////
712 void SmExpressionNode::CreateTextFromNode(String
&rText
)
715 USHORT nSize
= GetNumSubNodes();
718 for (USHORT i
= 0; i
< nSize
; i
++)
719 if (NULL
!= (pNode
= GetSubNode(i
)))
721 pNode
->CreateTextFromNode(rText
);
722 //Just a bit of foo to make unary +asd -asd +-asd -+asd look nice
723 if (pNode
->GetType() == NMATH
)
724 if ((nSize
!= 2) || ((rText
.GetChar(rText
.Len()-1) != '+') &&
725 (rText
.GetChar(rText
.Len()-1) != '-')))
731 rText
.EraseTrailingChars();
737 ///////////////////////////////////////////////////////////////////////////
739 void SmTableNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
740 // arranges all subnodes in one column
745 USHORT nSize
= GetNumSubNodes();
747 // make distance depend on font size
748 long nDist
= +(rFormat
.GetDistance(DIS_VERTICAL
)
749 * GetFont().GetSize().Height()) / 100L;
754 // arrange subnodes and get maximum width of them
758 for (i
= 0; i
< nSize
; i
++)
759 if (NULL
!= (pNode
= GetSubNode(i
)))
760 { pNode
->Arrange(rDev
, rFormat
);
761 if ((nTmp
= pNode
->GetItalicWidth()) > nMaxWidth
)
766 SmRect::operator = (SmRect(nMaxWidth
, 0));
767 for (i
= 0; i
< nSize
; i
++)
768 { if (NULL
!= (pNode
= GetSubNode(i
)))
769 { const SmRect
&rNodeRect
= pNode
->GetRect();
770 const SmNode
*pCoNode
= pNode
->GetLeftMost();
771 //SmTokenType eType = pCoNode->GetToken().eType;
772 RectHorAlign eHorAlign
= pCoNode
->GetRectHorAlign();
774 aPos
= rNodeRect
.AlignTo(*this, RP_BOTTOM
,
775 eHorAlign
, RVA_BASELINE
);
779 ExtendBy(rNodeRect
, nSize
> 1 ? RCP_NONE
: RCP_ARG
);
785 SmNode
* SmTableNode::GetLeftMost()
791 /**************************************************************************/
794 void SmLineNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
796 SmNode::Prepare(rFormat
, rDocShell
);
798 //! wir verwenden hier den 'FNT_VARIABLE' Font, da er vom Ascent und Descent
799 //! ia besser zum Rest der Formel passt als der 'FNT_MATH' Font.
800 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
805 /**************************************************************************/
808 void SmLineNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
809 // arranges all subnodes in one row with some extra space between
812 USHORT nSize
= GetNumSubNodes();
814 for (i
= 0; i
< nSize
; i
++)
815 if (NULL
!= (pNode
= GetSubNode(i
)))
816 pNode
->Arrange(rDev
, rFormat
);
818 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
819 aTmpDev
.SetFont(GetFont());
821 // provide an empty rectangle with alignment parameters for the "current"
822 // font (in order to make "a^1 {}_2^3 a_4" work correct, that is, have the
823 // same sub-/supscript positions.)
824 //! be sure to use a character that has explicitly defined HiAttribut
825 //! line in rect.cxx such as 'a' in order to make 'vec a' look same to
827 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, C2S("a"),
828 GetFont().GetBorderWidth()));
829 // make sure that the rectangle occupies (almost) no space
831 SetItalicSpaces(0, 0);
836 // make distance depend on font size
837 long nDist
= +(rFormat
.GetDistance(DIS_HORIZONTAL
)
838 * GetFont().GetSize().Height()) / 100L;
841 for (i
= 0; i
< nSize
; i
++)
842 if (NULL
!= (pNode
= GetSubNode(i
)))
844 aPos
= pNode
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
846 // no horizontal space before first node
851 ExtendBy( *pNode
, RCP_XOR
);
856 /**************************************************************************/
859 void SmExpressionNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
860 // as 'SmLineNode::Arrange' but keeps alignment of leftmost subnode
862 SmLineNode::Arrange(rDev
, rFormat
);
864 // copy alignment of leftmost subnode if any
865 SmNode
*pNode
= GetLeftMost();
867 SetRectHorAlign(pNode
->GetRectHorAlign(), FALSE
);
871 /**************************************************************************/
874 void SmUnHorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
876 BOOL bIsPostfix
= GetToken().eType
== TFACT
;
878 SmNode
*pOper
= GetSubNode(bIsPostfix
? 1 : 0),
879 *pBody
= GetSubNode(bIsPostfix
? 0 : 1);
880 DBG_ASSERT(pOper
, "Sm: NULL pointer");
881 DBG_ASSERT(pBody
, "Sm: NULL pointer");
883 pOper
->SetSize(Fraction (rFormat
.GetRelSize(SIZ_OPERATOR
), 100));
884 pOper
->Arrange(rDev
, rFormat
);
885 pBody
->Arrange(rDev
, rFormat
);
887 Point aPos
= pOper
->AlignTo(*pBody
, bIsPostfix
? RP_RIGHT
: RP_LEFT
,
888 RHA_CENTER
, RVA_BASELINE
);
889 // add a bit space between operator and argument
890 // (worst case -{1 over 2} where - and over have almost no space inbetween)
891 long nDelta
= pOper
->GetFont().GetSize().Height() / 20;
898 SmRect::operator = (*pBody
);
899 long nOldBot
= GetBottom();
901 ExtendBy(*pOper
, RCP_XOR
);
903 // workaround for Bug 50865: "a^2 a^+2" have different baselines
904 // for exponents (if size of exponent is large enough)
909 /**************************************************************************/
912 void SmRootNode::GetHeightVerOffset(const SmRect
&rRect
,
913 long &rHeight
, long &rVerOffset
) const
914 // calculate height and vertical offset of root sign suitable for 'rRect'
916 rVerOffset
= (rRect
.GetBottom() - rRect
.GetAlignB()) / 2;
917 rHeight
= rRect
.GetHeight() - rVerOffset
;
919 DBG_ASSERT(rHeight
>= 0, "Sm : Ooops...");
920 DBG_ASSERT(rVerOffset
>= 0, "Sm : Ooops...");
924 Point
SmRootNode::GetExtraPos(const SmRect
&rRootSymbol
,
925 const SmRect
&rExtra
) const
927 const Size
&rSymSize
= rRootSymbol
.GetSize();
929 Point aPos
= rRootSymbol
.GetTopLeft()
930 + Point((rSymSize
.Width() * 70) / 100,
931 (rSymSize
.Height() * 52) / 100);
933 // from this calculate topleft edge of 'rExtra'
934 aPos
.X() -= rExtra
.GetWidth() + rExtra
.GetItalicRightSpace();
935 aPos
.Y() -= rExtra
.GetHeight();
936 // if there's enough space move a bit less to the right
937 // examples: "nroot i a", "nroot j a"
938 // (it looks better if we don't use italic-spaces here)
939 long nX
= rRootSymbol
.GetLeft() + (rSymSize
.Width() * 30) / 100;
947 void SmRootNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
949 //! pExtra needs to have the smaller index than pRootSym in order to
950 //! not to get the root symbol but the pExtra when clicking on it in the
951 //! GraphicWindow. (That is because of the simplicity of the algorithm
952 //! that finds the node corresponding to a mouseclick in the window.)
953 SmNode
*pExtra
= GetSubNode(0),
954 *pRootSym
= GetSubNode(1),
955 *pBody
= GetSubNode(2);
956 DBG_ASSERT(pRootSym
, "Sm: NULL pointer");
957 DBG_ASSERT(pBody
, "Sm: NULL pointer");
959 pBody
->Arrange(rDev
, rFormat
);
963 GetHeightVerOffset(*pBody
, nHeight
, nVerOffset
);
964 nHeight
+= rFormat
.GetDistance(DIS_ROOT
)
965 * GetFont().GetSize().Height() / 100L;
967 // font specialist advised to change the width first
968 pRootSym
->AdaptToY(rDev
, nHeight
);
969 pRootSym
->AdaptToX(rDev
, pBody
->GetItalicWidth());
971 pRootSym
->Arrange(rDev
, rFormat
);
973 Point aPos
= pRootSym
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, RVA_BASELINE
);
974 //! overrride calulated vertical position
975 aPos
.Y() = pRootSym
->GetTop() + pBody
->GetBottom() - pRootSym
->GetBottom();
976 aPos
.Y() -= nVerOffset
;
977 pRootSym
->MoveTo(aPos
);
980 { pExtra
->SetSize(Fraction(rFormat
.GetRelSize(SIZ_INDEX
), 100));
981 pExtra
->Arrange(rDev
, rFormat
);
983 aPos
= GetExtraPos(*pRootSym
, *pExtra
);
984 pExtra
->MoveTo(aPos
);
987 SmRect::operator = (*pBody
);
988 ExtendBy(*pRootSym
, RCP_THIS
);
990 ExtendBy(*pExtra
, RCP_THIS
, (BOOL
) TRUE
);
994 void SmRootNode::CreateTextFromNode(String
&rText
)
996 SmNode
*pExtra
= GetSubNode(0);
999 APPEND(rText
,"nroot ");
1000 pExtra
->CreateTextFromNode(rText
);
1003 APPEND(rText
,"sqrt ");
1004 GetSubNode(2)->CreateTextFromNode(rText
);
1008 /**************************************************************************/
1011 void SmBinHorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1013 SmNode
*pLeft
= GetSubNode(0),
1014 *pOper
= GetSubNode(1),
1015 *pRight
= GetSubNode(2);
1016 DBG_ASSERT(pLeft
!= NULL
, "Sm: NULL pointer");
1017 DBG_ASSERT(pOper
!= NULL
, "Sm: NULL pointer");
1018 DBG_ASSERT(pRight
!= NULL
, "Sm: NULL pointer");
1020 pOper
->SetSize(Fraction (rFormat
.GetRelSize(SIZ_OPERATOR
), 100));
1022 pLeft
->Arrange(rDev
, rFormat
);
1023 pOper
->Arrange(rDev
, rFormat
);
1024 pRight
->Arrange(rDev
, rFormat
);
1026 const SmRect
&rOpRect
= pOper
->GetRect();
1028 long nDist
= (rOpRect
.GetWidth() *
1029 rFormat
.GetDistance(DIS_HORIZONTAL
)) / 100L;
1031 SmRect::operator = (*pLeft
);
1034 aPos
= pOper
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1036 pOper
->MoveTo(aPos
);
1037 ExtendBy(*pOper
, RCP_XOR
);
1039 aPos
= pRight
->AlignTo(*this, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1042 pRight
->MoveTo(aPos
);
1043 ExtendBy(*pRight
, RCP_XOR
);
1047 /**************************************************************************/
1050 void SmBinVerNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1052 SmNode
*pNum
= GetSubNode(0),
1053 *pLine
= GetSubNode(1),
1054 *pDenom
= GetSubNode(2);
1055 DBG_ASSERT(pNum
, "Sm : NULL pointer");
1056 DBG_ASSERT(pLine
, "Sm : NULL pointer");
1057 DBG_ASSERT(pDenom
, "Sm : NULL pointer");
1059 BOOL bIsTextmode
= rFormat
.IsTextmode();
1062 Fraction
aFraction(rFormat
.GetRelSize(SIZ_INDEX
), 100);
1063 pNum
->SetSize(aFraction
);
1064 pLine
->SetSize(aFraction
);
1065 pDenom
->SetSize(aFraction
);
1068 pNum
->Arrange(rDev
, rFormat
);
1069 pDenom
->Arrange(rDev
, rFormat
);
1071 long nFontHeight
= GetFont().GetSize().Height(),
1072 nExtLen
= nFontHeight
* rFormat
.GetDistance(DIS_FRACTION
) / 100L,
1073 nThick
= nFontHeight
* rFormat
.GetDistance(DIS_STROKEWIDTH
) / 100L,
1074 nWidth
= Max(pNum
->GetItalicWidth(), pDenom
->GetItalicWidth()),
1075 nNumDist
= bIsTextmode
? 0 :
1076 nFontHeight
* rFormat
.GetDistance(DIS_NUMERATOR
) / 100L,
1077 nDenomDist
= bIsTextmode
? 0 :
1078 nFontHeight
* rFormat
.GetDistance(DIS_DENOMINATOR
) / 100L;
1080 // font specialist advised to change the width first
1081 pLine
->AdaptToY(rDev
, nThick
);
1082 pLine
->AdaptToX(rDev
, nWidth
+ 2 * nExtLen
);
1083 pLine
->Arrange(rDev
, rFormat
);
1085 // get horizontal alignment for numerator
1086 const SmNode
*pLM
= pNum
->GetLeftMost();
1087 RectHorAlign eHorAlign
= pLM
->GetRectHorAlign();
1089 // move numerator to its position
1090 Point aPos
= pNum
->AlignTo(*pLine
, RP_TOP
, eHorAlign
, RVA_BASELINE
);
1091 aPos
.Y() -= nNumDist
;
1094 // get horizontal alignment for denominator
1095 pLM
= pDenom
->GetLeftMost();
1096 eHorAlign
= pLM
->GetRectHorAlign();
1098 // move denominator to its position
1099 aPos
= pDenom
->AlignTo(*pLine
, RP_BOTTOM
, eHorAlign
, RVA_BASELINE
);
1100 aPos
.Y() += nDenomDist
;
1101 pDenom
->MoveTo(aPos
);
1103 SmRect::operator = (*pNum
);
1104 ExtendBy(*pDenom
, RCP_NONE
).ExtendBy(*pLine
, RCP_NONE
, pLine
->GetCenterY());
1107 void SmBinVerNode::CreateTextFromNode(String
&rText
)
1109 SmNode
*pNum
= GetSubNode(0),
1110 // *pLine = GetSubNode(1),
1111 *pDenom
= GetSubNode(2);
1112 pNum
->CreateTextFromNode(rText
);
1113 APPEND(rText
,"over ");
1114 pDenom
->CreateTextFromNode(rText
);
1118 SmNode
* SmBinVerNode::GetLeftMost()
1124 /**************************************************************************/
1127 double Det(const Point
&rHeading1
, const Point
&rHeading2
)
1128 // gibt den Wert der durch die beiden Punkte gebildeten Determinante
1131 return rHeading1
.X() * rHeading2
.Y() - rHeading1
.Y() * rHeading2
.X();
1135 BOOL
IsPointInLine(const Point
&rPoint1
,
1136 const Point
&rPoint2
, const Point
&rHeading2
)
1137 // ergibt TRUE genau dann, wenn der Punkt 'rPoint1' zu der Gerade gehoert die
1138 // durch den Punkt 'rPoint2' geht und den Richtungsvektor 'rHeading2' hat
1140 DBG_ASSERT(rHeading2
!= Point(), "Sm : 0 vector");
1143 const double eps
= 5.0 * DBL_EPSILON
;
1146 if (labs(rHeading2
.X()) > labs(rHeading2
.Y()))
1148 fLambda
= (rPoint1
.X() - rPoint2
.X()) / (double) rHeading2
.X();
1149 bRes
= fabs(rPoint1
.Y() - (rPoint2
.Y() + fLambda
* rHeading2
.Y())) < eps
;
1153 fLambda
= (rPoint1
.Y() - rPoint2
.Y()) / (double) rHeading2
.Y();
1154 bRes
= fabs(rPoint1
.X() - (rPoint2
.X() + fLambda
* rHeading2
.X())) < eps
;
1161 USHORT
GetLineIntersectionPoint(Point
&rResult
,
1162 const Point
& rPoint1
, const Point
&rHeading1
,
1163 const Point
& rPoint2
, const Point
&rHeading2
)
1165 DBG_ASSERT(rHeading1
!= Point(), "Sm : 0 vector");
1166 DBG_ASSERT(rHeading2
!= Point(), "Sm : 0 vector");
1169 const double eps
= 5.0 * DBL_EPSILON
;
1171 // sind die Richtumgsvektoren linear abhaengig ?
1172 double fDet
= Det(rHeading1
, rHeading2
);
1173 if (fabs(fDet
) < eps
)
1175 nRes
= IsPointInLine(rPoint1
, rPoint2
, rHeading2
) ? USHRT_MAX
: 0;
1176 rResult
= nRes
? rPoint1
: Point();
1180 // hier achten wir nicht auf Rechengenauigkeit
1181 // (das wuerde aufwendiger und lohnt sich hier kaum)
1182 double fLambda
= ( (rPoint1
.Y() - rPoint2
.Y()) * rHeading2
.X()
1183 - (rPoint1
.X() - rPoint2
.X()) * rHeading2
.Y())
1185 rResult
= Point(rPoint1
.X() + (long) (fLambda
* rHeading1
.X()),
1186 rPoint1
.Y() + (long) (fLambda
* rHeading1
.Y()));
1194 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken
&rNodeToken
)
1195 : SmStructureNode(NBINDIAGONAL
, rNodeToken
)
1202 void SmBinDiagonalNode::GetOperPosSize(Point
&rPos
, Size
&rSize
,
1203 const Point
&rDiagPoint
, double fAngleDeg
) const
1204 // gibt die Position und Groesse fuer den Diagonalstrich zurueck.
1205 // Vor.: das SmRect des Nodes gibt die Begrenzung vor(!), muss also selbst
1206 // bereits bekannt sein.
1209 const double fPi
= 3.1415926535897932384626433;
1210 double fAngleRad
= fAngleDeg
/ 180.0 * fPi
;
1211 long nRectLeft
= GetItalicLeft(),
1212 nRectRight
= GetItalicRight(),
1213 nRectTop
= GetTop(),
1214 nRectBottom
= GetBottom();
1215 Point
aRightHdg (100, 0),
1217 aDiagHdg ( (long)(100.0 * cos(fAngleRad
)),
1218 (long)(-100.0 * sin(fAngleRad
)) );
1220 long nLeft
, nRight
, nTop
, nBottom
; // Raender des Rechtecks fuer die
1226 // obere rechte Ecke bestimmen
1228 GetLineIntersectionPoint(aPoint
,
1229 Point(nRectLeft
, nRectTop
), aRightHdg
,
1230 rDiagPoint
, aDiagHdg
);
1232 // gibt es einen Schnittpunkt mit dem oberen Rand ?
1233 if (aPoint
.X() <= nRectRight
)
1235 nRight
= aPoint
.X();
1240 // es muss einen Schnittpunkt mit dem rechten Rand geben!
1241 GetLineIntersectionPoint(aPoint
,
1242 Point(nRectRight
, nRectTop
), aDownHdg
,
1243 rDiagPoint
, aDiagHdg
);
1245 nRight
= nRectRight
;
1250 // untere linke Ecke bestimmen
1252 GetLineIntersectionPoint(aPoint
,
1253 Point(nRectLeft
, nRectBottom
), aRightHdg
,
1254 rDiagPoint
, aDiagHdg
);
1256 // gibt es einen Schnittpunkt mit dem unteren Rand ?
1257 if (aPoint
.X() >= nRectLeft
)
1260 nBottom
= nRectBottom
;
1264 // es muss einen Schnittpunkt mit dem linken Rand geben!
1265 GetLineIntersectionPoint(aPoint
,
1266 Point(nRectLeft
, nRectTop
), aDownHdg
,
1267 rDiagPoint
, aDiagHdg
);
1270 nBottom
= aPoint
.Y();
1276 // obere linke Ecke bestimmen
1278 GetLineIntersectionPoint(aPoint
,
1279 Point(nRectLeft
, nRectTop
), aRightHdg
,
1280 rDiagPoint
, aDiagHdg
);
1282 // gibt es einen Schnittpunkt mit dem oberen Rand ?
1283 if (aPoint
.X() >= nRectLeft
)
1290 // es muss einen Schnittpunkt mit dem linken Rand geben!
1291 GetLineIntersectionPoint(aPoint
,
1292 Point(nRectLeft
, nRectTop
), aDownHdg
,
1293 rDiagPoint
, aDiagHdg
);
1300 // untere rechte Ecke bestimmen
1302 GetLineIntersectionPoint(aPoint
,
1303 Point(nRectLeft
, nRectBottom
), aRightHdg
,
1304 rDiagPoint
, aDiagHdg
);
1306 // gibt es einen Schnittpunkt mit dem unteren Rand ?
1307 if (aPoint
.X() <= nRectRight
)
1309 nRight
= aPoint
.X();
1310 nBottom
= nRectBottom
;
1314 // es muss einen Schnittpunkt mit dem rechten Rand geben!
1315 GetLineIntersectionPoint(aPoint
,
1316 Point(nRectRight
, nRectTop
), aDownHdg
,
1317 rDiagPoint
, aDiagHdg
);
1319 nRight
= nRectRight
;
1320 nBottom
= aPoint
.Y();
1324 rSize
= Size(nRight
- nLeft
+ 1, nBottom
- nTop
+ 1);
1330 void SmBinDiagonalNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1332 //! die beiden Argumente muessen in den Subnodes vor dem Operator kommen,
1333 //! damit das anklicken im GraphicWindow den FormulaCursor richtig setzt
1334 //! (vgl SmRootNode)
1335 SmNode
*pLeft
= GetSubNode(0),
1336 *pRight
= GetSubNode(1);
1337 DBG_ASSERT(pLeft
, "Sm : NULL pointer");
1338 DBG_ASSERT(pRight
, "Sm : NULL pointer");
1340 DBG_ASSERT(GetSubNode(2)->GetType() == NPOLYLINE
, "Sm : falscher Nodetyp");
1341 SmPolyLineNode
*pOper
= (SmPolyLineNode
*) GetSubNode(2);
1342 DBG_ASSERT(pOper
, "Sm : NULL pointer");
1344 //! some routines being called extract some info from the OutputDevice's
1345 //! font (eg the space to be used for borders OR the font name(!!)).
1346 //! Thus the font should reflect the needs and has to be set!
1347 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
1348 aTmpDev
.SetFont(GetFont());
1350 pLeft
->Arrange(aTmpDev
, rFormat
);
1351 pRight
->Arrange(aTmpDev
, rFormat
);
1353 // implizit die Weite (incl Rand) des Diagonalstrichs ermitteln
1354 pOper
->Arrange(aTmpDev
, rFormat
);
1356 long nDelta
= pOper
->GetWidth() * 8 / 10;
1358 // TopLeft Position vom rechten Argument ermitteln
1360 aPos
.X() = pLeft
->GetItalicRight() + nDelta
+ pRight
->GetItalicLeftSpace();
1362 aPos
.Y() = pLeft
->GetBottom() + nDelta
;
1364 aPos
.Y() = pLeft
->GetTop() - nDelta
- pRight
->GetHeight();
1366 pRight
->MoveTo(aPos
);
1368 // neue Baseline bestimmen
1369 long nTmpBaseline
= IsAscending() ? (pLeft
->GetBottom() + pRight
->GetTop()) / 2
1370 : (pLeft
->GetTop() + pRight
->GetBottom()) / 2;
1371 Point
aLogCenter ((pLeft
->GetItalicRight() + pRight
->GetItalicLeft()) / 2,
1374 SmRect::operator = (*pLeft
);
1375 ExtendBy(*pRight
, RCP_NONE
);
1378 // Position und Groesse des Diagonalstrich ermitteln
1380 GetOperPosSize(aPos
, aTmpSize
, aLogCenter
, IsAscending() ? 60.0 : -60.0);
1382 // font specialist advised to change the width first
1383 pOper
->AdaptToY(aTmpDev
, aTmpSize
.Height());
1384 pOper
->AdaptToX(aTmpDev
, aTmpSize
.Width());
1385 // und diese wirksam machen
1386 pOper
->Arrange(aTmpDev
, rFormat
);
1388 pOper
->MoveTo(aPos
);
1390 ExtendBy(*pOper
, RCP_NONE
, nTmpBaseline
);
1394 /**************************************************************************/
1397 void SmSubSupNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1399 DBG_ASSERT(GetNumSubNodes() == 1 + SUBSUP_NUM_ENTRIES
,
1400 "Sm: falsche Anzahl von subnodes");
1402 SmNode
*pBody
= GetBody();
1403 DBG_ASSERT(pBody
, "Sm: NULL pointer");
1405 long nOrigHeight
= pBody
->GetFont().GetSize().Height();
1407 pBody
->Arrange(rDev
, rFormat
);
1409 const SmRect
&rBodyRect
= pBody
->GetRect();
1410 SmRect::operator = (rBodyRect
);
1412 // line that separates sub- and supscript rectangles
1413 long nDelimLine
= SmFromTo(GetAlignB(), GetAlignT(), 0.4);
1418 // iterate over all possible sub-/supscripts
1419 SmRect
aTmpRect (rBodyRect
);
1420 for (int i
= 0; i
< SUBSUP_NUM_ENTRIES
; i
++)
1421 { SmSubSup eSubSup
= (SmSubSup
) i
; // cast
1422 SmNode
*pSubSup
= GetSubSup(eSubSup
);
1427 // switch position of limits if we are in textmode
1428 if (rFormat
.IsTextmode() && (GetToken().nGroup
& TGLIMIT
))
1430 { case CSUB
: eSubSup
= RSUB
; break;
1431 case CSUP
: eSubSup
= RSUP
; break;
1436 // prevent sub-/supscripts from diminishing in size
1437 // (as would be in "a_{1_{2_{3_4}}}")
1438 if (GetFont().GetSize().Height() > rFormat
.GetBaseSize().Height() / 3)
1440 USHORT nIndex
= (eSubSup
== CSUB
|| eSubSup
== CSUP
) ?
1441 SIZ_LIMITS
: SIZ_INDEX
;
1442 Fraction
aFraction ( rFormat
.GetRelSize(nIndex
), 100 );
1443 pSubSup
->SetSize(aFraction
);
1446 pSubSup
->Arrange(rDev
, rFormat
);
1448 BOOL bIsTextmode
= rFormat
.IsTextmode();
1451 //! be sure that CSUB, CSUP are handled before the other cases!
1457 * rFormat
.GetDistance(DIS_SUBSCRIPT
) / 100L;
1458 aPos
= pSubSup
->GetRect().AlignTo(aTmpRect
,
1459 eSubSup
== LSUB
? RP_LEFT
: RP_RIGHT
,
1460 RHA_CENTER
, RVA_BOTTOM
);
1462 nDelta
= nDelimLine
- aPos
.Y();
1470 * rFormat
.GetDistance(DIS_SUPERSCRIPT
) / 100L;
1471 aPos
= pSubSup
->GetRect().AlignTo(aTmpRect
,
1472 eSubSup
== LSUP
? RP_LEFT
: RP_RIGHT
,
1473 RHA_CENTER
, RVA_TOP
);
1475 nDelta
= aPos
.Y() + pSubSup
->GetHeight() - nDelimLine
;
1482 * rFormat
.GetDistance(DIS_LOWERLIMIT
) / 100L;
1483 aPos
= pSubSup
->GetRect().AlignTo(rBodyRect
, RP_BOTTOM
,
1484 RHA_CENTER
, RVA_BASELINE
);
1490 * rFormat
.GetDistance(DIS_UPPERLIMIT
) / 100L;
1491 aPos
= pSubSup
->GetRect().AlignTo(rBodyRect
, RP_TOP
,
1492 RHA_CENTER
, RVA_BASELINE
);
1496 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
1500 pSubSup
->MoveTo(aPos
);
1501 ExtendBy(*pSubSup
, RCP_THIS
, (BOOL
) TRUE
);
1503 // update rectangle to which RSUB, RSUP, LSUB, LSUP
1504 // will be aligned to
1505 if (eSubSup
== CSUB
|| eSubSup
== CSUP
)
1510 void SmSubSupNode::CreateTextFromNode(String
&rText
)
1513 GetSubNode(0)->CreateTextFromNode(rText
);
1515 if (NULL
!= (pNode
= GetSubNode(LSUB
+1)))
1517 APPEND(rText
,"lsub ");
1518 pNode
->CreateTextFromNode(rText
);
1520 if (NULL
!= (pNode
= GetSubNode(LSUP
+1)))
1522 APPEND(rText
,"lsup ");
1523 pNode
->CreateTextFromNode(rText
);
1525 if (NULL
!= (pNode
= GetSubNode(CSUB
+1)))
1527 APPEND(rText
,"csub ");
1528 pNode
->CreateTextFromNode(rText
);
1530 if (NULL
!= (pNode
= GetSubNode(CSUP
+1)))
1532 APPEND(rText
,"csup ");
1533 pNode
->CreateTextFromNode(rText
);
1535 if (NULL
!= (pNode
= GetSubNode(RSUB
+1)))
1537 rText
.EraseTrailingChars();
1539 pNode
->CreateTextFromNode(rText
);
1541 if (NULL
!= (pNode
= GetSubNode(RSUP
+1)))
1543 rText
.EraseTrailingChars();
1545 pNode
->CreateTextFromNode(rText
);
1550 /**************************************************************************/
1552 void SmBraceNode::CreateTextFromNode(String
&rText
)
1554 if (GetScaleMode() == SCALE_HEIGHT
)
1555 APPEND(rText
,"left ");
1558 GetSubNode(0)->CreateTextFromNode(aStr
);
1559 aStr
.EraseLeadingAndTrailingChars();
1560 aStr
.EraseLeadingChars('\\');
1563 if (aStr
.EqualsAscii("divides"))
1564 APPEND(rText
,"lline");
1565 else if (aStr
.EqualsAscii("parallel"))
1566 APPEND(rText
,"ldline");
1567 else if (aStr
.EqualsAscii("<"))
1568 APPEND(rText
,"langle");
1574 APPEND(rText
,"none ");
1576 GetSubNode(1)->CreateTextFromNode(rText
);
1577 if (GetScaleMode() == SCALE_HEIGHT
)
1578 APPEND(rText
,"right ");
1581 GetSubNode(2)->CreateTextFromNode(aStr
);
1582 aStr
.EraseLeadingAndTrailingChars();
1583 aStr
.EraseLeadingChars('\\');
1586 if (aStr
.EqualsAscii("divides"))
1587 APPEND(rText
,"rline");
1588 else if (aStr
.EqualsAscii("parallel"))
1589 APPEND(rText
,"rdline");
1590 else if (aStr
.EqualsAscii(">"))
1591 APPEND(rText
,"rangle");
1597 APPEND(rText
,"none ");
1603 void SmBraceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1605 SmNode
*pLeft
= GetSubNode(0),
1606 *pBody
= GetSubNode(1),
1607 *pRight
= GetSubNode(2);
1608 DBG_ASSERT(pLeft
, "Sm: NULL pointer");
1609 DBG_ASSERT(pBody
, "Sm: NULL pointer");
1610 DBG_ASSERT(pRight
, "Sm: NULL pointer");
1612 pBody
->Arrange(rDev
, rFormat
);
1614 BOOL bIsScaleNormal
= rFormat
.IsScaleNormalBrackets(),
1615 bScale
= pBody
->GetHeight() > 0 &&
1616 (GetScaleMode() == SCALE_HEIGHT
|| bIsScaleNormal
),
1617 bIsABS
= GetToken().eType
== TABS
;
1619 long nFaceHeight
= GetFont().GetSize().Height();
1621 // Uebergroesse in % ermitteln
1623 if (!bIsABS
&& bScale
)
1624 { // im Fall von Klammern mit Uebergroesse...
1625 USHORT nIndex
= GetScaleMode() == SCALE_HEIGHT
?
1626 DIS_BRACKETSIZE
: DIS_NORMALBRACKETSIZE
;
1627 nPerc
= rFormat
.GetDistance(nIndex
);
1630 // ermitteln der Hoehe fuer die Klammern
1634 nBraceHeight
= pBody
->GetType() == NBRACEBODY
?
1635 ((SmBracebodyNode
*) pBody
)->GetBodyHeight()
1636 : pBody
->GetHeight();
1637 nBraceHeight
+= 2 * (nBraceHeight
* nPerc
/ 100L);
1640 nBraceHeight
= nFaceHeight
;
1642 // Abstand zum Argument
1643 nPerc
= bIsABS
? 0 : rFormat
.GetDistance(DIS_BRACKETSPACE
);
1644 long nDist
= nFaceHeight
* nPerc
/ 100L;
1646 // sofern erwuenscht skalieren der Klammern auf die gewuenschte Groesse
1649 Size
aTmpSize (pLeft
->GetFont().GetSize());
1650 DBG_ASSERT(pRight
->GetFont().GetSize() == aTmpSize
,
1651 "Sm : unterschiedliche Fontgroessen");
1652 aTmpSize
.Width() = Min((long) nBraceHeight
* 60L / 100L,
1653 rFormat
.GetBaseSize().Height() * 3L / 2L);
1654 // correction factor since change from StarMath to StarSymbol font
1655 // because of the different font width in the FontMetric
1656 aTmpSize
.Width() *= 182;
1657 aTmpSize
.Width() /= 267;
1659 xub_Unicode cChar
= pLeft
->GetToken().cMathChar
;
1660 if (cChar
!= MS_LINE
&& cChar
!= MS_DLINE
)
1661 pLeft
->GetFont().SetSize(aTmpSize
);
1663 cChar
= pRight
->GetToken().cMathChar
;
1664 if (cChar
!= MS_LINE
&& cChar
!= MS_DLINE
)
1665 pRight
->GetFont().SetSize(aTmpSize
);
1667 pLeft
->AdaptToY(rDev
, nBraceHeight
);
1668 pRight
->AdaptToY(rDev
, nBraceHeight
);
1671 pLeft
->Arrange(rDev
, rFormat
);
1672 pRight
->Arrange(rDev
, rFormat
);
1674 // damit auch "\(a\) - (a) - left ( a right )" vernuenftig aussieht
1675 RectVerAlign eVerAlign
= bScale
? RVA_CENTERY
: RVA_BASELINE
;
1678 aPos
= pLeft
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, eVerAlign
);
1680 pLeft
->MoveTo(aPos
);
1682 aPos
= pRight
->AlignTo(*pBody
, RP_RIGHT
, RHA_CENTER
, eVerAlign
);
1684 pRight
->MoveTo(aPos
);
1686 SmRect::operator = (*pBody
);
1687 ExtendBy(*pLeft
, RCP_THIS
).ExtendBy(*pRight
, RCP_THIS
);
1691 /**************************************************************************/
1694 void SmBracebodyNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1696 USHORT nNumSubNodes
= GetNumSubNodes();
1697 if (nNumSubNodes
== 0)
1700 // arrange arguments
1702 for (i
= 0; i
< nNumSubNodes
; i
+= 2)
1703 GetSubNode(i
)->Arrange(rDev
, rFormat
);
1705 // build reference rectangle with necessary info for vertical alignment
1706 SmRect
aRefRect (*GetSubNode(0));
1707 for (i
= 0; i
< nNumSubNodes
; i
+= 2)
1709 SmRect
aTmpRect (*GetSubNode(i
));
1710 Point aPos
= aTmpRect
.AlignTo(aRefRect
, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
1711 aTmpRect
.MoveTo(aPos
);
1712 aRefRect
.ExtendBy(aTmpRect
, RCP_XOR
);
1715 nBodyHeight
= aRefRect
.GetHeight();
1717 // scale separators to required height and arrange them
1718 BOOL bScale
= GetScaleMode() == SCALE_HEIGHT
|| rFormat
.IsScaleNormalBrackets();
1719 long nHeight
= bScale
? aRefRect
.GetHeight() : GetFont().GetSize().Height();
1720 USHORT nIndex
= GetScaleMode() == SCALE_HEIGHT
?
1721 DIS_BRACKETSIZE
: DIS_NORMALBRACKETSIZE
;
1722 USHORT nPerc
= rFormat
.GetDistance(nIndex
);
1724 nHeight
+= 2 * (nHeight
* nPerc
/ 100L);
1725 for (i
= 1; i
< nNumSubNodes
; i
+= 2)
1727 SmNode
*pNode
= GetSubNode(i
);
1728 pNode
->AdaptToY(rDev
, nHeight
);
1729 pNode
->Arrange(rDev
, rFormat
);
1732 // horizontal distance between argument and brackets or separators
1733 long nDist
= GetFont().GetSize().Height()
1734 * rFormat
.GetDistance(DIS_BRACKETSPACE
) / 100L;
1736 SmNode
*pLeft
= GetSubNode(0);
1737 SmRect::operator = (*pLeft
);
1738 for (i
= 1; i
< nNumSubNodes
; i
++)
1740 BOOL bIsSeparator
= i
% 2 != 0;
1741 RectVerAlign eVerAlign
= bIsSeparator
? RVA_CENTERY
: RVA_BASELINE
;
1743 SmNode
*pRight
= GetSubNode(i
);
1744 Point aPosX
= pRight
->AlignTo(*pLeft
, RP_RIGHT
, RHA_CENTER
, eVerAlign
),
1745 aPosY
= pRight
->AlignTo(aRefRect
, RP_RIGHT
, RHA_CENTER
, eVerAlign
);
1748 pRight
->MoveTo(Point(aPosX
.X(), aPosY
.Y()));
1749 ExtendBy(*pRight
, bIsSeparator
? RCP_THIS
: RCP_XOR
);
1756 /**************************************************************************/
1759 void SmVerticalBraceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1761 SmNode
*pBody
= GetSubNode(0),
1762 *pBrace
= GetSubNode(1),
1763 *pScript
= GetSubNode(2);
1764 DBG_ASSERT(pBody
, "Sm: NULL pointer!");
1765 DBG_ASSERT(pBrace
, "Sm: NULL pointer!");
1766 DBG_ASSERT(pScript
, "Sm: NULL pointer!");
1768 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
1769 aTmpDev
.SetFont(GetFont());
1771 pBody
->Arrange(aTmpDev
, rFormat
);
1773 // Groesse wie bei Grenzen fuer diesen Teil
1774 pScript
->SetSize( Fraction( rFormat
.GetRelSize(SIZ_LIMITS
), 100 ) );
1775 // etwas hoehere Klammern als normal
1776 pBrace
->SetSize( Fraction(3, 2) );
1778 long nItalicWidth
= pBody
->GetItalicWidth();
1779 if (nItalicWidth
> 0)
1780 pBrace
->AdaptToX(aTmpDev
, nItalicWidth
);
1782 pBrace
->Arrange(aTmpDev
, rFormat
);
1783 pScript
->Arrange(aTmpDev
, rFormat
);
1785 // die relativen Position und die Abstaende zueinander bestimmen
1787 long nFontHeight
= pBody
->GetFont().GetSize().Height();
1788 long nDistBody
= nFontHeight
* rFormat
.GetDistance(DIS_ORNAMENTSIZE
),
1789 nDistScript
= nFontHeight
;
1790 if (GetToken().eType
== TOVERBRACE
)
1793 nDistBody
= - nDistBody
;
1794 nDistScript
*= - rFormat
.GetDistance(DIS_UPPERLIMIT
);
1798 eRectPos
= RP_BOTTOM
;
1799 nDistScript
*= + rFormat
.GetDistance(DIS_LOWERLIMIT
);
1802 nDistScript
/= 100L;
1804 Point aPos
= pBrace
->AlignTo(*pBody
, eRectPos
, RHA_CENTER
, RVA_BASELINE
);
1805 aPos
.Y() += nDistBody
;
1806 pBrace
->MoveTo(aPos
);
1808 aPos
= pScript
->AlignTo(*pBrace
, eRectPos
, RHA_CENTER
, RVA_BASELINE
);
1809 aPos
.Y() += nDistScript
;
1810 pScript
->MoveTo(aPos
);
1812 SmRect::operator = (*pBody
);
1813 ExtendBy(*pBrace
, RCP_THIS
).ExtendBy(*pScript
, RCP_THIS
);
1817 /**************************************************************************/
1820 SmNode
* SmOperNode::GetSymbol()
1822 SmNode
*pNode
= GetSubNode(0);
1823 DBG_ASSERT(pNode
, "Sm: NULL pointer!");
1825 if (pNode
->GetType() == NSUBSUP
)
1826 pNode
= ((SmSubSupNode
*) pNode
)->GetBody();
1828 DBG_ASSERT(pNode
, "Sm: NULL pointer!");
1833 long SmOperNode::CalcSymbolHeight(const SmNode
&rSymbol
,
1834 const SmFormat
&rFormat
) const
1835 // returns the font height to be used for operator-symbol
1837 long nHeight
= GetFont().GetSize().Height();
1839 SmTokenType eTmpType
= GetToken().eType
;
1840 if (eTmpType
== TLIM
|| eTmpType
== TLIMINF
|| eTmpType
== TLIMSUP
)
1843 if (!rFormat
.IsTextmode())
1845 // set minimum size ()
1846 nHeight
+= (nHeight
* 20L) / 100L;
1849 * rFormat
.GetDistance(DIS_OPERATORSIZE
) / 100L;
1850 nHeight
= nHeight
* 686L / 845L;
1853 // correct user-defined symbols to match height of sum from used font
1854 if (rSymbol
.GetToken().eType
== TSPECIAL
)
1855 nHeight
= nHeight
* 845L / 686L;
1861 void SmOperNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1863 SmNode
*pOper
= GetSubNode(0);
1864 SmNode
*pBody
= GetSubNode(1);
1866 DBG_ASSERT(pOper
, "Sm: Subnode fehlt");
1867 DBG_ASSERT(pBody
, "Sm: Subnode fehlt");
1869 SmNode
*pSymbol
= GetSymbol();
1870 pSymbol
->SetSize(Fraction(CalcSymbolHeight(*pSymbol
, rFormat
),
1871 pSymbol
->GetFont().GetSize().Height()));
1873 pBody
->Arrange(rDev
, rFormat
);
1874 pOper
->Arrange(rDev
, rFormat
);
1876 long nOrigHeight
= GetFont().GetSize().Height(),
1878 * rFormat
.GetDistance(DIS_OPERATORSPACE
) / 100L;
1880 Point aPos
= pOper
->AlignTo(*pBody
, RP_LEFT
, RHA_CENTER
, /*RVA_CENTERY*/RVA_MID
);
1882 pOper
->MoveTo(aPos
);
1884 SmRect::operator = (*pBody
);
1885 ExtendBy(*pOper
, RCP_THIS
);
1889 /**************************************************************************/
1892 void SmAlignNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1893 // setzt im ganzen subtree (incl aktuellem node) das alignment
1895 DBG_ASSERT(GetNumSubNodes() > 0, "Sm: SubNode fehlt");
1897 SmNode
*pNode
= GetSubNode(0);
1899 RectHorAlign eHorAlign
= RHA_CENTER
;
1900 switch (GetToken().eType
)
1902 case TALIGNL
: eHorAlign
= RHA_LEFT
; break;
1903 case TALIGNC
: eHorAlign
= RHA_CENTER
; break;
1904 case TALIGNR
: eHorAlign
= RHA_RIGHT
; break;
1908 SetRectHorAlign(eHorAlign
);
1910 pNode
->Arrange(rDev
, rFormat
);
1912 SmRect::operator = (pNode
->GetRect());
1916 /**************************************************************************/
1919 void SmAttributNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
1921 SmNode
*pAttr
= GetSubNode(0),
1922 *pBody
= GetSubNode(1);
1923 DBG_ASSERT(pBody
, "Sm: Body fehlt");
1924 DBG_ASSERT(pAttr
, "Sm: Attribut fehlt");
1926 pBody
->Arrange(rDev
, rFormat
);
1928 if (GetScaleMode() == SCALE_WIDTH
)
1929 pAttr
->AdaptToX(rDev
, pBody
->GetItalicWidth());
1930 pAttr
->Arrange(rDev
, rFormat
);
1932 // get relative position of attribut
1933 RectVerAlign eVerAlign
;
1935 switch (GetToken().eType
)
1937 eVerAlign
= RVA_ATTRIBUT_LO
;
1940 eVerAlign
= RVA_ATTRIBUT_MID
;
1943 eVerAlign
= RVA_ATTRIBUT_HI
;
1944 if (pBody
->GetType() == NATTRIBUT
)
1945 nDist
= GetFont().GetSize().Height()
1946 * rFormat
.GetDistance(DIS_ORNAMENTSPACE
) / 100L;
1948 Point aPos
= pAttr
->AlignTo(*pBody
, RP_ATTRIBUT
, RHA_CENTER
, eVerAlign
);
1950 pAttr
->MoveTo(aPos
);
1952 SmRect::operator = (*pBody
);
1953 ExtendBy(*pAttr
, RCP_THIS
, (BOOL
) TRUE
);
1957 /**************************************************************************/
1962 void SmFontNode::CreateTextFromNode(String
&rText
)
1964 switch (GetToken().eType
)
1967 APPEND(rText
,"bold ");
1970 APPEND(rText
,"nbold ");
1973 APPEND(rText
,"italic ");
1976 APPEND(rText
,"nitalic ");
1979 APPEND(rText
,"phantom ");
1983 APPEND(rText
,"size ");
1992 case FNTSIZ_MULTIPLY
:
1998 case FNTSIZ_ABSOLUT
:
2002 rText
+= String( ::rtl::math::doubleToUString(
2003 static_cast<double>(aFontSize
),
2004 rtl_math_StringFormat_Automatic
,
2005 rtl_math_DecimalPlaces_Max
, '.', sal_True
));
2010 APPEND(rText
,"color black ");
2013 APPEND(rText
,"color white ");
2016 APPEND(rText
,"color red ");
2019 APPEND(rText
,"color green ");
2022 APPEND(rText
,"color blue ");
2025 APPEND(rText
,"color cyan ");
2028 APPEND(rText
,"color magenta ");
2031 APPEND(rText
,"color yellow ");
2034 APPEND(rText
,"font sans ");
2037 APPEND(rText
,"font serif ");
2040 APPEND(rText
,"font fixed ");
2045 GetSubNode(1)->CreateTextFromNode(rText
);
2049 void SmFontNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2051 //! prepare subnodes first
2052 SmNode::Prepare(rFormat
, rDocShell
);
2055 switch (GetToken().eType
)
2057 case TFIXED
: nFnt
= FNT_FIXED
; break;
2058 case TSANS
: nFnt
= FNT_SANS
; break;
2059 case TSERIF
: nFnt
= FNT_SERIF
; break;
2064 { GetFont() = rFormat
.GetFont( sal::static_int_cast
< USHORT
>(nFnt
) );
2068 //! prevent overwrites of this font by 'Arrange' or 'SetFont' calls of
2069 //! other font nodes (those with lower depth in the tree)
2070 Flags() |= FLG_FONT
;
2074 void SmFontNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2076 SmNode
*pNode
= GetSubNode(1);
2077 DBG_ASSERT(pNode
, "Sm: SubNode fehlt");
2079 switch (GetToken().eType
)
2081 pNode
->SetFontSize(aFontSize
, nSizeType
);
2086 pNode
->SetFont(GetFont());
2088 case TUNKNOWN
: break; // no assertion on "font <?> <?>"
2090 case TPHANTOM
: SetPhantom(TRUE
); break;
2091 case TBOLD
: SetAttribut(ATTR_BOLD
); break;
2092 case TITALIC
: SetAttribut(ATTR_ITALIC
); break;
2093 case TNBOLD
: ClearAttribut(ATTR_BOLD
); break;
2094 case TNITALIC
: ClearAttribut(ATTR_ITALIC
); break;
2096 case TBLACK
: SetColor(Color(COL_BLACK
)); break;
2097 case TWHITE
: SetColor(Color(COL_WHITE
)); break;
2098 case TRED
: SetColor(Color(COL_RED
)); break;
2099 case TGREEN
: SetColor(Color(COL_GREEN
)); break;
2100 case TBLUE
: SetColor(Color(COL_BLUE
)); break;
2101 case TCYAN
: SetColor(Color(COL_CYAN
)); break;
2102 case TMAGENTA
: SetColor(Color(COL_MAGENTA
)); break;
2103 case TYELLOW
: SetColor(Color(COL_YELLOW
)); break;
2106 DBG_ASSERT(FALSE
, "Sm: unbekannter Fall");
2109 pNode
->Arrange(rDev
, rFormat
);
2111 SmRect::operator = (pNode
->GetRect());
2115 void SmFontNode::SetSizeParameter(const Fraction
& rValue
, USHORT Type
)
2122 /**************************************************************************/
2125 SmPolyLineNode::SmPolyLineNode(const SmToken
&rNodeToken
)
2126 : SmGraphicNode(NPOLYLINE
, rNodeToken
)
2133 void SmPolyLineNode::AdaptToX(const OutputDevice
&/*rDev*/, ULONG nNewWidth
)
2135 aToSize
.Width() = nNewWidth
;
2139 void SmPolyLineNode::AdaptToY(const OutputDevice
&/*rDev*/, ULONG nNewHeight
)
2141 GetFont().FreezeBorderWidth();
2142 aToSize
.Height() = nNewHeight
;
2146 void SmPolyLineNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2148 //! some routines being called extract some info from the OutputDevice's
2149 //! font (eg the space to be used for borders OR the font name(!!)).
2150 //! Thus the font should reflect the needs and has to be set!
2151 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2152 aTmpDev
.SetFont(GetFont());
2154 long nBorderwidth
= GetFont().GetBorderWidth();
2157 // Das Polygon mit den beiden Endpunkten bilden
2159 DBG_ASSERT(aPoly
.GetSize() == 2, "Sm : falsche Anzahl von Punkten");
2160 Point aPointA
, aPointB
;
2161 if (GetToken().eType
== TWIDESLASH
)
2163 aPointA
.X() = nBorderwidth
;
2164 aPointA
.Y() = aToSize
.Height() - nBorderwidth
;
2165 aPointB
.X() = aToSize
.Width() - nBorderwidth
;
2166 aPointB
.Y() = nBorderwidth
;
2170 DBG_ASSERT(GetToken().eType
== TWIDEBACKSLASH
, "Sm : unerwartetes Token");
2172 aPointA
.Y() = nBorderwidth
;
2173 aPointB
.X() = aToSize
.Width() - nBorderwidth
;
2174 aPointB
.Y() = aToSize
.Height() - nBorderwidth
;
2176 aPoly
.SetPoint(aPointA
, 0);
2177 aPoly
.SetPoint(aPointB
, 1);
2179 long nThick
= GetFont().GetSize().Height()
2180 * rFormat
.GetDistance(DIS_STROKEWIDTH
) / 100L;
2181 nWidth
= nThick
+ 2 * nBorderwidth
;
2183 SmRect::operator = (SmRect(aToSize
.Width(), aToSize
.Height()));
2187 void SmPolyLineNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
2192 long nBorderwidth
= GetFont().GetBorderWidth();
2195 aInfo
.SetWidth(nWidth
- 2 * nBorderwidth
);
2197 Point
aOffset (Point() - aPoly
.GetBoundRect().TopLeft()
2198 + Point(nBorderwidth
, nBorderwidth
)),
2199 aPos (rPosition
+ aOffset
);
2200 ((Polygon
&) aPoly
).Move(aPos
.X(), aPos
.Y());
2202 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, FALSE
);
2203 aTmpDev
.SetLineColor( GetFont().GetColor() );
2205 rDev
.DrawPolyLine(aPoly
, aInfo
);
2207 #ifdef SM_RECT_DEBUG
2211 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2212 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2217 /**************************************************************************/
2219 void SmRootSymbolNode::AdaptToX(const OutputDevice
&/*rDev*/, ULONG nWidth
)
2221 nBodyWidth
= nWidth
;
2225 void SmRootSymbolNode::AdaptToY(const OutputDevice
&rDev
, ULONG nHeight
)
2227 // etwas extra Laenge damit der horizontale Balken spaeter ueber dem
2228 // Argument positioniert ist
2229 SmMathSymbolNode::AdaptToY(rDev
, nHeight
+ nHeight
/ 10L);
2233 void SmRootSymbolNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
2238 // draw root-sign itself
2239 SmMathSymbolNode::Draw(rDev
, rPosition
);
2241 SmTmpDevice
aTmpDev( (OutputDevice
&) rDev
, TRUE
);
2242 aTmpDev
.SetFillColor(GetFont().GetColor());
2243 rDev
.SetLineColor();
2244 aTmpDev
.SetFont( GetFont() );
2246 // since the width is always unscaled it corresponds ot the _original_
2247 // _unscaled_ font height to be used, we use that to calculate the
2248 // bar height. Thus it is independent of the arguments height.
2249 // ( see display of sqrt QQQ versus sqrt stack{Q#Q#Q#Q} )
2250 long nBarHeight
= GetWidth() * 7L / 100L;
2251 long nBarWidth
= nBodyWidth
+ GetBorderWidth();
2252 Point
aBarOffset( GetWidth(), +GetBorderWidth() );
2253 Point
aBarPos( rPosition
+ aBarOffset
);
2255 Rectangle
aBar(aBarPos
, Size( nBarWidth
, nBarHeight
) );
2256 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
2257 //! increasing zoomfactor.
2258 // This is done by shifting it's output-position to a point that
2259 // corresponds exactly to a pixel on the output device.
2260 Point
aDrawPos( rDev
.PixelToLogic(rDev
.LogicToPixel(aBar
.TopLeft())) );
2261 //aDrawPos.X() = aBar.Left(); //! don't change X position
2262 aBar
.SetPos( aDrawPos
);
2264 rDev
.DrawRect( aBar
);
2266 #ifdef SM_RECT_DEBUG
2270 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2271 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2276 /**************************************************************************/
2279 void SmRectangleNode::AdaptToX(const OutputDevice
&/*rDev*/, ULONG nWidth
)
2281 aToSize
.Width() = nWidth
;
2285 void SmRectangleNode::AdaptToY(const OutputDevice
&/*rDev*/, ULONG nHeight
)
2287 GetFont().FreezeBorderWidth();
2288 aToSize
.Height() = nHeight
;
2292 void SmRectangleNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&/*rFormat*/)
2294 long nFontHeight
= GetFont().GetSize().Height();
2295 long nWidth
= aToSize
.Width(),
2296 nHeight
= aToSize
.Height();
2298 nHeight
= nFontHeight
/ 30;
2300 nWidth
= nFontHeight
/ 3;
2302 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2303 aTmpDev
.SetFont(GetFont());
2305 // add some borderspace
2306 ULONG nTmpBorderWidth
= GetFont().GetBorderWidth();
2307 //nWidth += nTmpBorderWidth;
2308 nHeight
+= 2 * nTmpBorderWidth
;
2310 //! use this method in order to have 'SmRect::HasAlignInfo() == TRUE'
2311 //! and thus having the attribut-fences updated in 'SmRect::ExtendBy'
2312 SmRect::operator = (SmRect(nWidth
, nHeight
));
2316 void SmRectangleNode::Draw(OutputDevice
&rDev
, const Point
&rPosition
) const
2321 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, FALSE
);
2322 aTmpDev
.SetFillColor(GetFont().GetColor());
2323 rDev
.SetLineColor();
2324 aTmpDev
.SetFont(GetFont());
2326 ULONG nTmpBorderWidth
= GetFont().GetBorderWidth();
2328 // get rectangle and remove borderspace
2329 Rectangle
aTmp (AsRectangle() + rPosition
- GetTopLeft());
2330 aTmp
.Left() += nTmpBorderWidth
;
2331 aTmp
.Right() -= nTmpBorderWidth
;
2332 aTmp
.Top() += nTmpBorderWidth
;
2333 aTmp
.Bottom() -= nTmpBorderWidth
;
2335 DBG_ASSERT(aTmp
.GetHeight() > 0 && aTmp
.GetWidth() > 0,
2336 "Sm: leeres Rechteck");
2338 //! avoid GROWING AND SHRINKING of drawn rectangle when constantly
2339 //! increasing zoomfactor.
2340 // This is done by shifting it's output-position to a point that
2341 // corresponds exactly to a pixel on the output device.
2342 Point
aPos (rDev
.PixelToLogic(rDev
.LogicToPixel(aTmp
.TopLeft())));
2345 rDev
.DrawRect(aTmp
);
2347 #ifdef SM_RECT_DEBUG
2351 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2352 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2357 /**************************************************************************/
2360 void SmTextNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2362 SmNode::Prepare(rFormat
, rDocShell
);
2364 // default setting for horizontal alignment of nodes with TTEXT
2365 // content is as alignl (cannot be done in Arrange since it would
2366 // override the settings made by an SmAlignNode before)
2367 if (TTEXT
== GetToken().eType
)
2368 SetRectHorAlign( RHA_LEFT
);
2370 aText
= GetToken().aText
;
2371 GetFont() = rFormat
.GetFont(GetFontDesc());
2373 if (IsItalic( GetFont() ))
2374 Attributes() |= ATTR_ITALIC
;
2375 if (IsBold( GetFont() ))
2376 Attributes() |= ATTR_BOLD
;
2378 // special handling for ':' where it is a token on it's own and is likely
2379 // to be used for mathematical notations. (E.g. a:b = 2:3)
2380 // In that case it should not be displayed in italic.
2381 if (GetToken().aText
.Len() == 1 && GetToken().aText
.GetChar(0) == ':')
2382 Attributes() &= ~ATTR_ITALIC
;
2386 void SmTextNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2388 PrepareAttributes();
2390 USHORT nSizeDesc
= GetFontDesc() == FNT_FUNCTION
?
2391 SIZ_FUNCTION
: SIZ_TEXT
;
2392 GetFont() *= Fraction (rFormat
.GetRelSize(nSizeDesc
), 100);
2394 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2395 aTmpDev
.SetFont(GetFont());
2397 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, aText
, GetFont().GetBorderWidth()));
2400 void SmTextNode::CreateTextFromNode(String
&rText
)
2403 if (GetToken().eType
== TTEXT
)
2410 SmParser aParseTest
;
2411 SmNode
*pTable
= aParseTest
.Parse(GetToken().aText
);
2413 if ( (pTable
->GetType() == NTABLE
) && (pTable
->GetNumSubNodes() == 1) )
2415 SmNode
*pResult
= pTable
->GetSubNode(0);
2416 if ( (pResult
->GetType() == NLINE
) &&
2417 (pResult
->GetNumSubNodes() == 1) )
2419 pResult
= pResult
->GetSubNode(0);
2420 if ( (pResult
->GetType() == NEXPRESSION
) &&
2421 (pResult
->GetNumSubNodes() == 1) )
2423 pResult
= pResult
->GetSubNode(0);
2424 if (pResult
->GetType() == NTEXT
)
2431 if ((GetToken().eType
== TIDENT
) && (GetFontDesc() == FNT_FUNCTION
))
2433 //Search for existing functions and remove extraenous keyword
2434 APPEND(rText
,"func ");
2437 APPEND(rText
,"italic ");
2444 rText
.Append(GetToken().aText
);
2451 void SmTextNode::Draw(OutputDevice
&rDev
, const Point
& rPosition
) const
2453 if (IsPhantom() || aText
.Len() == 0 || aText
.GetChar(0) == xub_Unicode('\0'))
2456 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, FALSE
);
2457 aTmpDev
.SetFont(GetFont());
2459 Point
aPos (rPosition
);
2460 aPos
.Y() += GetBaselineOffset();
2461 // auf Pixelkoordinaten runden
2462 aPos
= rDev
.PixelToLogic( rDev
.LogicToPixel(aPos
) );
2464 rDev
.DrawStretchText(aPos
, GetWidth(), aText
);
2466 #ifdef SM_RECT_DEBUG
2470 int nRFlags
= SM_RECT_CORE
| SM_RECT_ITALIC
| SM_RECT_LINES
| SM_RECT_MID
;
2471 SmRect::Draw(rDev
, rPosition
, nRFlags
);
2475 void SmTextNode::GetAccessibleText( String
&rText
) const
2480 /**************************************************************************/
2482 void SmMatrixNode::CreateTextFromNode(String
&rText
)
2484 APPEND(rText
,"matrix {");
2485 for (USHORT i
= 0; i
< nNumRows
; i
++)
2487 for (USHORT j
= 0; j
< nNumCols
; j
++)
2489 SmNode
*pNode
= GetSubNode(i
* nNumCols
+ j
);
2490 pNode
->CreateTextFromNode(rText
);
2491 if (j
!= nNumCols
-1)
2494 if (i
!= nNumRows
-1)
2495 APPEND(rText
,"## ");
2497 rText
.EraseTrailingChars();
2502 void SmMatrixNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2509 // initialize array that is to hold the maximum widhts of all
2510 // elements (subnodes) in that column.
2511 long *pColWidth
= new long[nNumCols
];
2512 for (j
= 0; j
< nNumCols
; j
++)
2515 // arrange subnodes and calculate the aboves arrays contents
2516 USHORT nNodes
= GetNumSubNodes();
2517 for (i
= 0; i
< nNodes
; i
++)
2519 USHORT nIdx
= nNodes
- 1 - i
;
2520 if (NULL
!= (pNode
= GetSubNode(nIdx
)))
2522 pNode
->Arrange(rDev
, rFormat
);
2523 int nCol
= nIdx
% nNumCols
;
2524 pColWidth
[nCol
] = Max(pColWidth
[nCol
], pNode
->GetItalicWidth());
2528 // norm distance from which the following two are calcutated
2529 const int nNormDist
= 3 * GetFont().GetSize().Height();
2531 // define horizontal and vertical minimal distances that seperate
2533 long nHorDist
= nNormDist
* rFormat
.GetDistance(DIS_MATRIXCOL
) / 100L,
2534 nVerDist
= nNormDist
* rFormat
.GetDistance(DIS_MATRIXROW
) / 100L;
2536 // build array that holds the leftmost position for each column
2537 long *pColLeft
= new long[nNumCols
];
2539 for (j
= 0; j
< nNumCols
; j
++)
2541 nX
+= pColWidth
[j
] + nHorDist
;
2546 SmRect::operator = (SmRect());
2547 for (i
= 0; i
< nNumRows
; i
++)
2548 { aLineRect
= SmRect();
2549 for (j
= 0; j
< nNumCols
; j
++)
2550 { SmNode
*pTmpNode
= GetSubNode(i
* nNumCols
+ j
);
2551 DBG_ASSERT(pTmpNode
, "Sm: NULL pointer");
2553 const SmRect
&rNodeRect
= pTmpNode
->GetRect();
2555 // align all baselines in that row if possible
2556 aPos
= rNodeRect
.AlignTo(aLineRect
, RP_RIGHT
, RHA_CENTER
, RVA_BASELINE
);
2557 aPos
.X() += nHorDist
;
2559 // get horizontal alignment
2560 const SmNode
*pCoNode
= pTmpNode
->GetLeftMost();
2561 RectHorAlign eHorAlign
= pCoNode
->GetRectHorAlign();
2563 // caculate horizontal position of element depending on column
2564 // and horizontal alignment
2567 aPos
.X() = rNodeRect
.GetLeft() + pColLeft
[j
];
2570 aPos
.X() = rNodeRect
.GetLeft() + pColLeft
[j
]
2572 - rNodeRect
.GetItalicCenterX();
2575 aPos
.X() = rNodeRect
.GetLeft() + pColLeft
[j
]
2576 + pColWidth
[j
] - rNodeRect
.GetItalicWidth();
2580 pTmpNode
->MoveTo(aPos
);
2581 aLineRect
.ExtendBy(rNodeRect
, RCP_XOR
);
2584 aPos
= aLineRect
.AlignTo(*this, RP_BOTTOM
, RHA_CENTER
, RVA_BASELINE
);
2585 aPos
.Y() += nVerDist
;
2587 // move 'aLineRect' and rectangles in that line to final position
2588 aDelta
.X() = 0; // since horizontal alignment is already done
2589 aDelta
.Y() = aPos
.Y() - aLineRect
.GetTop();
2590 aLineRect
.Move(aDelta
);
2591 for (j
= 0; j
< nNumCols
; j
++)
2592 if (NULL
!= (pNode
= GetSubNode(i
* nNumCols
+ j
)))
2593 pNode
->Move(aDelta
);
2595 ExtendBy(aLineRect
, RCP_NONE
);
2599 delete [] pColWidth
;
2603 void SmMatrixNode::SetRowCol(USHORT nMatrixRows
, USHORT nMatrixCols
)
2605 nNumRows
= nMatrixRows
;
2606 nNumCols
= nMatrixCols
;
2610 SmNode
* SmMatrixNode::GetLeftMost()
2616 /**************************************************************************/
2619 SmMathSymbolNode::SmMathSymbolNode(const SmToken
&rNodeToken
)
2620 : SmSpecialNode(NMATH
, rNodeToken
, FNT_MATH
)
2622 xub_Unicode cChar
= GetToken().cMathChar
;
2623 if ((xub_Unicode
) '\0' != cChar
)
2627 void SmMathSymbolNode::AdaptToX(const OutputDevice
&rDev
, ULONG nWidth
)
2629 // Since there is no function to do this, we try to approximate it:
2630 Size
aFntSize (GetFont().GetSize());
2632 //! however the result is a bit better with 'nWidth' as initial font width
2633 aFntSize
.Width() = nWidth
;
2634 GetFont().SetSize(aFntSize
);
2636 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2637 aTmpDev
.SetFont(GetFont());
2639 // get denominator of error factor for width
2640 long nTmpBorderWidth
= GetFont().GetBorderWidth();
2641 long nDenom
= SmRect(aTmpDev
, NULL
, GetText(), nTmpBorderWidth
).GetItalicWidth();
2643 // scale fontwidth with this error factor
2644 aFntSize
.Width() *= nWidth
;
2645 aFntSize
.Width() /= nDenom
? nDenom
: 1;
2647 GetFont().SetSize(aFntSize
);
2650 void SmMathSymbolNode::AdaptToY(const OutputDevice
&rDev
, ULONG nHeight
)
2652 GetFont().FreezeBorderWidth();
2653 Size
aFntSize (GetFont().GetSize());
2655 // da wir nur die Hoehe skalieren wollen muesen wir hier ggf die Fontweite
2656 // ermitteln um diese beizubehalten.
2657 if (aFntSize
.Width() == 0)
2659 OutputDevice
&rDevNC
= (OutputDevice
&) rDev
;
2660 rDevNC
.Push(PUSH_FONT
| PUSH_MAPMODE
);
2661 rDevNC
.SetFont(GetFont());
2662 aFntSize
.Width() = rDev
.GetFontMetric().GetSize().Width();
2665 DBG_ASSERT(aFntSize
.Width() != 0, "Sm: ");
2667 //! however the result is a bit better with 'nHeight' as initial
2669 aFntSize
.Height() = nHeight
;
2670 GetFont().SetSize(aFntSize
);
2672 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2673 aTmpDev
.SetFont(GetFont());
2675 // get denominator of error factor for height
2676 long nTmpBorderWidth
= GetFont().GetBorderWidth();
2677 long nDenom
= SmRect(aTmpDev
, NULL
, GetText(), nTmpBorderWidth
).GetHeight();
2679 // scale fontwidth with this error factor
2680 aFntSize
.Height() *= nHeight
;
2681 aFntSize
.Height() /= nDenom
? nDenom
: 1;
2683 GetFont().SetSize(aFntSize
);
2687 void SmMathSymbolNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2689 SmNode::Prepare(rFormat
, rDocShell
);
2691 GetFont() = rFormat
.GetFont(GetFontDesc());
2692 // use same font size as is used for variables
2693 GetFont().SetSize( rFormat
.GetFont( FNT_VARIABLE
).GetSize() );
2695 DBG_ASSERT(GetFont().GetCharSet() == RTL_TEXTENCODING_SYMBOL
||
2696 GetFont().GetCharSet() == RTL_TEXTENCODING_UNICODE
,
2697 "incorrect charset for character from StarMath/StarSymbol font");
2699 Flags() |= FLG_FONT
| FLG_ITALIC
;
2703 void SmMathSymbolNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2705 const XubString
&rText
= GetText();
2707 if (rText
.Len() == 0 || rText
.GetChar(0) == xub_Unicode('\0'))
2708 { SmRect::operator = (SmRect());
2712 PrepareAttributes();
2714 GetFont() *= Fraction (rFormat
.GetRelSize(SIZ_TEXT
), 100);
2716 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2717 aTmpDev
.SetFont(GetFont());
2719 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, rText
, GetFont().GetBorderWidth()));
2722 void SmMathSymbolNode::CreateTextFromNode(String
&rText
)
2725 MathType::LookupChar(GetToken().cMathChar
, sStr
);
2729 void SmRectangleNode::CreateTextFromNode(String
&rText
)
2731 switch (GetToken().eType
)
2734 APPEND(rText
,"underline ");
2737 APPEND(rText
,"overline ");
2740 APPEND(rText
,"overstrike ");
2747 void SmAttributNode::CreateTextFromNode(String
&rText
)
2750 USHORT nSize
= GetNumSubNodes();
2751 DBG_ASSERT(nSize
== 2, "Node missing members");
2753 sal_Unicode nLast
=0;
2754 if (NULL
!= (pNode
= GetSubNode(0)))
2757 pNode
->CreateTextFromNode(aStr
);
2762 nLast
= aStr
.GetChar(0);
2766 APPEND(rText
,"overline ");
2769 APPEND(rText
,"dot ");
2772 APPEND(rText
,"widetilde ");
2775 APPEND(rText
,"ddot ");
2780 APPEND(rText
,"dddot ");
2783 rText
.Append(nLast
);
2790 if (NULL
!= (pNode
= GetSubNode(1)))
2791 pNode
->CreateTextFromNode(rText
);
2793 rText
.EraseTrailingChars();
2795 if (nLast
== 0xE082)
2796 APPEND(rText
," overbrace {}");
2801 /**************************************************************************/
2804 void SmSpecialNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2806 SmNode::Prepare(rFormat
, rDocShell
);
2809 SmModule
*pp
= SM_MOD1();
2811 if (NULL
!= (pSym
= pp
->GetSymSetManager().GetSymbolByName(GetToken().aText
)))
2813 SetText( pSym
->GetCharacter() );
2814 GetFont() = pSym
->GetFace();
2818 SetText( GetToken().aText
);
2819 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
2821 // use same font size as is used for variables
2822 GetFont().SetSize( rFormat
.GetFont( FNT_VARIABLE
).GetSize() );
2824 //! eigentlich sollten nur WEIGHT_NORMAL und WEIGHT_BOLD vorkommen...
2825 //! In der sms-Datei gibt es jedoch zB auch 'WEIGHT_ULTRALIGHT'
2826 //! daher vergleichen wir hier mit > statt mit != .
2827 //! (Langfristig sollte die Notwendigkeit fuer 'PrepareAttribut', und damit
2828 //! fuer dieses hier, mal entfallen.)
2830 //! see also SmFontStyles::GetStyleName
2831 if (IsItalic( GetFont() ))
2832 SetAttribut(ATTR_ITALIC
);
2833 if (IsBold( GetFont() ))
2834 SetAttribut(ATTR_BOLD
);
2836 Flags() |= FLG_FONT
;
2840 void SmSpecialNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2842 PrepareAttributes();
2844 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2845 aTmpDev
.SetFont(GetFont());
2847 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(), GetFont().GetBorderWidth()));
2851 void SmSpecialNode::Draw(OutputDevice
&rDev
, const Point
& rPosition
) const
2853 //! since this chars might come from any font, that we may not have
2854 //! set to ALIGN_BASELINE yet, we do it now.
2855 ((SmSpecialNode
*)this)->GetFont().SetAlign(ALIGN_BASELINE
);
2857 SmTextNode::Draw(rDev
, rPosition
);
2861 /**************************************************************************/
2864 void SmGlyphSpecialNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2866 PrepareAttributes();
2868 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2869 aTmpDev
.SetFont(GetFont());
2871 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(),
2872 GetFont().GetBorderWidth()).AsGlyphRect());
2876 /**************************************************************************/
2879 void SmPlaceNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2881 SmNode::Prepare(rFormat
, rDocShell
);
2883 GetFont().SetColor(COL_GRAY
);
2884 Flags() |= FLG_COLOR
| FLG_FONT
| FLG_ITALIC
;
2888 void SmPlaceNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2890 PrepareAttributes();
2892 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2893 aTmpDev
.SetFont(GetFont());
2895 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, GetText(), GetFont().GetBorderWidth()));
2899 /**************************************************************************/
2902 void SmErrorNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2904 SmNode::Prepare(rFormat
, rDocShell
);
2906 GetFont().SetColor(COL_RED
);
2907 Flags() |= FLG_VISIBLE
| FLG_BOLD
| FLG_ITALIC
2908 | FLG_COLOR
| FLG_FONT
| FLG_SIZE
;
2912 void SmErrorNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2914 PrepareAttributes();
2916 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2917 aTmpDev
.SetFont(GetFont());
2919 const XubString
&rText
= GetText();
2920 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, rText
, GetFont().GetBorderWidth()));
2924 /**************************************************************************/
2927 void SmBlankNode::IncreaseBy(const SmToken
&rToken
)
2929 switch(rToken
.eType
)
2931 case TBLANK
: nNum
+= 4; break;
2932 case TSBLANK
: nNum
+= 1; break;
2939 void SmBlankNode::Prepare(const SmFormat
&rFormat
, const SmDocShell
&rDocShell
)
2941 SmNode::Prepare(rFormat
, rDocShell
);
2943 //! hier muss/sollte es lediglich nicht der StarMath Font sein,
2944 //! damit fuer das in Arrange verwendete Zeichen ein "normales"
2945 //! (ungecliptes) Rechteck erzeugt wird.
2946 GetFont() = rFormat
.GetFont(FNT_VARIABLE
);
2948 Flags() |= FLG_FONT
| FLG_BOLD
| FLG_ITALIC
;
2952 void SmBlankNode::Arrange(const OutputDevice
&rDev
, const SmFormat
&rFormat
)
2954 SmTmpDevice
aTmpDev ((OutputDevice
&) rDev
, TRUE
);
2955 aTmpDev
.SetFont(GetFont());
2957 // Abstand von der Fonthoehe abhaengig machen
2958 // (damit er beim skalieren (zB size *2 {a ~ b}) mitwaechst)
2959 long nDist
= GetFont().GetSize().Height() / 10L,
2960 nSpace
= nNum
* nDist
;
2962 // ein SmRect mit Baseline und allem drum und dran besorgen
2963 SmRect::operator = (SmRect(aTmpDev
, &rFormat
, XubString(xub_Unicode(' ')),
2964 GetFont().GetBorderWidth()));
2966 // und dieses auf die gewuenschte Breite bringen
2967 SetItalicSpaces(0, 0);