update credits
[LibreOffice.git] / svtools / source / control / ctrlbox.cxx
blobb839b898588c82b6bebcf6f1f8f1dec03e3996ec
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <tools/stream.hxx>
21 #include <vcl/builder.hxx>
22 #include <vcl/svapp.hxx>
23 #include <vcl/field.hxx>
24 #include <vcl/helper.hxx>
25 #include <sal/macros.h>
26 #include <comphelper/processfactory.hxx>
27 #include <comphelper/string.hxx>
28 #include <unotools/charclass.hxx>
30 #include <svtools/sampletext.hxx>
31 #include <svtools/svtresid.hxx>
32 #include <svtools/svtools.hrc>
33 #include <svtools/ctrlbox.hxx>
34 #include <svtools/ctrltool.hxx>
35 #include <svtools/borderhelper.hxx>
37 #include <vcl/i18nhelp.hxx>
38 #include <vcl/fontcapabilities.hxx>
39 #include <basegfx/polygon/b2dpolygon.hxx>
40 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <rtl/bootstrap.hxx>
44 #if OSL_DEBUG_LEVEL > 1
45 #include <cstdio>
46 #endif
48 #include <stdio.h>
50 #define IMGOUTERTEXTSPACE 5
51 #define EXTRAFONTSIZE 5
52 #define GAPTOEXTRAPREVIEW 10
53 #define MAXPREVIEWWIDTH 120
54 #define MINGAPWIDTH 2
56 #define FONTNAMEBOXMRUENTRIESFILE "/user/config/fontnameboxmruentries"
58 using namespace ::com::sun::star;
60 // ========================================================================
61 // ColorListBox
62 // ========================================================================
64 // --------------------
65 // - ImplColorListData -
66 // --------------------
68 class ImplColorListData
70 public:
71 Color aColor;
72 sal_Bool bColor;
74 ImplColorListData() : aColor( COL_BLACK ) { bColor = sal_False; }
75 ImplColorListData( const Color& rColor ) : aColor( rColor ) { bColor = sal_True; }
78 // -----------------------------------------------------------------------
80 void ColorListBox::ImplInit()
82 pColorList = new ImpColorList();
84 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
85 aImageSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
86 EnableUserDraw( sal_True );
87 SetUserItemSize( aImageSize );
90 // -----------------------------------------------------------------------
92 void ColorListBox::ImplDestroyColorEntries()
94 for ( size_t n = pColorList->size(); n; )
95 delete (*pColorList)[ --n ];
96 pColorList->clear();
99 // -----------------------------------------------------------------------
101 ColorListBox::ColorListBox( Window* pParent, WinBits nWinStyle ) :
102 ListBox( pParent, nWinStyle )
104 ImplInit();
105 SetEdgeBlending(true);
108 // -----------------------------------------------------------------------
110 ColorListBox::ColorListBox( Window* pParent, const ResId& rResId ) :
111 ListBox( pParent, rResId )
113 ImplInit();
114 SetEdgeBlending(true);
117 namespace
119 bool extractDropdown(VclBuilder::stringmap &rMap)
121 bool bDropdown = true;
122 VclBuilder::stringmap::iterator aFind = rMap.find(OString(RTL_CONSTASCII_STRINGPARAM("dropdown")));
123 if (aFind != rMap.end())
125 bDropdown = toBool(aFind->second);
126 rMap.erase(aFind);
128 return bDropdown;
132 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeColorListBox(Window *pParent, VclBuilder::stringmap &rMap)
134 bool bDropdown = extractDropdown(rMap);
135 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
136 if (bDropdown)
137 nWinBits |= WB_DROPDOWN;
138 ColorListBox *pListBox = new ColorListBox(pParent, nWinBits);
139 if (bDropdown)
140 pListBox->EnableAutoSize(true);
141 return pListBox;
144 // -----------------------------------------------------------------------
146 ColorListBox::~ColorListBox()
148 ImplDestroyColorEntries();
149 delete pColorList;
152 // -----------------------------------------------------------------------
154 sal_uInt16 ColorListBox::InsertEntry( const XubString& rStr, sal_uInt16 nPos )
156 nPos = ListBox::InsertEntry( rStr, nPos );
157 if ( nPos != LISTBOX_ERROR )
159 ImplColorListData* pData = new ImplColorListData;
160 if ( nPos < pColorList->size() )
162 ImpColorList::iterator it = pColorList->begin();
163 ::std::advance( it, nPos );
164 pColorList->insert( it, pData );
166 else
168 pColorList->push_back( pData );
169 nPos = pColorList->size() - 1;
172 return nPos;
175 // -----------------------------------------------------------------------
177 sal_uInt16 ColorListBox::InsertEntry( const Color& rColor, const XubString& rStr,
178 sal_uInt16 nPos )
180 nPos = ListBox::InsertEntry( rStr, nPos );
181 if ( nPos != LISTBOX_ERROR )
183 ImplColorListData* pData = new ImplColorListData( rColor );
184 if ( nPos < pColorList->size() )
186 ImpColorList::iterator it = pColorList->begin();
187 ::std::advance( it, nPos );
188 pColorList->insert( it, pData );
190 else
192 pColorList->push_back( pData );
193 nPos = pColorList->size() - 1;
196 return nPos;
199 // -----------------------------------------------------------------------
201 void ColorListBox::InsertAutomaticEntryColor(const Color &rColor)
203 // insert the "Automatic"-entry always on the first position
204 InsertEntry( rColor, SVT_RESSTR(STR_SVT_AUTOMATIC_COLOR), 0 );
207 // -----------------------------------------------------------------------
209 void ColorListBox::RemoveEntry( sal_uInt16 nPos )
211 ListBox::RemoveEntry( nPos );
212 if ( nPos < pColorList->size() )
214 ImpColorList::iterator it = pColorList->begin();
215 ::std::advance( it, nPos );
216 delete *it;
217 pColorList->erase( it );
221 // -----------------------------------------------------------------------
223 void ColorListBox::Clear()
225 ImplDestroyColorEntries();
226 ListBox::Clear();
229 // -----------------------------------------------------------------------
231 void ColorListBox::CopyEntries( const ColorListBox& rBox )
233 // Liste leeren
234 ImplDestroyColorEntries();
236 // Daten kopieren
237 size_t nCount = rBox.pColorList->size();
238 for ( size_t n = 0; n < nCount; n++ )
240 ImplColorListData* pData = (*rBox.pColorList)[ n ];
241 sal_uInt16 nPos = InsertEntry( rBox.GetEntry( n ), LISTBOX_APPEND );
242 if ( nPos != LISTBOX_ERROR )
244 if ( nPos < pColorList->size() )
246 ImpColorList::iterator it = pColorList->begin();
247 ::std::advance( it, nPos );
248 pColorList->insert( it, new ImplColorListData( *pData ) );
250 else
252 pColorList->push_back( new ImplColorListData( *pData ) );
258 // -----------------------------------------------------------------------
260 sal_uInt16 ColorListBox::GetEntryPos( const Color& rColor ) const
262 for( sal_uInt16 n = (sal_uInt16) pColorList->size(); n; )
264 ImplColorListData* pData = (*pColorList)[ --n ];
265 if ( pData->bColor && ( pData->aColor == rColor ) )
266 return n;
268 return LISTBOX_ENTRY_NOTFOUND;
271 // -----------------------------------------------------------------------
273 Color ColorListBox::GetEntryColor( sal_uInt16 nPos ) const
275 Color aColor;
276 ImplColorListData* pData = ( nPos < pColorList->size() ) ? (*pColorList)[ nPos ] : NULL;
277 if ( pData && pData->bColor )
278 aColor = pData->aColor;
279 return aColor;
282 // -----------------------------------------------------------------------
284 void ColorListBox::UserDraw( const UserDrawEvent& rUDEvt )
286 size_t nPos = rUDEvt.GetItemId();
287 ImplColorListData* pData = ( nPos < pColorList->size() ) ? (*pColorList)[ nPos ] : NULL;
288 if ( pData )
290 if ( pData->bColor )
292 Point aPos( rUDEvt.GetRect().TopLeft() );
294 aPos.X() += 2;
295 aPos.Y() += ( rUDEvt.GetRect().GetHeight() - aImageSize.Height() ) / 2;
297 const Rectangle aRect(aPos, aImageSize);
299 rUDEvt.GetDevice()->Push();
300 rUDEvt.GetDevice()->SetFillColor( pData->aColor );
301 rUDEvt.GetDevice()->SetLineColor( rUDEvt.GetDevice()->GetTextColor() );
302 rUDEvt.GetDevice()->DrawRect(aRect);
303 rUDEvt.GetDevice()->Pop();
305 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
306 const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
308 if(nEdgeBlendingPercent)
310 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
311 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
312 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
313 const BitmapEx aBlendFrame(createBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight));
315 if(!aBlendFrame.IsEmpty())
317 rUDEvt.GetDevice()->DrawBitmapEx(aRect.TopLeft(), aBlendFrame);
321 ListBox::DrawEntry( rUDEvt, sal_False, sal_True, sal_False );
323 else
324 ListBox::DrawEntry( rUDEvt, sal_False, sal_True, sal_True );
326 else
327 ListBox::DrawEntry( rUDEvt, sal_True, sal_True, sal_False );
330 // =======================================================================
331 // LineListBox
332 // =======================================================================
334 BorderWidthImpl::BorderWidthImpl( sal_uInt16 nFlags, double nRate1, double nRate2, double nRateGap ):
335 m_nFlags( nFlags ),
336 m_nRate1( nRate1 ),
337 m_nRate2( nRate2 ),
338 m_nRateGap( nRateGap )
342 BorderWidthImpl& BorderWidthImpl::operator= ( const BorderWidthImpl& r )
344 m_nFlags = r.m_nFlags;
345 m_nRate1 = r.m_nRate1;
346 m_nRate2 = r.m_nRate2;
347 m_nRateGap = r.m_nRateGap;
348 return *this;
351 bool BorderWidthImpl::operator== ( const BorderWidthImpl& r ) const
353 return ( m_nFlags == r.m_nFlags ) &&
354 ( m_nRate1 == r.m_nRate1 ) &&
355 ( m_nRate2 == r.m_nRate2 ) &&
356 ( m_nRateGap == r.m_nRateGap );
359 long BorderWidthImpl::GetLine1( long nWidth ) const
361 long result = static_cast<long>(m_nRate1);
362 if ( ( m_nFlags & CHANGE_LINE1 ) > 0 )
364 long const nConstant2 = (m_nFlags & CHANGE_LINE2) ? 0 : m_nRate2;
365 long const nConstantD = (m_nFlags & CHANGE_DIST ) ? 0 : m_nRateGap;
366 result = std::max<long>(0,
367 static_cast<long>((m_nRate1 * nWidth) + 0.5)
368 - (nConstant2 + nConstantD));
369 if (result == 0 && m_nRate1 > 0.0 && nWidth > 0)
370 { // fdo#51777: hack to essentially treat 1 twip DOUBLE border
371 result = 1; // as 1 twip SINGLE border
374 return result;
377 long BorderWidthImpl::GetLine2( long nWidth ) const
379 long result = static_cast<long>(m_nRate2);
380 if ( ( m_nFlags & CHANGE_LINE2 ) > 0 )
382 long const nConstant1 = (m_nFlags & CHANGE_LINE1) ? 0 : m_nRate1;
383 long const nConstantD = (m_nFlags & CHANGE_DIST ) ? 0 : m_nRateGap;
384 result = std::max<long>(0,
385 static_cast<long>((m_nRate2 * nWidth) + 0.5)
386 - (nConstant1 + nConstantD));
388 return result;
391 long BorderWidthImpl::GetGap( long nWidth ) const
393 long result = static_cast<long>(m_nRateGap);
394 if ( ( m_nFlags & CHANGE_DIST ) > 0 )
396 long const nConstant1 = (m_nFlags & CHANGE_LINE1) ? 0 : m_nRate1;
397 long const nConstant2 = (m_nFlags & CHANGE_LINE2) ? 0 : m_nRate2;
398 result = std::max<long>(0,
399 static_cast<long>((m_nRateGap * nWidth) + 0.5)
400 - (nConstant1 + nConstant2));
403 // Avoid having too small distances (less than 0.1pt)
404 if ( result < MINGAPWIDTH && m_nRate1 > 0 && m_nRate2 > 0 )
405 result = MINGAPWIDTH;
407 return result;
410 static double lcl_getGuessedWidth( long nTested, double nRate, bool nChanging )
412 double nWidth = -1.0;
413 if ( nChanging )
414 nWidth = double( nTested ) / nRate;
415 else
417 if ( double( nTested ) == nRate )
418 nWidth = nRate;
421 return nWidth;
424 long BorderWidthImpl::GuessWidth( long nLine1, long nLine2, long nGap )
426 std::vector< double > aToCompare;
427 bool bInvalid = false;
429 bool bLine1Change = ( m_nFlags & CHANGE_LINE1 ) > 0;
430 double nWidth1 = lcl_getGuessedWidth( nLine1, m_nRate1, bLine1Change );
431 if ( bLine1Change )
432 aToCompare.push_back( nWidth1 );
433 else if ( !bLine1Change && nWidth1 < 0 )
434 bInvalid = true;
436 bool bLine2Change = ( m_nFlags & CHANGE_LINE2 ) > 0;
437 double nWidth2 = lcl_getGuessedWidth( nLine2, m_nRate2, bLine2Change );
438 if ( bLine2Change )
439 aToCompare.push_back( nWidth2 );
440 else if ( !bLine2Change && nWidth2 < 0 )
441 bInvalid = true;
443 bool bGapChange = ( m_nFlags & CHANGE_DIST ) > 0;
444 double nWidthGap = lcl_getGuessedWidth( nGap, m_nRateGap, bGapChange );
445 if ( bGapChange && nGap > MINGAPWIDTH )
446 aToCompare.push_back( nWidthGap );
447 else if ( !bGapChange && nWidthGap < 0 )
448 bInvalid = true;
450 // non-constant line width factors must sum to 1
451 assert((((bLine1Change) ? m_nRate1 : 0) +
452 ((bLine2Change) ? m_nRate2 : 0) +
453 ((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001 );
455 double nWidth = 0.0;
456 if ( (!bInvalid) && (!aToCompare.empty()) )
458 nWidth = *aToCompare.begin();
459 std::vector< double >::iterator pIt = aToCompare.begin();
460 while ( pIt != aToCompare.end() && !bInvalid )
462 bInvalid = ( nWidth != *pIt );
463 ++pIt;
465 nWidth = (bInvalid) ? 0.0 : nLine1 + nLine2 + nGap;
468 return nWidth;
471 /** Utility class storing the border line width, style and colors. The widths
472 are defined in Twips.
474 class ImpLineListData
476 private:
477 BorderWidthImpl m_aWidthImpl;
479 Color ( *m_pColor1Fn )( Color );
480 Color ( *m_pColor2Fn )( Color );
481 Color ( *m_pColorDistFn )( Color, Color );
483 long m_nMinWidth;
484 sal_uInt16 m_nStyle;
486 public:
487 ImpLineListData( BorderWidthImpl aWidthImpl, sal_uInt16 nStyle,
488 long nMinWidth=0, Color ( *pColor1Fn ) ( Color ) = &sameColor,
489 Color ( *pColor2Fn ) ( Color ) = &sameColor, Color ( *pColorDistFn ) ( Color, Color ) = &sameDistColor );
491 /** Returns the computed width of the line 1 in twips. */
492 long GetLine1ForWidth( long nWidth ) { return m_aWidthImpl.GetLine1( nWidth ); }
494 /** Returns the computed width of the line 2 in twips. */
495 long GetLine2ForWidth( long nWidth ) { return m_aWidthImpl.GetLine2( nWidth ); }
497 /** Returns the computed width of the gap in twips. */
498 long GetDistForWidth( long nWidth ) { return m_aWidthImpl.GetGap( nWidth ); }
500 Color GetColorLine1( const Color& aMain );
501 Color GetColorLine2( const Color& aMain );
502 Color GetColorDist( const Color& aMain, const Color& rDefault );
504 /** Returns the minimum width in twips */
505 long GetMinWidth( );
506 sal_uInt16 GetStyle( );
509 ImpLineListData::ImpLineListData( BorderWidthImpl aWidthImpl,
510 sal_uInt16 nStyle, long nMinWidth, Color ( *pColor1Fn )( Color ),
511 Color ( *pColor2Fn )( Color ), Color ( *pColorDistFn )( Color, Color ) ) :
512 m_aWidthImpl( aWidthImpl ),
513 m_pColor1Fn( pColor1Fn ),
514 m_pColor2Fn( pColor2Fn ),
515 m_pColorDistFn( pColorDistFn ),
516 m_nMinWidth( nMinWidth ),
517 m_nStyle( nStyle )
521 long ImpLineListData::GetMinWidth( )
523 return m_nMinWidth;
526 Color ImpLineListData::GetColorLine1( const Color& rMain )
528 return ( *m_pColor1Fn )( rMain );
531 Color ImpLineListData::GetColorLine2( const Color& rMain )
533 return ( *m_pColor2Fn )( rMain );
536 Color ImpLineListData::GetColorDist( const Color& rMain, const Color& rDefault )
538 return ( *m_pColorDistFn )( rMain, rDefault );
541 sal_uInt16 LineListBox::GetSelectEntryStyle( sal_uInt16 nSelIndex ) const
543 sal_uInt16 nStyle = STYLE_SOLID;
544 sal_uInt16 nPos = GetSelectEntryPos( nSelIndex );
545 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
547 if ( m_sNone.Len( ) > 0 )
548 nPos--;
549 nStyle = GetEntryStyle( nPos );
552 return nStyle;
555 sal_uInt16 ImpLineListData::GetStyle( )
557 return m_nStyle;
560 // -----------------------------------------------------------------------
562 void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, long nWidth, sal_uInt16 nDashing )
564 sal_uInt16 nOldAA = rDev.GetAntialiasing();
565 rDev.SetAntialiasing( nOldAA & ~ANTIALIASING_ENABLE_B2DDRAW );
567 basegfx::B2DPolyPolygon aPolygons = svtools::ApplyLineDashing( rPolygon, nDashing, rDev.GetMapMode().GetMapUnit() );
568 for ( sal_uInt32 i = 0; i < aPolygons.count( ); i++ )
570 basegfx::B2DPolygon aDash = aPolygons.getB2DPolygon( i );
571 basegfx::B2DPoint aStart = aDash.getB2DPoint( 0 );
572 basegfx::B2DPoint aEnd = aDash.getB2DPoint( aDash.count() - 1 );
574 basegfx::B2DVector aVector( aEnd - aStart );
575 aVector.normalize( );
576 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
578 // Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line
579 long nPix = rDev.PixelToLogic( Size( 0, 1 ) ).Height();
580 if ( rDev.GetMapMode().GetMapUnit() == MAP_PIXEL && nWidth == nPix )
581 nWidth = 0;
583 const basegfx::B2DVector aWidthOffset( double( nWidth ) / 2 * aPerpendicular);
584 basegfx::B2DPolygon aDashPolygon;
585 aDashPolygon.append( aStart + aWidthOffset );
586 aDashPolygon.append( aEnd + aWidthOffset );
587 aDashPolygon.append( aEnd - aWidthOffset );
588 aDashPolygon.append( aStart - aWidthOffset );
589 aDashPolygon.setClosed( true );
591 rDev.DrawPolygon( aDashPolygon );
594 rDev.SetAntialiasing( nOldAA );
597 namespace svtools
599 std::vector < double > GetDashing( sal_uInt16 nDashing, MapUnit eUnit )
601 ::std::vector < double >aPattern;
602 switch ( nDashing )
604 case STYLE_DOTTED:
605 if ( eUnit == MAP_TWIP )
607 aPattern.push_back( 30.0 );
608 aPattern.push_back( 110.0 );
610 else if ( eUnit == MAP_100TH_MM )
612 aPattern.push_back( 50 );
613 aPattern.push_back( 200 );
615 else if ( eUnit == MAP_PIXEL )
617 aPattern.push_back( 1.0 );
618 aPattern.push_back( 3.0 );
620 break;
621 case STYLE_DASHED:
622 if ( eUnit == MAP_TWIP )
624 aPattern.push_back( 110 );
625 aPattern.push_back( 110 );
627 else if ( eUnit == MAP_100TH_MM )
629 aPattern.push_back( 200 );
630 aPattern.push_back( 200 );
632 else if ( eUnit == MAP_PIXEL )
634 aPattern.push_back( 10 );
635 aPattern.push_back( 20 );
637 break;
638 case STYLE_FINE_DASHED:
639 if ( eUnit == MAP_PIXEL )
641 aPattern.push_back( 4 );
642 aPattern.push_back( 1 );
644 break;
645 default:
646 break;
649 return aPattern;
652 basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, MapUnit eUnit )
654 std::vector< double > aPattern = GetDashing( nDashing, eUnit );
655 basegfx::B2DPolyPolygon aPolygons;
656 if ( ! aPattern.empty() )
657 basegfx::tools::applyLineDashing( rPolygon, aPattern, &aPolygons );
658 else
659 aPolygons.append( rPolygon );
661 return aPolygons;
664 basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, MapUnit eUnit, double fScale )
666 std::vector< double > aPattern = GetDashing( nDashing, eUnit );
667 std::vector< double >::iterator i = aPattern.begin();
668 while( i != aPattern.end() ) {
669 (*i) *= fScale;
670 ++i;
673 basegfx::B2DPolyPolygon aPolygons;
674 if ( ! aPattern.empty() )
675 basegfx::tools::applyLineDashing( rPolygon, aPattern, &aPolygons );
676 else
677 aPolygons.append( rPolygon );
679 return aPolygons;
682 void DrawLine( OutputDevice& rDev, const Point& rP1, const Point& rP2,
683 sal_uInt32 nWidth, sal_uInt16 nDashing )
685 DrawLine( rDev, basegfx::B2DPoint( rP1.X(), rP1.Y() ),
686 basegfx::B2DPoint( rP2.X(), rP2.Y( ) ), nWidth, nDashing );
689 void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rP1, const basegfx::B2DPoint& rP2,
690 sal_uInt32 nWidth, sal_uInt16 nDashing )
692 basegfx::B2DPolygon aPolygon;
693 aPolygon.append( rP1 );
694 aPolygon.append( rP2 );
695 lclDrawPolygon( rDev, aPolygon, nWidth, nDashing );
699 void LineListBox::ImpGetLine( long nLine1, long nLine2, long nDistance,
700 Color aColor1, Color aColor2, Color aColorDist,
701 sal_uInt16 nStyle, Bitmap& rBmp )
703 //TODO, rather than including the " " text to force
704 //the line height, better would be do drop
705 //this calculation and draw a bitmap of height
706 //equal to normal text line and center the
707 //line within that
708 long nMinWidth = GetTextWidth(OUString("----------"));
709 Size aSize = CalcSubEditSize();
710 aSize.Width() = std::max(nMinWidth, aSize.Width());
711 aSize.Width() -= aTxtSize.Width();
712 aSize.Width() -= 6;
713 aSize.Height() = aTxtSize.Height();
715 // SourceUnit nach Twips
716 if ( eSourceUnit == FUNIT_POINT )
718 nLine1 /= 5;
719 nLine2 /= 5;
720 nDistance /= 5;
723 // Linien malen
724 aSize = aVirDev.PixelToLogic( aSize );
725 long nPix = aVirDev.PixelToLogic( Size( 0, 1 ) ).Height();
726 sal_uInt32 n1 = nLine1;
727 sal_uInt32 n2 = nLine2;
728 long nDist = nDistance;
729 n1 += nPix-1;
730 n1 -= n1%nPix;
731 if ( n2 )
733 nDist += nPix-1;
734 nDist -= nDist%nPix;
735 n2 += nPix-1;
736 n2 -= n2%nPix;
738 long nVirHeight = n1+nDist+n2;
739 if ( nVirHeight > aSize.Height() )
740 aSize.Height() = nVirHeight;
741 // negative Breiten muss und darf man nicht painten
742 if ( aSize.Width() > 0 )
744 Size aVirSize = aVirDev.LogicToPixel( aSize );
745 if ( aVirDev.GetOutputSizePixel() != aVirSize )
746 aVirDev.SetOutputSizePixel( aVirSize );
747 aVirDev.SetFillColor( aColorDist );
748 aVirDev.DrawRect( Rectangle( Point(), aSize ) );
750 aVirDev.SetFillColor( aColor1 );
752 double y1 = double( n1 ) / 2;
753 svtools::DrawLine( aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
755 if ( n2 )
757 double y2 = n1 + nDist + double( n2 ) / 2;
758 aVirDev.SetFillColor( aColor2 );
759 svtools::DrawLine( aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, STYLE_SOLID );
761 rBmp = aVirDev.GetBitmap( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
765 // -----------------------------------------------------------------------
767 void LineListBox::ImplInit()
769 aTxtSize.Width() = GetTextWidth( OUString( " " ) );
770 aTxtSize.Height() = GetTextHeight();
771 pLineList = new ImpLineList();
772 eUnit = FUNIT_POINT;
773 eSourceUnit = FUNIT_POINT;
775 aVirDev.SetLineColor();
776 aVirDev.SetMapMode( MapMode( MAP_TWIP ) );
778 UpdatePaintLineColor();
781 // -----------------------------------------------------------------------
783 LineListBox::LineListBox( Window* pParent, WinBits nWinStyle ) :
784 ListBox( pParent, nWinStyle ),
785 m_nWidth( 5 ),
786 m_sNone( ),
787 aColor( COL_BLACK ),
788 maPaintCol( COL_BLACK )
790 ImplInit();
793 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeLineListBox(Window *pParent, VclBuilder::stringmap &rMap)
795 bool bDropdown = extractDropdown(rMap);
796 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
797 if (bDropdown)
798 nWinBits |= WB_DROPDOWN;
799 LineListBox *pListBox = new LineListBox(pParent, nWinBits);
800 if (bDropdown)
801 pListBox->EnableAutoSize(true);
802 return pListBox;
805 // -----------------------------------------------------------------------
807 LineListBox::LineListBox( Window* pParent, const ResId& rResId ) :
808 ListBox( pParent, rResId ),
809 m_nWidth( 5 ),
810 m_sNone( ),
811 aColor( COL_BLACK ),
812 maPaintCol( COL_BLACK )
814 ImplInit();
817 // -----------------------------------------------------------------------
819 LineListBox::~LineListBox()
821 for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
822 if ( (*pLineList)[ i ] ) {
823 delete (*pLineList)[ i ];
826 pLineList->clear();
827 delete pLineList;
830 sal_uInt16 LineListBox::GetStylePos( sal_uInt16 nListPos, long nWidth )
832 sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;
833 if ( m_sNone.Len( ) > 0 )
834 nListPos--;
836 sal_uInt16 i = 0;
837 sal_uInt16 n = 0;
838 sal_uInt16 nCount = pLineList->size();
839 while ( nPos == LISTBOX_ENTRY_NOTFOUND && i < nCount )
841 ImpLineListData* pData = (*pLineList)[ i ];
842 if ( pData && pData->GetMinWidth() <= nWidth )
844 if ( nListPos == n )
845 nPos = i;
846 n++;
848 i++;
851 return nPos;
855 void LineListBox::SelectEntry( sal_uInt16 nStyle, sal_Bool bSelect )
857 sal_uInt16 nPos = GetEntryPos( nStyle );
858 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
859 ListBox::SelectEntryPos( nPos, bSelect );
862 // -----------------------------------------------------------------------
864 sal_uInt16 LineListBox::InsertEntry( const XubString& rStr, sal_uInt16 nPos )
866 nPos = ListBox::InsertEntry( rStr, nPos );
867 if ( nPos != LISTBOX_ERROR ) {
868 if ( nPos < pLineList->size() ) {
869 ImpLineList::iterator it = pLineList->begin();
870 ::std::advance( it, nPos );
871 pLineList->insert( it, reinterpret_cast<ImpLineListData *>(NULL) );
872 } else {
873 pLineList->push_back( NULL );
876 return nPos;
879 // -----------------------------------------------------------------------
881 void LineListBox::InsertEntry(
882 BorderWidthImpl aWidthImpl,
883 sal_uInt16 nStyle, long nMinWidth,
884 Color ( *pColor1Fn )( Color ), Color ( *pColor2Fn )( Color ),
885 Color ( *pColorDistFn )( Color, Color ) )
887 ImpLineListData* pData = new ImpLineListData(
888 aWidthImpl, nStyle, nMinWidth,
889 pColor1Fn, pColor2Fn, pColorDistFn );
890 pLineList->push_back( pData );
893 // -----------------------------------------------------------------------
895 void LineListBox::RemoveEntry( sal_uInt16 nPos )
897 ListBox::RemoveEntry( nPos );
899 if ( nPos < pLineList->size() ) {
900 ImpLineList::iterator it = pLineList->begin();
901 ::std::advance( it, nPos );
902 if ( *it ) delete *it;
903 pLineList->erase( it );
907 // -----------------------------------------------------------------------
909 void LineListBox::Clear()
911 for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
912 if ( (*pLineList)[ i ] ) {
913 delete (*pLineList)[ i ];
916 pLineList->clear();
918 ListBox::Clear();
921 // -----------------------------------------------------------------------
923 sal_uInt16 LineListBox::GetEntryPos( sal_uInt16 nStyle ) const
925 for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
926 ImpLineListData* pData = (*pLineList)[ i ];
927 if ( pData )
929 if ( GetEntryStyle( i ) == nStyle )
931 size_t nPos = i;
932 if ( m_sNone.Len() > 0 )
933 nPos ++;
934 return (sal_uInt16)nPos;
938 return LISTBOX_ENTRY_NOTFOUND;
941 // -----------------------------------------------------------------------
943 sal_uInt16 LineListBox::GetEntryStyle( sal_uInt16 nPos ) const
945 ImpLineListData* pData = (nPos < pLineList->size()) ? (*pLineList)[ nPos ] : NULL;
946 return ( pData ) ? pData->GetStyle() : STYLE_NONE;
949 // -----------------------------------------------------------------------
951 sal_Bool LineListBox::UpdatePaintLineColor( void )
953 sal_Bool bRet = sal_True;
954 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
955 Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor );
957 bRet = aNewCol != maPaintCol;
959 if( bRet )
960 maPaintCol = aNewCol;
962 return bRet;
965 void LineListBox::UpdateEntries( long nOldWidth )
967 SetUpdateMode( sal_False );
969 UpdatePaintLineColor( );
971 sal_uInt16 nSelEntry = GetSelectEntryPos();
972 sal_uInt16 nTypePos = GetStylePos( nSelEntry, nOldWidth );
974 // Remove the old entries
975 while ( GetEntryCount( ) > 0 )
976 ListBox::RemoveEntry( 0 );
978 // Add the new entries based on the defined width
979 if ( m_sNone.Len( ) > 0 )
980 ListBox::InsertEntry( m_sNone, LISTBOX_APPEND );
982 sal_uInt16 n = 0;
983 sal_uInt16 nCount = pLineList->size( );
984 while ( n < nCount )
986 ImpLineListData* pData = (*pLineList)[ n ];
987 if ( pData && pData->GetMinWidth() <= m_nWidth )
989 Bitmap aBmp;
990 ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
991 pData->GetLine2ForWidth( m_nWidth ),
992 pData->GetDistForWidth( m_nWidth ),
993 GetColorLine1( GetEntryCount( ) ),
994 GetColorLine2( GetEntryCount( ) ),
995 GetColorDist( GetEntryCount( ) ),
996 pData->GetStyle(), aBmp );
997 ListBox::InsertEntry( OUString( " " ), aBmp, LISTBOX_APPEND );
998 if ( n == nTypePos )
999 SelectEntryPos( GetEntryCount() - 1 );
1001 else if ( n == nTypePos )
1002 SetNoSelection();
1003 n++;
1006 SetUpdateMode( sal_True );
1007 Invalidate();
1010 // -----------------------------------------------------------------------
1012 Color LineListBox::GetColorLine1( sal_uInt16 nPos )
1014 Color rResult = GetPaintColor( );
1016 sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
1017 ImpLineListData* pData = (*pLineList)[ nStyle ];
1018 if ( pData )
1019 rResult = pData->GetColorLine1( GetColor( ) );
1021 return rResult;
1024 Color LineListBox::GetColorLine2( sal_uInt16 nPos )
1026 Color rResult = GetPaintColor( );
1028 sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
1029 ImpLineListData* pData = (*pLineList)[ nStyle ];
1030 if ( pData )
1031 rResult = pData->GetColorLine2( GetColor( ) );
1033 return rResult;
1036 Color LineListBox::GetColorDist( sal_uInt16 nPos )
1038 Color rResult = GetSettings().GetStyleSettings().GetFieldColor();
1040 sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
1041 ImpLineListData* pData = (*pLineList)[ nStyle ];
1042 if ( pData )
1043 rResult = pData->GetColorDist( GetColor( ), rResult );
1045 return rResult;
1048 // -----------------------------------------------------------------------
1050 void LineListBox::DataChanged( const DataChangedEvent& rDCEvt )
1052 ListBox::DataChanged( rDCEvt );
1054 if( ( rDCEvt.GetType() == DATACHANGED_SETTINGS ) && ( rDCEvt.GetFlags() & SETTINGS_STYLE ) )
1055 UpdateEntries( m_nWidth );
1059 // ===================================================================
1060 // FontNameBox
1061 // ===================================================================
1063 FontNameBox::FontNameBox( Window* pParent, WinBits nWinStyle ) :
1064 ComboBox( pParent, nWinStyle )
1066 mpFontList = NULL;
1067 mbWYSIWYG = sal_False;
1068 InitFontMRUEntriesFile();
1071 // -------------------------------------------------------------------
1073 FontNameBox::FontNameBox( Window* pParent, const ResId& rResId ) :
1074 ComboBox( pParent, rResId )
1076 mpFontList = NULL;
1077 mbWYSIWYG = sal_False;
1078 InitFontMRUEntriesFile();
1081 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeFontNameBox(Window *pParent, VclBuilder::stringmap &rMap)
1083 bool bDropdown = extractDropdown(rMap);
1084 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
1085 if (bDropdown)
1086 nWinBits |= WB_DROPDOWN;
1087 FontNameBox *pListBox = new FontNameBox(pParent, nWinBits);
1088 if (bDropdown)
1089 pListBox->EnableAutoSize(true);
1090 return pListBox;
1093 // -------------------------------------------------------------------
1095 FontNameBox::~FontNameBox()
1097 SaveMRUEntries (maFontMRUEntriesFile);
1098 ImplDestroyFontList();
1101 // -------------------------------------------------------------------
1103 void FontNameBox::SaveMRUEntries( const String& aFontMRUEntriesFile, sal_Unicode cSep ) const
1105 OString aEntries(OUStringToOString(GetMRUEntries(cSep),
1106 RTL_TEXTENCODING_UTF8));
1108 if (aEntries.isEmpty() || !aFontMRUEntriesFile.Len())
1109 return;
1111 SvFileStream aStream;
1112 aStream.Open( aFontMRUEntriesFile, STREAM_WRITE | STREAM_TRUNC );
1113 if( ! (aStream.IsOpen() && aStream.IsWritable()) )
1115 #if OSL_DEBUG_LEVEL > 1
1116 fprintf( stderr, "FontNameBox::SaveMRUEntries: opening mru entries file %s failed\n", OUStringToOString(aFontMRUEntriesFile, RTL_TEXTENCODING_UTF8 ).getStr() );
1117 #endif
1118 return;
1121 aStream.SetLineDelimiter( LINEEND_LF );
1122 aStream.WriteLine( aEntries );
1123 aStream.WriteLine( OString() );
1126 // -------------------------------------------------------------------
1128 void FontNameBox::LoadMRUEntries( const String& aFontMRUEntriesFile, sal_Unicode cSep )
1130 if( ! aFontMRUEntriesFile.Len() )
1131 return;
1133 SvFileStream aStream( aFontMRUEntriesFile, STREAM_READ );
1134 if( ! aStream.IsOpen() )
1136 #if OSL_DEBUG_LEVEL > 1
1137 fprintf( stderr, "FontNameBox::LoadMRUEntries: opening mru entries file %s failed\n", OUStringToOString(aFontMRUEntriesFile, RTL_TEXTENCODING_UTF8).getStr() );
1138 #endif
1139 return;
1142 OString aLine;
1143 aStream.ReadLine( aLine );
1144 OUString aEntries = OStringToOUString(aLine,
1145 RTL_TEXTENCODING_UTF8);
1146 SetMRUEntries( aEntries, cSep );
1149 // ------------------------------------------------------------------
1151 void FontNameBox::InitFontMRUEntriesFile()
1153 OUString sUserConfigDir("${$BRAND_BASE_DIR/program/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}");
1154 rtl::Bootstrap::expandMacros(sUserConfigDir);
1156 maFontMRUEntriesFile = sUserConfigDir;
1157 if( maFontMRUEntriesFile.Len() )
1159 maFontMRUEntriesFile.AppendAscii( FONTNAMEBOXMRUENTRIESFILE );
1163 // -------------------------------------------------------------------
1165 void FontNameBox::ImplDestroyFontList()
1167 delete mpFontList;
1170 // -------------------------------------------------------------------
1172 void FontNameBox::Fill( const FontList* pList )
1174 // store old text and clear box
1175 XubString aOldText = GetText();
1176 XubString rEntries = GetMRUEntries();
1177 sal_Bool bLoadFromFile = ! rEntries.Len();
1178 Clear();
1180 ImplDestroyFontList();
1181 mpFontList = new ImplFontList;
1183 // insert fonts
1184 sal_uInt16 nFontCount = pList->GetFontNameCount();
1185 for ( sal_uInt16 i = 0; i < nFontCount; i++ )
1187 const FontInfo& rFontInfo = pList->GetFontName( i );
1188 sal_uLong nIndex = InsertEntry( rFontInfo.GetName() );
1189 if ( nIndex != LISTBOX_ERROR )
1191 if ( nIndex < mpFontList->size() ) {
1192 ImplFontList::iterator it = mpFontList->begin();
1193 ::std::advance( it, nIndex );
1194 mpFontList->insert( it, rFontInfo );
1195 } else {
1196 mpFontList->push_back( rFontInfo );
1201 if ( bLoadFromFile )
1202 LoadMRUEntries (maFontMRUEntriesFile);
1203 else
1204 SetMRUEntries( rEntries );
1206 ImplCalcUserItemSize();
1208 // restore text
1209 if ( aOldText.Len() )
1210 SetText( aOldText );
1213 // -------------------------------------------------------------------
1215 void FontNameBox::EnableWYSIWYG( sal_Bool bEnable )
1217 if ( bEnable != mbWYSIWYG )
1219 mbWYSIWYG = bEnable;
1220 EnableUserDraw( mbWYSIWYG );
1221 ImplCalcUserItemSize();
1225 // -------------------------------------------------------------------
1227 void FontNameBox::ImplCalcUserItemSize()
1229 Size aUserItemSz;
1230 if ( mbWYSIWYG && mpFontList )
1232 aUserItemSz = Size(MAXPREVIEWWIDTH, GetTextHeight() );
1233 aUserItemSz.Height() *= 16;
1234 aUserItemSz.Height() /= 10;
1236 SetUserItemSize( aUserItemSz );
1239 namespace
1241 long shrinkFontToFit(OUString &rSampleText, long nH, Font &rFont, OutputDevice &rDevice, Rectangle &rTextRect)
1243 long nWidth = 0;
1245 Size aSize( rFont.GetSize() );
1247 //Make sure it fits in the available height
1248 while (aSize.Height() > 0)
1250 if (!rDevice.GetTextBoundRect(rTextRect, rSampleText, 0, 0))
1251 break;
1252 if (rTextRect.GetHeight() <= nH)
1254 nWidth = rTextRect.GetWidth();
1255 break;
1258 aSize.Height() -= EXTRAFONTSIZE;
1259 rFont.SetSize(aSize);
1260 rDevice.SetFont(rFont);
1263 return nWidth;
1267 // -------------------------------------------------------------------
1269 void FontNameBox::UserDraw( const UserDrawEvent& rUDEvt )
1271 assert( mpFontList );
1273 FontInfo& rInfo = (*mpFontList)[ rUDEvt.GetItemId() ];
1274 Point aTopLeft = rUDEvt.GetRect().TopLeft();
1275 long nX = aTopLeft.X();
1276 long nH = rUDEvt.GetRect().GetHeight();
1278 if ( mbWYSIWYG )
1280 nX += IMGOUTERTEXTSPACE;
1282 const bool bSymbolFont = isSymbolFont(rInfo);
1284 Color aTextColor = rUDEvt.GetDevice()->GetTextColor();
1285 Font aOldFont( rUDEvt.GetDevice()->GetFont() );
1286 Size aSize( aOldFont.GetSize() );
1287 aSize.Height() += EXTRAFONTSIZE;
1288 Font aFont( rInfo );
1289 aFont.SetSize( aSize );
1290 rUDEvt.GetDevice()->SetFont( aFont );
1291 rUDEvt.GetDevice()->SetTextColor( aTextColor );
1293 bool bUsingCorrectFont = true;
1294 Rectangle aTextRect;
1296 // Preview the font name
1297 OUString sFontName = rInfo.GetName();
1299 //If it shouldn't or can't draw its own name because it doesn't have the glyphs
1300 if (!canRenderNameOfSelectedFont(*rUDEvt.GetDevice()))
1301 bUsingCorrectFont = false;
1302 else
1304 //Make sure it fits in the available height, shrinking the font if necessary
1305 bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, *rUDEvt.GetDevice(), aTextRect) != 0;
1308 if (!bUsingCorrectFont)
1310 rUDEvt.GetDevice()->SetFont(aOldFont);
1311 rUDEvt.GetDevice()->GetTextBoundRect(aTextRect, sFontName, 0, 0);
1314 long nTextHeight = aTextRect.GetHeight();
1315 long nDesiredGap = (nH-nTextHeight)/2;
1316 long nVertAdjust = nDesiredGap - aTextRect.Top();
1317 Point aPos( nX, aTopLeft.Y() + nVertAdjust );
1318 rUDEvt.GetDevice()->DrawText( aPos, sFontName );
1319 long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW;
1321 if (!bUsingCorrectFont)
1322 rUDEvt.GetDevice()->SetFont( aFont );
1324 OUString sSampleText;
1326 if (!bSymbolFont)
1328 const bool bNameBeginsWithLatinText = rInfo.GetName().GetChar(0) <= 'z';
1330 if (bNameBeginsWithLatinText || !bUsingCorrectFont)
1331 sSampleText = makeShortRepresentativeTextForSelectedFont(*rUDEvt.GetDevice());
1334 //If we're not a symbol font, but could neither render our own name and
1335 //we can't determine what script it would like to render, then try a
1336 //few well known scripts
1337 if (sSampleText.isEmpty() && !bUsingCorrectFont)
1339 static const UScriptCode aScripts[] =
1341 USCRIPT_ARABIC,
1342 USCRIPT_HEBREW,
1344 USCRIPT_BENGALI,
1345 USCRIPT_GURMUKHI,
1346 USCRIPT_GUJARATI,
1347 USCRIPT_ORIYA,
1348 USCRIPT_TAMIL,
1349 USCRIPT_TELUGU,
1350 USCRIPT_KANNADA,
1351 USCRIPT_MALAYALAM,
1352 USCRIPT_SINHALA,
1353 USCRIPT_DEVANAGARI,
1355 USCRIPT_THAI,
1356 USCRIPT_LAO,
1357 USCRIPT_GEORGIAN,
1358 USCRIPT_TIBETAN,
1359 USCRIPT_SYRIAC,
1360 USCRIPT_MYANMAR,
1361 USCRIPT_ETHIOPIC,
1362 USCRIPT_KHMER,
1363 USCRIPT_MONGOLIAN,
1365 USCRIPT_KOREAN,
1366 USCRIPT_JAPANESE,
1367 USCRIPT_HAN,
1368 USCRIPT_SIMPLIFIED_HAN,
1369 USCRIPT_TRADITIONAL_HAN,
1371 USCRIPT_GREEK
1374 for (size_t i = 0; i < SAL_N_ELEMENTS(aScripts); ++i)
1376 OUString sText = makeShortRepresentativeTextForScript(aScripts[i]);
1377 if (!sText.isEmpty())
1379 bool bHasSampleTextGlyphs = (STRING_LEN == rUDEvt.GetDevice()->HasGlyphs(aFont, sText));
1380 if (bHasSampleTextGlyphs)
1382 sSampleText = sText;
1383 break;
1388 static const UScriptCode aMinimalScripts[] =
1390 USCRIPT_HEBREW, //e.g. biblical hebrew
1391 USCRIPT_GREEK
1394 for (size_t i = 0; i < SAL_N_ELEMENTS(aMinimalScripts); ++i)
1396 OUString sText = makeShortMinimalTextForScript(aMinimalScripts[i]);
1397 if (!sText.isEmpty())
1399 bool bHasSampleTextGlyphs = (STRING_LEN == rUDEvt.GetDevice()->HasGlyphs(aFont, sText));
1400 if (bHasSampleTextGlyphs)
1402 sSampleText = sText;
1403 break;
1409 //If we're a symbol font, or for some reason the font still couldn't
1410 //render something representative of what it would like to render then
1411 //make up some semi-random text that it *can* display
1412 if (bSymbolFont || (!bUsingCorrectFont && sSampleText.isEmpty()))
1413 sSampleText = makeShortRepresentativeSymbolTextForSelectedFont(*rUDEvt.GetDevice());
1415 if (!sSampleText.isEmpty())
1417 const Size &rItemSize = rUDEvt.GetDevice()->GetOutputSize();
1418 //leave a little border at the edge
1419 long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE;
1420 if (nSpace >= 0)
1422 //Make sure it fits in the available height, and get how wide that would be
1423 long nWidth = shrinkFontToFit(sSampleText, nH, aFont, *rUDEvt.GetDevice(), aTextRect);
1424 //Chop letters off until it fits in the available width
1425 while (nWidth > nSpace || nWidth > MAXPREVIEWWIDTH)
1427 sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
1428 nWidth = rUDEvt.GetDevice()->GetTextBoundRect(aTextRect, sSampleText, 0, 0) ?
1429 aTextRect.GetWidth() : 0;
1432 //center the text on the line
1433 if (!sSampleText.isEmpty() && nWidth)
1435 nTextHeight = aTextRect.GetHeight();
1436 nDesiredGap = (nH-nTextHeight)/2;
1437 nVertAdjust = nDesiredGap - aTextRect.Top();
1438 aPos = Point(nTextX + nSpace - nWidth, aTopLeft.Y() + nVertAdjust);
1439 rUDEvt.GetDevice()->DrawText( aPos, sSampleText );
1444 rUDEvt.GetDevice()->SetFont( aOldFont );
1445 DrawEntry( rUDEvt, sal_False, sal_False); // draw separator
1447 else
1449 DrawEntry( rUDEvt, sal_True, sal_True );
1453 // ===================================================================
1454 // FontStyleBox
1455 // ===================================================================
1457 FontStyleBox::FontStyleBox( Window* pParent, const ResId& rResId ) :
1458 ComboBox( pParent, rResId )
1460 aLastStyle = GetText();
1463 FontStyleBox::FontStyleBox( Window* pParent, WinBits nBits ) :
1464 ComboBox( pParent, nBits )
1466 aLastStyle = GetText();
1469 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeFontStyleBox(Window *pParent, VclBuilder::stringmap &rMap)
1471 bool bDropdown = extractDropdown(rMap);
1472 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
1473 if (bDropdown)
1474 nWinBits |= WB_DROPDOWN;
1475 FontStyleBox *pListBox = new FontStyleBox(pParent, nWinBits);
1476 if (bDropdown)
1477 pListBox->EnableAutoSize(true);
1478 return pListBox;
1481 FontStyleBox::~FontStyleBox()
1485 // -------------------------------------------------------------------
1487 void FontStyleBox::Select()
1489 // keep text over fill operation
1490 aLastStyle = GetText();
1491 ComboBox::Select();
1494 // -------------------------------------------------------------------
1496 void FontStyleBox::LoseFocus()
1498 // keep text over fill operation
1499 aLastStyle = GetText();
1500 ComboBox::LoseFocus();
1503 // -------------------------------------------------------------------
1505 void FontStyleBox::Modify()
1507 CharClass aChrCls( ::comphelper::getProcessComponentContext(),
1508 GetSettings().GetLanguageTag() );
1509 XubString aStr = GetText();
1510 sal_uInt16 nEntryCount = GetEntryCount();
1512 if ( GetEntryPos( aStr ) == COMBOBOX_ENTRY_NOTFOUND )
1514 aStr = aChrCls.uppercase(aStr);
1515 for ( sal_uInt16 i = 0; i < nEntryCount; i++ )
1517 XubString aEntryText = aChrCls.uppercase(GetEntry(i));
1519 if ( aStr == aEntryText )
1521 SetText( GetEntry( i ) );
1522 break;
1527 ComboBox::Modify();
1530 // -------------------------------------------------------------------
1532 void FontStyleBox::Fill( const XubString& rName, const FontList* pList )
1534 // note: this method must call ComboBox::SetText(),
1535 // else aLastStyle will overwritten
1536 // store prior selection position and clear box
1537 XubString aOldText = GetText();
1538 sal_uInt16 nPos = GetEntryPos( aOldText );
1539 Clear();
1541 // does a font with this name already exist?
1542 sal_Handle hFontInfo = pList->GetFirstFontInfo( rName );
1543 if ( hFontInfo )
1545 OUString aStyleText;
1546 FontWeight eLastWeight = WEIGHT_DONTKNOW;
1547 FontItalic eLastItalic = ITALIC_NONE;
1548 FontWidth eLastWidth = WIDTH_DONTKNOW;
1549 sal_Bool bNormal = sal_False;
1550 sal_Bool bItalic = sal_False;
1551 sal_Bool bBold = sal_False;
1552 sal_Bool bBoldItalic = sal_False;
1553 sal_Bool bInsert = sal_False;
1554 FontInfo aInfo;
1555 while ( hFontInfo )
1557 aInfo = pList->GetFontInfo( hFontInfo );
1559 FontWeight eWeight = aInfo.GetWeight();
1560 FontItalic eItalic = aInfo.GetItalic();
1561 FontWidth eWidth = aInfo.GetWidthType();
1562 // Only if the attributes are different, we insert the
1563 // Font to avoid double Entries in different languages
1564 if ( (eWeight != eLastWeight) || (eItalic != eLastItalic) ||
1565 (eWidth != eLastWidth) )
1567 if ( bInsert )
1568 InsertEntry( aStyleText );
1570 if ( eWeight <= WEIGHT_NORMAL )
1572 if ( eItalic != ITALIC_NONE )
1573 bItalic = sal_True;
1574 else
1575 bNormal = sal_True;
1577 else
1579 if ( eItalic != ITALIC_NONE )
1580 bBoldItalic = sal_True;
1581 else
1582 bBold = sal_True;
1585 // For wrong StyleNames we replace this with the correct once
1586 aStyleText = pList->GetStyleName( aInfo );
1587 bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
1588 if ( !bInsert )
1590 aStyleText = pList->GetStyleName( eWeight, eItalic );
1591 bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
1594 eLastWeight = eWeight;
1595 eLastItalic = eItalic;
1596 eLastWidth = eWidth;
1598 else
1600 if ( bInsert )
1602 // If we have two names for the same attributes
1603 // we prefer the translated standard names
1604 const OUString& rAttrStyleText = pList->GetStyleName( eWeight, eItalic );
1605 if (rAttrStyleText != aStyleText)
1607 OUString aTempStyleText = pList->GetStyleName( aInfo );
1608 if (rAttrStyleText == aTempStyleText)
1609 aStyleText = rAttrStyleText;
1610 bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
1615 if ( !bItalic && (aStyleText == pList->GetItalicStr()) )
1616 bItalic = sal_True;
1617 else if ( !bBold && (aStyleText == pList->GetBoldStr()) )
1618 bBold = sal_True;
1619 else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) )
1620 bBoldItalic = sal_True;
1622 hFontInfo = pList->GetNextFontInfo( hFontInfo );
1625 if ( bInsert )
1626 InsertEntry( aStyleText );
1628 // Bestimmte Styles als Nachbildung
1629 if ( bNormal )
1631 if ( !bItalic )
1632 InsertEntry( pList->GetItalicStr() );
1633 if ( !bBold )
1634 InsertEntry( pList->GetBoldStr() );
1636 if ( !bBoldItalic )
1638 if ( bNormal || bItalic || bBold )
1639 InsertEntry( pList->GetBoldItalicStr() );
1641 if ( aOldText.Len() )
1643 if ( GetEntryPos( aLastStyle ) != LISTBOX_ENTRY_NOTFOUND )
1644 ComboBox::SetText( aLastStyle );
1645 else
1647 if ( nPos >= GetEntryCount() )
1648 ComboBox::SetText( GetEntry( 0 ) );
1649 else
1650 ComboBox::SetText( GetEntry( nPos ) );
1654 else
1656 // Wenn Font nicht, dann Standard-Styles einfuegen
1657 InsertEntry( pList->GetNormalStr() );
1658 InsertEntry( pList->GetItalicStr() );
1659 InsertEntry( pList->GetBoldStr() );
1660 InsertEntry( pList->GetBoldItalicStr() );
1661 if ( aOldText.Len() )
1663 if ( nPos > GetEntryCount() )
1664 ComboBox::SetText( GetEntry( 0 ) );
1665 else
1666 ComboBox::SetText( GetEntry( nPos ) );
1671 // ===================================================================
1672 // FontSizeBox
1673 // ===================================================================
1675 FontSizeBox::FontSizeBox( Window* pParent, WinBits nWinSize ) :
1676 MetricBox( pParent, nWinSize )
1678 ImplInit();
1681 // -----------------------------------------------------------------------
1683 FontSizeBox::FontSizeBox( Window* pParent, const ResId& rResId ) :
1684 MetricBox( pParent, rResId )
1686 ImplInit();
1689 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeFontSizeBox(Window *pParent, VclBuilder::stringmap &rMap)
1691 bool bDropdown = extractDropdown(rMap);
1692 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
1693 if (bDropdown)
1694 nWinBits |= WB_DROPDOWN;
1695 FontSizeBox* pListBox = new FontSizeBox(pParent, nWinBits);
1696 if (bDropdown)
1697 pListBox->EnableAutoSize(true);
1698 return pListBox;
1701 // -----------------------------------------------------------------------
1703 FontSizeBox::~FontSizeBox()
1707 // -----------------------------------------------------------------------
1709 void FontSizeBox::ImplInit()
1711 EnableAutocomplete( sal_False );
1713 bRelativeMode = sal_False;
1714 bPtRelative = sal_False;
1715 bRelative = sal_False;
1716 bStdSize = sal_False;
1717 pFontList = NULL;
1719 SetShowTrailingZeros( sal_False );
1720 SetDecimalDigits( 1 );
1721 SetMin( 20 );
1722 SetMax( 9999 );
1723 SetProminentEntryType( PROMINENT_MIDDLE );
1726 // -----------------------------------------------------------------------
1728 void FontSizeBox::Reformat()
1730 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1731 if ( !bRelativeMode || !aFontSizeNames.IsEmpty() )
1733 long nNewValue = aFontSizeNames.Name2Size( GetText() );
1734 if ( nNewValue)
1736 mnLastValue = nNewValue;
1737 return;
1741 MetricBox::Reformat();
1744 // -----------------------------------------------------------------------
1746 void FontSizeBox::Modify()
1748 MetricBox::Modify();
1750 if ( bRelativeMode )
1752 XubString aStr = comphelper::string::stripStart(GetText(), ' ');
1754 sal_Bool bNewMode = bRelative;
1755 sal_Bool bOldPtRelMode = bPtRelative;
1757 if ( bRelative )
1759 bPtRelative = sal_False;
1760 const sal_Unicode* pStr = aStr.GetBuffer();
1761 while ( *pStr )
1763 if ( ((*pStr < '0') || (*pStr > '9')) && (*pStr != '%') )
1765 if ( ('-' == *pStr || '+' == *pStr) && !bPtRelative )
1766 bPtRelative = sal_True;
1767 else if ( bPtRelative && 'p' == *pStr && 't' == *++pStr )
1769 else
1771 bNewMode = sal_False;
1772 break;
1775 pStr++;
1778 else
1780 if ( STRING_NOTFOUND != aStr.Search( '%' ) )
1782 bNewMode = sal_True;
1783 bPtRelative = sal_False;
1786 if ( '-' == aStr.GetChar( 0 ) || '+' == aStr.GetChar( 0 ) )
1788 bNewMode = sal_True;
1789 bPtRelative = sal_True;
1793 if ( bNewMode != bRelative || bPtRelative != bOldPtRelMode )
1794 SetRelative( bNewMode );
1798 // -----------------------------------------------------------------------
1800 void FontSizeBox::Fill( const FontInfo* pInfo, const FontList* pList )
1802 // remember for relative mode
1803 pFontList = pList;
1805 // no font sizes need to be set for relative mode
1806 if ( bRelative )
1807 return;
1809 // query font sizes
1810 const long* pTempAry;
1811 const long* pAry = 0;
1813 if( pInfo )
1815 aFontInfo = *pInfo;
1816 pAry = pList->GetSizeAry( *pInfo );
1818 else
1820 pAry = pList->GetStdSizeAry();
1823 // first insert font size names (for simplified/traditional chinese)
1824 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1825 if ( pAry == pList->GetStdSizeAry() )
1827 // for standard sizes we don't need to bother
1828 if ( bStdSize && GetEntryCount() && aFontSizeNames.IsEmpty() )
1829 return;
1830 bStdSize = sal_True;
1832 else
1833 bStdSize = sal_False;
1835 Selection aSelection = GetSelection();
1836 XubString aStr = GetText();
1838 Clear();
1839 sal_uInt16 nPos = 0;
1841 if ( !aFontSizeNames.IsEmpty() )
1843 if ( pAry == pList->GetStdSizeAry() )
1845 // for scalable fonts all font size names
1846 sal_uLong nCount = aFontSizeNames.Count();
1847 for( sal_uLong i = 0; i < nCount; i++ )
1849 String aSizeName = aFontSizeNames.GetIndexName( i );
1850 long nSize = aFontSizeNames.GetIndexSize( i );
1851 ComboBox::InsertEntry( aSizeName, nPos );
1852 ComboBox::SetEntryData( nPos, (void*)(-nSize) ); // mark as special
1853 nPos++;
1856 else
1858 // for fixed size fonts only selectable font size names
1859 pTempAry = pAry;
1860 while ( *pTempAry )
1862 String aSizeName = aFontSizeNames.Size2Name( *pTempAry );
1863 if ( aSizeName.Len() )
1865 ComboBox::InsertEntry( aSizeName, nPos );
1866 ComboBox::SetEntryData( nPos, (void*)(-(*pTempAry)) ); // mark as special
1867 nPos++;
1869 pTempAry++;
1874 // then insert numerical font size values
1875 pTempAry = pAry;
1876 while ( *pTempAry )
1878 InsertValue( *pTempAry, FUNIT_NONE, nPos );
1879 ComboBox::SetEntryData( nPos, (void*)(*pTempAry) );
1880 nPos++;
1881 pTempAry++;
1884 SetText( aStr );
1885 SetSelection( aSelection );
1888 // -----------------------------------------------------------------------
1890 void FontSizeBox::EnableRelativeMode( sal_uInt16 nMin, sal_uInt16 nMax, sal_uInt16 nStep )
1892 bRelativeMode = sal_True;
1893 nRelMin = nMin;
1894 nRelMax = nMax;
1895 nRelStep = nStep;
1896 SetUnit( FUNIT_POINT );
1899 // -----------------------------------------------------------------------
1901 void FontSizeBox::EnablePtRelativeMode( short nMin, short nMax, short nStep )
1903 bRelativeMode = sal_True;
1904 nPtRelMin = nMin;
1905 nPtRelMax = nMax;
1906 nPtRelStep = nStep;
1907 SetUnit( FUNIT_POINT );
1910 // -----------------------------------------------------------------------
1912 void FontSizeBox::SetRelative( sal_Bool bNewRelative )
1914 if ( bRelativeMode )
1916 Selection aSelection = GetSelection();
1917 XubString aStr = comphelper::string::stripStart(GetText(), ' ');
1919 if ( bNewRelative )
1921 bRelative = sal_True;
1922 bStdSize = sal_False;
1924 if ( bPtRelative )
1926 SetDecimalDigits( 1 );
1927 SetMin( nPtRelMin );
1928 SetMax( nPtRelMax );
1929 SetUnit( FUNIT_POINT );
1931 Clear();
1933 short i = nPtRelMin, n = 0;
1934 // JP 30.06.98: more than 100 values are not useful
1935 while ( i <= nPtRelMax && n++ < 100 )
1937 InsertValue( i );
1938 i = i + nPtRelStep;
1941 else
1943 SetDecimalDigits( 0 );
1944 SetMin( nRelMin );
1945 SetMax( nRelMax );
1946 SetCustomUnitText(OUString('%'));
1947 SetUnit( FUNIT_CUSTOM );
1949 Clear();
1950 sal_uInt16 i = nRelMin;
1951 while ( i <= nRelMax )
1953 InsertValue( i );
1954 i = i + nRelStep;
1958 else
1960 bRelative = bPtRelative = sal_False;
1961 SetDecimalDigits( 1 );
1962 SetMin( 20 );
1963 SetMax( 9999 );
1964 SetUnit( FUNIT_POINT );
1965 if ( pFontList )
1966 Fill( &aFontInfo, pFontList );
1969 SetText( aStr );
1970 SetSelection( aSelection );
1974 // -----------------------------------------------------------------------
1976 OUString FontSizeBox::CreateFieldText( sal_Int64 nValue ) const
1978 OUString sRet( MetricBox::CreateFieldText( nValue ) );
1979 if ( bRelativeMode && bPtRelative && (0 <= nValue) && !sRet.isEmpty() )
1980 sRet = "+" + sRet;
1981 return sRet;
1984 // -----------------------------------------------------------------------
1986 void FontSizeBox::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit )
1988 if ( !bRelative )
1990 sal_Int64 nTempValue = MetricField::ConvertValue( nNewValue, GetBaseValue(), GetDecimalDigits(), eInUnit, GetUnit() );
1991 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1992 // conversion loses precision; however font sizes should
1993 // never have a problem with that
1994 String aName = aFontSizeNames.Size2Name( static_cast<long>(nTempValue) );
1995 if ( aName.Len() && (GetEntryPos( aName ) != LISTBOX_ENTRY_NOTFOUND) )
1997 mnLastValue = nTempValue;
1998 SetText( aName );
1999 mnFieldValue = mnLastValue;
2000 SetEmptyFieldValueData( sal_False );
2001 return;
2005 MetricBox::SetValue( nNewValue, eInUnit );
2008 // -----------------------------------------------------------------------
2010 void FontSizeBox::SetValue( sal_Int64 nNewValue )
2012 SetValue( nNewValue, FUNIT_NONE );
2015 // -----------------------------------------------------------------------
2017 sal_Int64 FontSizeBox::GetValue( sal_uInt16 nPos, FieldUnit eOutUnit ) const
2019 if ( !bRelative )
2021 sal_Int64 nComboVal = static_cast<sal_Int64>(reinterpret_cast<long>(ComboBox::GetEntryData( nPos )));
2022 if ( nComboVal < 0 ) // marked as special?
2024 return MetricField::ConvertValue( -nComboVal, mnBaseValue, GetDecimalDigits(),
2025 meUnit, eOutUnit );
2029 // do normal font size processing
2030 sal_Int64 nRetValue = MetricBox::GetValue( nPos, eOutUnit );
2031 return nRetValue;
2034 // -----------------------------------------------------------------------
2036 sal_Int64 FontSizeBox::GetValue( FieldUnit eOutUnit ) const
2038 if ( !bRelative )
2040 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
2041 sal_Int64 nValue = aFontSizeNames.Name2Size( GetText() );
2042 if ( nValue)
2043 return MetricField::ConvertValue( nValue, GetBaseValue(), GetDecimalDigits(), GetUnit(), eOutUnit );
2046 return MetricBox::GetValue( eOutUnit );
2049 // -----------------------------------------------------------------------
2051 sal_Int64 FontSizeBox::GetValue() const
2053 // implementation not inline, because it is a virtual function
2054 return GetValue( FUNIT_NONE );
2057 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */