update dev300-m58
[ooovba.git] / starmath / source / node.cxx
blob051542c4732483fc158659a3dac2dd6b52ebf01d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: node.cxx,v $
10 * $Revision: 1.42 $
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>
45 #include "node.hxx"
46 #include <rect.hxx>
47 #include "symbol.hxx"
48 #include "smmod.hxx"
49 #include <document.hxx>
50 #include <view.hxx>
51 #ifndef _MATHTYPE_HXX
52 #include "mathtype.hxx"
53 #endif
55 #include <math.h>
56 #include <float.h>
58 // define this to draw rectangles for debugging
59 //#define SM_RECT_DEBUG
61 ////////////////////////////////////////
62 // SmTmpDevice
63 // Allows for font and color changes. The original settings will be restored
64 // in the destructor.
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'
67 // functions.
68 // Usually a MapMode of 1/100th mm will be used.
71 class SmTmpDevice
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 );
81 public:
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) :
96 rOutDev(rTheDev)
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())
114 nNewCol = COL_BLACK;
115 else
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())
125 nNewCol = COL_WHITE;
126 else if (aBgCol.IsBright() && aTmpColor.IsBright())
127 nNewCol = COL_BLACK;
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)
146 eType = eNodeType;
147 eScaleMode = SCALE_NONE;
148 aNodeToken = rNodeToken;
149 nAccIndex = -1;
153 SmNode::~SmNode()
158 BOOL SmNode::IsVisible() const
160 return FALSE;
164 USHORT SmNode::GetNumSubNodes() const
166 return 0;
170 SmNode * SmNode::GetSubNode(USHORT /*nIndex*/)
172 return NULL;
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;
193 SmNode *pNode;
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);
206 SmNode *pNode;
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)
216 if (
217 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
218 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
221 nAttributes |= nAttrib;
224 SmNode *pNode;
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)
234 if (
235 (nAttrib == ATTR_BOLD && !(Flags() & FLG_BOLD)) ||
236 (nAttrib == ATTR_ITALIC && !(Flags() & FLG_ITALIC))
239 nAttributes &= ~nAttrib;
242 SmNode *pNode;
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))
253 GetFont() = rFace;
255 SmNode *pNode;
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
266 Size aFntSize;
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;
277 switch(nType)
279 case FNTSIZ_ABSOLUT:
280 aFntSize.Height() = nHeight;
281 break;
283 case FNTSIZ_PLUS:
284 aFntSize.Height() += nHeight;
285 break;
287 case FNTSIZ_MINUS:
288 aFntSize.Height() -= nHeight;
289 break;
291 case FNTSIZ_MULTIPLY:
292 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) * rSize);
293 break;
295 case FNTSIZ_DIVIDE:
296 if (rSize != Fraction(0L))
297 aFntSize.Height() = (long) (Fraction(aFntSize.Height()) / rSize);
298 break;
299 default:
300 break;
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);
311 SmNode *pNode;
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)
321 GetFont() *= rSize;
323 SmNode *pNode;
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;
336 if (bApplyToSubTree)
338 SmNode *pNode;
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
357 bIsDebug = TRUE;
358 #else
359 bIsDebug = FALSE;
360 #endif
361 bIsPhantom = FALSE;
362 nFlags = 0;
363 nAttributes = 0;
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);
378 SmNode *pNode;
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;
394 SmNode *pNode;
395 USHORT nSize = GetNumSubNodes();
396 for (USHORT i = 0; i < nSize; i++)
397 if (NULL != (pNode = pThis->GetSubNode(i)))
398 pNode->ToggleDebug();
400 #endif
403 void SmNode::Move(const Point& rPosition)
405 if (rPosition.X() == 0 && rPosition.Y() == 0)
406 return;
408 SmRect::Move(rPosition);
410 SmNode *pNode;
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)
420 SmNode *pNode;
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)
429 SmNode *pNode;
430 USHORT nSize = GetNumSubNodes();
431 if (nSize > 1)
432 rText.Append('{');
433 for (USHORT i = 0; i < nSize; i++)
434 if (NULL != (pNode = GetSubNode(i)))
435 pNode->CreateTextFromNode(rText);
436 if (nSize > 1)
438 rText.EraseTrailingChars();
439 APPEND(rText,"} ");
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
456 if (IsPhantom())
457 return;
459 const SmNode *pNode;
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);
467 #ifdef SM_RECT_DEBUG
468 if (!IsDebug())
469 return;
471 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
472 SmRect::Draw(rDev, rPosition, nRFlags);
473 #endif
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)
481 if ( IsVisible()
482 && nRow == GetToken().nRow
483 && nCol >= GetToken().nCol && nCol < GetToken().nCol + GetToken().aText.Len())
484 return this;
485 else
487 USHORT nNumSubNodes = GetNumSubNodes();
488 for (USHORT i = 0; i < nNumSubNodes; i++)
489 { const SmNode *pNode = GetSubNode(i);
491 if (!pNode)
492 continue;
494 const SmNode *pResult = pNode->FindTokenAt(nRow, nCol);
495 if (pResult)
496 return pResult;
500 return 0;
504 const SmNode * SmNode::FindRectClosestTo(const Point &rPoint) const
506 long nDist = LONG_MAX;
507 const SmNode *pResult = 0;
509 if (IsVisible())
510 pResult = this;
511 else
513 USHORT nNumSubNodes = GetNumSubNodes();
514 for (USHORT i = 0; i < nNumSubNodes; i++)
515 { const SmNode *pNode = GetSubNode(i);
517 if (!pNode)
518 continue;
520 long nTmp;
521 const SmNode *pFound = pNode->FindRectClosestTo(rPoint);
522 if (pFound && (nTmp = pFound->OrientedDist(rPoint)) < nDist)
523 { nDist = nTmp;
524 pResult = pFound;
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))
533 break;
538 return pResult;
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();
551 String aTxt;
552 if (nIdx >= 0)
553 GetAccessibleText( aTxt ); // get text if used in following 'if' statement
555 if (nIdx >= 0
556 && nIdx <= nAccIdx && nAccIdx < nIdx + aTxt.Len())
557 pResult = this;
558 else
560 USHORT nNumSubNodes = GetNumSubNodes();
561 for (USHORT i = 0; i < nNumSubNodes; i++)
563 const SmNode *pNode = GetSubNode(i);
564 if (!pNode)
565 continue;
567 pResult = pNode->FindNodeWithAccessibleIndex(nAccIdx);
568 if (pResult)
569 return pResult;
573 return pResult;
576 ///////////////////////////////////////////////////////////////////////////
578 SmStructureNode::SmStructureNode( const SmStructureNode &rNode ) :
579 SmNode( rNode.GetType(), rNode.GetToken() )
581 ULONG i;
582 for (i = 0; i < aSubNodes.size(); i++)
583 delete aSubNodes[i];
584 aSubNodes.resize(0);
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()
598 SmNode *pNode;
600 for (USHORT i = 0; i < GetNumSubNodes(); i++)
601 if (NULL != (pNode = GetSubNode(i)))
602 delete pNode;
606 SmStructureNode & SmStructureNode::operator = ( const SmStructureNode &rNode )
608 SmNode::operator = ( rNode );
610 ULONG i;
611 for (i = 0; i < aSubNodes.size(); i++)
612 delete aSubNodes[i];
613 aSubNodes.resize(0);
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;
623 return *this;
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 );
631 if (pFirst)
632 aSubNodes[0] = pFirst;
633 if (pSecond)
634 aSubNodes[1] = pSecond;
635 if (pThird)
636 aSubNodes[2] = pThird;
640 void SmStructureNode::SetSubNodes(const SmNodeArray &rNodeArray)
642 aSubNodes = rNodeArray;
646 BOOL SmStructureNode::IsVisible() const
648 return FALSE;
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);
670 if (pNode)
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
686 return TRUE;
690 USHORT SmVisibleNode::GetNumSubNodes() const
692 return 0;
696 SmNode * SmVisibleNode::GetSubNode(USHORT /*nIndex*/)
698 return NULL;
702 ///////////////////////////////////////////////////////////////////////////
704 void SmGraphicNode::GetAccessibleText( String &rText ) const
706 rText += GetToken().aText;
709 ///////////////////////////////////////////////////////////////////////////
712 void SmExpressionNode::CreateTextFromNode(String &rText)
714 SmNode *pNode;
715 USHORT nSize = GetNumSubNodes();
716 if (nSize > 1)
717 rText.Append('{');
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) != '-')))
726 rText.Append(' ');
729 if (nSize > 1)
731 rText.EraseTrailingChars();
732 APPEND(rText,"} ");
737 ///////////////////////////////////////////////////////////////////////////
739 void SmTableNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
740 // arranges all subnodes in one column
742 Point rPosition;
744 SmNode *pNode;
745 USHORT nSize = GetNumSubNodes();
747 // make distance depend on font size
748 long nDist = +(rFormat.GetDistance(DIS_VERTICAL)
749 * GetFont().GetSize().Height()) / 100L;
751 if (nSize < 1)
752 return;
754 // arrange subnodes and get maximum width of them
755 long nMaxWidth = 0,
756 nTmp;
757 USHORT i;
758 for (i = 0; i < nSize; i++)
759 if (NULL != (pNode = GetSubNode(i)))
760 { pNode->Arrange(rDev, rFormat);
761 if ((nTmp = pNode->GetItalicWidth()) > nMaxWidth)
762 nMaxWidth = nTmp;
765 Point aPos;
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);
776 if (i)
777 aPos.Y() += nDist;
778 pNode->MoveTo(aPos);
779 ExtendBy(rNodeRect, nSize > 1 ? RCP_NONE : RCP_ARG);
785 SmNode * SmTableNode::GetLeftMost()
787 return this;
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);
801 Flags() |= FLG_FONT;
805 /**************************************************************************/
808 void SmLineNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
809 // arranges all subnodes in one row with some extra space between
811 SmNode *pNode;
812 USHORT nSize = GetNumSubNodes();
813 USHORT i;
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
826 //! 'vec {a}'.
827 SmRect::operator = (SmRect(aTmpDev, &rFormat, C2S("a"),
828 GetFont().GetBorderWidth()));
829 // make sure that the rectangle occupies (almost) no space
830 SetWidth(1);
831 SetItalicSpaces(0, 0);
833 if (nSize < 1)
834 return;
836 // make distance depend on font size
837 long nDist = +(rFormat.GetDistance(DIS_HORIZONTAL)
838 * GetFont().GetSize().Height()) / 100L;
840 Point aPos;
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
847 if (i)
848 aPos.X() += nDist;
850 pNode->MoveTo(aPos);
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();
866 if (pNode)
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;
892 if (bIsPostfix)
893 aPos.X() += nDelta;
894 else
895 aPos.X() -= nDelta;
896 pOper->MoveTo(aPos);
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)
905 SetBottom(nOldBot);
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;
940 if (aPos.X() > nX)
941 aPos.X() = nX;
943 return aPos;
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);
961 long nHeight,
962 nVerOffset;
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);
979 if (pExtra)
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);
989 if (pExtra)
990 ExtendBy(*pExtra, RCP_THIS, (BOOL) TRUE);
994 void SmRootNode::CreateTextFromNode(String &rText)
996 SmNode *pExtra = GetSubNode(0);
997 if (pExtra)
999 APPEND(rText,"nroot ");
1000 pExtra->CreateTextFromNode(rText);
1002 else
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);
1033 Point aPos;
1034 aPos = pOper->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1035 aPos.X() += nDist;
1036 pOper->MoveTo(aPos);
1037 ExtendBy(*pOper, RCP_XOR);
1039 aPos = pRight->AlignTo(*this, RP_RIGHT, RHA_CENTER, RVA_BASELINE);
1040 aPos.X() += nDist;
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();
1060 if (bIsTextmode)
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;
1092 pNum->MoveTo(aPos);
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()
1120 return this;
1124 /**************************************************************************/
1127 double Det(const Point &rHeading1, const Point &rHeading2)
1128 // gibt den Wert der durch die beiden Punkte gebildeten Determinante
1129 // zurueck
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");
1142 BOOL bRes = FALSE;
1143 const double eps = 5.0 * DBL_EPSILON;
1145 double fLambda;
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;
1151 else
1153 fLambda = (rPoint1.Y() - rPoint2.Y()) / (double) rHeading2.Y();
1154 bRes = fabs(rPoint1.X() - (rPoint2.X() + fLambda * rHeading2.X())) < eps;
1157 return bRes;
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");
1168 USHORT nRes = 1;
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();
1178 else
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())
1184 / fDet;
1185 rResult = Point(rPoint1.X() + (long) (fLambda * rHeading1.X()),
1186 rPoint1.Y() + (long) (fLambda * rHeading1.Y()));
1189 return nRes;
1194 SmBinDiagonalNode::SmBinDiagonalNode(const SmToken &rNodeToken)
1195 : SmStructureNode(NBINDIAGONAL, rNodeToken)
1197 bAscending = FALSE;
1198 SetNumSubNodes(3);
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),
1216 aDownHdg (0, 100),
1217 aDiagHdg ( (long)(100.0 * cos(fAngleRad)),
1218 (long)(-100.0 * sin(fAngleRad)) );
1220 long nLeft, nRight, nTop, nBottom; // Raender des Rechtecks fuer die
1221 // Diagonale
1222 Point aPoint;
1223 if (IsAscending())
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();
1236 nTop = nRectTop;
1238 else
1240 // es muss einen Schnittpunkt mit dem rechten Rand geben!
1241 GetLineIntersectionPoint(aPoint,
1242 Point(nRectRight, nRectTop), aDownHdg,
1243 rDiagPoint, aDiagHdg);
1245 nRight = nRectRight;
1246 nTop = aPoint.Y();
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)
1259 nLeft = aPoint.X();
1260 nBottom = nRectBottom;
1262 else
1264 // es muss einen Schnittpunkt mit dem linken Rand geben!
1265 GetLineIntersectionPoint(aPoint,
1266 Point(nRectLeft, nRectTop), aDownHdg,
1267 rDiagPoint, aDiagHdg);
1269 nLeft = nRectLeft;
1270 nBottom = aPoint.Y();
1273 else
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)
1285 nLeft = aPoint.X();
1286 nTop = nRectTop;
1288 else
1290 // es muss einen Schnittpunkt mit dem linken Rand geben!
1291 GetLineIntersectionPoint(aPoint,
1292 Point(nRectLeft, nRectTop), aDownHdg,
1293 rDiagPoint, aDiagHdg);
1295 nLeft = nRectLeft;
1296 nTop = aPoint.Y();
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;
1312 else
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);
1325 rPos.X() = nLeft;
1326 rPos.Y() = nTop;
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
1359 Point aPos;
1360 aPos.X() = pLeft->GetItalicRight() + nDelta + pRight->GetItalicLeftSpace();
1361 if (IsAscending())
1362 aPos.Y() = pLeft->GetBottom() + nDelta;
1363 else
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,
1372 nTmpBaseline);
1374 SmRect::operator = (*pLeft);
1375 ExtendBy(*pRight, RCP_NONE);
1378 // Position und Groesse des Diagonalstrich ermitteln
1379 Size aTmpSize;
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);
1415 Point aPos;
1416 long nDelta, nDist;
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);
1424 if (!pSubSup)
1425 continue;
1427 // switch position of limits if we are in textmode
1428 if (rFormat.IsTextmode() && (GetToken().nGroup & TGLIMIT))
1429 switch (eSubSup)
1430 { case CSUB: eSubSup = RSUB; break;
1431 case CSUP: eSubSup = RSUP; break;
1432 default:
1433 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();
1449 nDist = 0;
1451 //! be sure that CSUB, CSUP are handled before the other cases!
1452 switch (eSubSup)
1453 { case RSUB :
1454 case LSUB :
1455 if (!bIsTextmode)
1456 nDist = nOrigHeight
1457 * rFormat.GetDistance(DIS_SUBSCRIPT) / 100L;
1458 aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1459 eSubSup == LSUB ? RP_LEFT : RP_RIGHT,
1460 RHA_CENTER, RVA_BOTTOM);
1461 aPos.Y() += nDist;
1462 nDelta = nDelimLine - aPos.Y();
1463 if (nDelta > 0)
1464 aPos.Y() += nDelta;
1465 break;
1466 case RSUP :
1467 case LSUP :
1468 if (!bIsTextmode)
1469 nDist = nOrigHeight
1470 * rFormat.GetDistance(DIS_SUPERSCRIPT) / 100L;
1471 aPos = pSubSup->GetRect().AlignTo(aTmpRect,
1472 eSubSup == LSUP ? RP_LEFT : RP_RIGHT,
1473 RHA_CENTER, RVA_TOP);
1474 aPos.Y() -= nDist;
1475 nDelta = aPos.Y() + pSubSup->GetHeight() - nDelimLine;
1476 if (nDelta > 0)
1477 aPos.Y() -= nDelta;
1478 break;
1479 case CSUB :
1480 if (!bIsTextmode)
1481 nDist = nOrigHeight
1482 * rFormat.GetDistance(DIS_LOWERLIMIT) / 100L;
1483 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_BOTTOM,
1484 RHA_CENTER, RVA_BASELINE);
1485 aPos.Y() += nDist;
1486 break;
1487 case CSUP :
1488 if (!bIsTextmode)
1489 nDist = nOrigHeight
1490 * rFormat.GetDistance(DIS_UPPERLIMIT) / 100L;
1491 aPos = pSubSup->GetRect().AlignTo(rBodyRect, RP_TOP,
1492 RHA_CENTER, RVA_BASELINE);
1493 aPos.Y() -= nDist;
1494 break;
1495 default :
1496 DBG_ASSERT(FALSE, "Sm: unbekannter Fall");
1497 break;
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)
1506 aTmpRect = *this;
1510 void SmSubSupNode::CreateTextFromNode(String &rText)
1512 SmNode *pNode;
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();
1538 rText.Append('_');
1539 pNode->CreateTextFromNode(rText);
1541 if (NULL != (pNode = GetSubNode(RSUP+1)))
1543 rText.EraseTrailingChars();
1544 rText.Append('^');
1545 pNode->CreateTextFromNode(rText);
1550 /**************************************************************************/
1552 void SmBraceNode::CreateTextFromNode(String &rText)
1554 if (GetScaleMode() == SCALE_HEIGHT)
1555 APPEND(rText,"left ");
1557 String aStr;
1558 GetSubNode(0)->CreateTextFromNode(aStr);
1559 aStr.EraseLeadingAndTrailingChars();
1560 aStr.EraseLeadingChars('\\');
1561 if (aStr.Len())
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");
1569 else
1570 rText.Append(aStr);
1571 rText.Append(' ');
1573 else
1574 APPEND(rText,"none ");
1576 GetSubNode(1)->CreateTextFromNode(rText);
1577 if (GetScaleMode() == SCALE_HEIGHT)
1578 APPEND(rText,"right ");
1580 String aStr;
1581 GetSubNode(2)->CreateTextFromNode(aStr);
1582 aStr.EraseLeadingAndTrailingChars();
1583 aStr.EraseLeadingChars('\\');
1584 if (aStr.Len())
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");
1592 else
1593 rText.Append(aStr);
1594 rText.Append(' ');
1596 else
1597 APPEND(rText,"none ");
1599 rText.Append(' ');
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
1622 USHORT nPerc = 0;
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
1631 long nBraceHeight;
1632 if (bScale)
1634 nBraceHeight = pBody->GetType() == NBRACEBODY ?
1635 ((SmBracebodyNode *) pBody)->GetBodyHeight()
1636 : pBody->GetHeight();
1637 nBraceHeight += 2 * (nBraceHeight * nPerc / 100L);
1639 else
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
1647 if (bScale)
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;
1677 Point aPos;
1678 aPos = pLeft->AlignTo(*pBody, RP_LEFT, RHA_CENTER, eVerAlign);
1679 aPos.X() -= nDist;
1680 pLeft->MoveTo(aPos);
1682 aPos = pRight->AlignTo(*pBody, RP_RIGHT, RHA_CENTER, eVerAlign);
1683 aPos.X() += nDist;
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)
1698 return;
1700 // arrange arguments
1701 USHORT i;
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);
1723 if (bScale)
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);
1746 aPosX.X() += nDist;
1748 pRight->MoveTo(Point(aPosX.X(), aPosY.Y()));
1749 ExtendBy(*pRight, bIsSeparator ? RCP_THIS : RCP_XOR);
1751 pLeft = pRight;
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
1786 RectPos eRectPos;
1787 long nFontHeight = pBody->GetFont().GetSize().Height();
1788 long nDistBody = nFontHeight * rFormat.GetDistance(DIS_ORNAMENTSIZE),
1789 nDistScript = nFontHeight;
1790 if (GetToken().eType == TOVERBRACE)
1792 eRectPos = RP_TOP;
1793 nDistBody = - nDistBody;
1794 nDistScript *= - rFormat.GetDistance(DIS_UPPERLIMIT);
1796 else // TUNDERBRACE
1798 eRectPos = RP_BOTTOM;
1799 nDistScript *= + rFormat.GetDistance(DIS_LOWERLIMIT);
1801 nDistBody /= 100L;
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!");
1829 return pNode;
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)
1841 return nHeight;
1843 if (!rFormat.IsTextmode())
1845 // set minimum size ()
1846 nHeight += (nHeight * 20L) / 100L;
1848 nHeight += nHeight
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;
1857 return nHeight;
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(),
1877 nDist = nOrigHeight
1878 * rFormat.GetDistance(DIS_OPERATORSPACE) / 100L;
1880 Point aPos = pOper->AlignTo(*pBody, RP_LEFT, RHA_CENTER, /*RVA_CENTERY*/RVA_MID);
1881 aPos.X() -= nDist;
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;
1905 default:
1906 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;
1934 long nDist = 0;
1935 switch (GetToken().eType)
1936 { case TUNDERLINE :
1937 eVerAlign = RVA_ATTRIBUT_LO;
1938 break;
1939 case TOVERSTRIKE :
1940 eVerAlign = RVA_ATTRIBUT_MID;
1941 break;
1942 default :
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);
1949 aPos.Y() -= nDist;
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)
1966 case TBOLD:
1967 APPEND(rText,"bold ");
1968 break;
1969 case TNBOLD:
1970 APPEND(rText,"nbold ");
1971 break;
1972 case TITALIC:
1973 APPEND(rText,"italic ");
1974 break;
1975 case TNITALIC:
1976 APPEND(rText,"nitalic ");
1977 break;
1978 case TPHANTOM:
1979 APPEND(rText,"phantom ");
1980 break;
1981 case TSIZE:
1983 APPEND(rText,"size ");
1984 switch (nSizeType)
1986 case FNTSIZ_PLUS:
1987 rText.Append('+');
1988 break;
1989 case FNTSIZ_MINUS:
1990 rText.Append('-');
1991 break;
1992 case FNTSIZ_MULTIPLY:
1993 rText.Append('*');
1994 break;
1995 case FNTSIZ_DIVIDE:
1996 rText.Append('/');
1997 break;
1998 case FNTSIZ_ABSOLUT:
1999 default:
2000 break;
2002 rText += String( ::rtl::math::doubleToUString(
2003 static_cast<double>(aFontSize),
2004 rtl_math_StringFormat_Automatic,
2005 rtl_math_DecimalPlaces_Max, '.', sal_True));
2006 rText.Append(' ');
2008 break;
2009 case TBLACK:
2010 APPEND(rText,"color black ");
2011 break;
2012 case TWHITE:
2013 APPEND(rText,"color white ");
2014 break;
2015 case TRED:
2016 APPEND(rText,"color red ");
2017 break;
2018 case TGREEN:
2019 APPEND(rText,"color green ");
2020 break;
2021 case TBLUE:
2022 APPEND(rText,"color blue ");
2023 break;
2024 case TCYAN:
2025 APPEND(rText,"color cyan ");
2026 break;
2027 case TMAGENTA:
2028 APPEND(rText,"color magenta ");
2029 break;
2030 case TYELLOW:
2031 APPEND(rText,"color yellow ");
2032 break;
2033 case TSANS:
2034 APPEND(rText,"font sans ");
2035 break;
2036 case TSERIF:
2037 APPEND(rText,"font serif ");
2038 break;
2039 case TFIXED:
2040 APPEND(rText,"font fixed ");
2041 break;
2042 default:
2043 break;
2045 GetSubNode(1)->CreateTextFromNode(rText);
2049 void SmFontNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2051 //! prepare subnodes first
2052 SmNode::Prepare(rFormat, rDocShell);
2054 int nFnt = -1;
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;
2060 default:
2061 break;
2063 if (nFnt != -1)
2064 { GetFont() = rFormat.GetFont( sal::static_int_cast< USHORT >(nFnt) );
2065 SetFont(GetFont());
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)
2080 { case TSIZE :
2081 pNode->SetFontSize(aFontSize, nSizeType);
2082 break;
2083 case TSANS :
2084 case TSERIF :
2085 case TFIXED :
2086 pNode->SetFont(GetFont());
2087 break;
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;
2105 default:
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)
2117 nSizeType = Type;
2118 aFontSize = rValue;
2122 /**************************************************************************/
2125 SmPolyLineNode::SmPolyLineNode(const SmToken &rNodeToken)
2126 : SmGraphicNode(NPOLYLINE, rNodeToken)
2128 aPoly.SetSize(2);
2129 nWidth = 0;
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;
2168 else
2170 DBG_ASSERT(GetToken().eType == TWIDEBACKSLASH, "Sm : unerwartetes Token");
2171 aPointA.X() =
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
2189 if (IsPhantom())
2190 return;
2192 long nBorderwidth = GetFont().GetBorderWidth();
2194 LineInfo aInfo;
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
2208 if (!IsDebug())
2209 return;
2211 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2212 SmRect::Draw(rDev, rPosition, nRFlags);
2213 #endif
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
2235 if (IsPhantom())
2236 return;
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
2267 if (!IsDebug())
2268 return;
2270 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2271 SmRect::Draw(rDev, rPosition, nRFlags);
2272 #endif
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();
2297 if (nHeight == 0)
2298 nHeight = nFontHeight / 30;
2299 if (nWidth == 0)
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
2318 if (IsPhantom())
2319 return;
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())));
2343 aTmp.SetPos(aPos);
2345 rDev.DrawRect(aTmp);
2347 #ifdef SM_RECT_DEBUG
2348 if (!IsDebug())
2349 return;
2351 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2352 SmRect::Draw(rDev, rPosition, nRFlags);
2353 #endif
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)
2402 BOOL bQuoted=FALSE;
2403 if (GetToken().eType == TTEXT)
2405 rText.Append('\"');
2406 bQuoted=TRUE;
2408 else
2410 SmParser aParseTest;
2411 SmNode *pTable = aParseTest.Parse(GetToken().aText);
2412 bQuoted=TRUE;
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)
2425 bQuoted=FALSE;
2429 delete pTable;
2431 if ((GetToken().eType == TIDENT) && (GetFontDesc() == FNT_FUNCTION))
2433 //Search for existing functions and remove extraenous keyword
2434 APPEND(rText,"func ");
2436 else if (bQuoted)
2437 APPEND(rText,"italic ");
2439 if (bQuoted)
2440 rText.Append('\"');
2444 rText.Append(GetToken().aText);
2446 if (bQuoted)
2447 rText.Append('\"');
2448 rText.Append(' ');
2451 void SmTextNode::Draw(OutputDevice &rDev, const Point& rPosition) const
2453 if (IsPhantom() || aText.Len() == 0 || aText.GetChar(0) == xub_Unicode('\0'))
2454 return;
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
2467 if (!IsDebug())
2468 return;
2470 int nRFlags = SM_RECT_CORE | SM_RECT_ITALIC | SM_RECT_LINES | SM_RECT_MID;
2471 SmRect::Draw(rDev, rPosition, nRFlags);
2472 #endif
2475 void SmTextNode::GetAccessibleText( String &rText ) const
2477 rText += aText;
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)
2492 APPEND(rText,"# ");
2494 if (i != nNumRows-1)
2495 APPEND(rText,"## ");
2497 rText.EraseTrailingChars();
2498 APPEND(rText,"} ");
2502 void SmMatrixNode::Arrange(const OutputDevice &rDev, const SmFormat &rFormat)
2504 Point aPosition,
2505 aOffset;
2506 SmNode *pNode;
2507 USHORT i, j;
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++)
2513 pColWidth[j] = 0;
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
2532 // the elements
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];
2538 long nX = 0;
2539 for (j = 0; j < nNumCols; j++)
2540 { pColLeft[j] = nX;
2541 nX += pColWidth[j] + nHorDist;
2544 Point aPos, aDelta;
2545 SmRect aLineRect;
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
2565 switch (eHorAlign)
2566 { case RHA_LEFT:
2567 aPos.X() = rNodeRect.GetLeft() + pColLeft[j];
2568 break;
2569 case RHA_CENTER:
2570 aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2571 + pColWidth[j] / 2
2572 - rNodeRect.GetItalicCenterX();
2573 break;
2574 case RHA_RIGHT:
2575 aPos.X() = rNodeRect.GetLeft() + pColLeft[j]
2576 + pColWidth[j] - rNodeRect.GetItalicWidth();
2577 break;
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);
2598 delete [] pColLeft;
2599 delete [] pColWidth;
2603 void SmMatrixNode::SetRowCol(USHORT nMatrixRows, USHORT nMatrixCols)
2605 nNumRows = nMatrixRows;
2606 nNumCols = nMatrixCols;
2610 SmNode * SmMatrixNode::GetLeftMost()
2612 return this;
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)
2624 SetText( 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();
2663 rDevNC.Pop();
2665 DBG_ASSERT(aFntSize.Width() != 0, "Sm: ");
2667 //! however the result is a bit better with 'nHeight' as initial
2668 //! font height
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());
2709 return;
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)
2724 String sStr;
2725 MathType::LookupChar(GetToken().cMathChar, sStr);
2726 rText.Append(sStr);
2729 void SmRectangleNode::CreateTextFromNode(String &rText)
2731 switch (GetToken().eType)
2733 case TUNDERLINE:
2734 APPEND(rText,"underline ");
2735 break;
2736 case TOVERLINE:
2737 APPEND(rText,"overline ");
2738 break;
2739 case TOVERSTRIKE:
2740 APPEND(rText,"overstrike ");
2741 break;
2742 default:
2743 break;
2747 void SmAttributNode::CreateTextFromNode(String &rText)
2749 SmNode *pNode;
2750 USHORT nSize = GetNumSubNodes();
2751 DBG_ASSERT(nSize == 2, "Node missing members");
2752 rText.Append('{');
2753 sal_Unicode nLast=0;
2754 if (NULL != (pNode = GetSubNode(0)))
2756 String aStr;
2757 pNode->CreateTextFromNode(aStr);
2758 if (aStr.Len() > 1)
2759 rText.Append(aStr);
2760 else
2762 nLast = aStr.GetChar(0);
2763 switch (nLast)
2765 case 0xAF:
2766 APPEND(rText,"overline ");
2767 break;
2768 case 0x2d9:
2769 APPEND(rText,"dot ");
2770 break;
2771 case 0x2dc:
2772 APPEND(rText,"widetilde ");
2773 break;
2774 case 0xA8:
2775 APPEND(rText,"ddot ");
2776 break;
2777 case 0xE082:
2778 break;
2779 case 0xE09B:
2780 APPEND(rText,"dddot ");
2781 break;
2782 default:
2783 rText.Append(nLast);
2784 break;
2789 if (nSize == 2)
2790 if (NULL != (pNode = GetSubNode(1)))
2791 pNode->CreateTextFromNode(rText);
2793 rText.EraseTrailingChars();
2795 if (nLast == 0xE082)
2796 APPEND(rText," overbrace {}");
2798 APPEND(rText,"} ");
2801 /**************************************************************************/
2804 void SmSpecialNode::Prepare(const SmFormat &rFormat, const SmDocShell &rDocShell)
2806 SmNode::Prepare(rFormat, rDocShell);
2808 const SmSym *pSym;
2809 SmModule *pp = SM_MOD1();
2811 if (NULL != (pSym = pp->GetSymSetManager().GetSymbolByName(GetToken().aText)))
2813 SetText( pSym->GetCharacter() );
2814 GetFont() = pSym->GetFace();
2816 else
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;
2933 default:
2934 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);
2968 SetWidth(nSpace);