Bump version to 5.0-14
[LibreOffice.git] / svtools / source / control / ctrlbox.cxx
blob95214b1a86687a38ec4b342f770a17f3e33cf829
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 <config_folders.h>
22 #include <i18nutil/unicode.hxx>
23 #include <tools/stream.hxx>
24 #include <vcl/builderfactory.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/field.hxx>
27 #include <vcl/helper.hxx>
28 #include <vcl/settings.hxx>
29 #include <sal/macros.h>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/string.hxx>
32 #include <unotools/charclass.hxx>
34 #include <svtools/sampletext.hxx>
35 #include <svtools/svtresid.hxx>
36 #include <svtools/svtools.hrc>
37 #include <svtools/ctrlbox.hxx>
38 #include <svtools/ctrltool.hxx>
39 #include <svtools/borderhelper.hxx>
41 #include <vcl/i18nhelp.hxx>
42 #include <vcl/fontcapabilities.hxx>
43 #include <basegfx/polygon/b2dpolygon.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
46 #include <com/sun/star/table/BorderLineStyle.hpp>
48 #include <rtl/bootstrap.hxx>
50 #include <stdio.h>
52 #define IMGOUTERTEXTSPACE 5
53 #define EXTRAFONTSIZE 5
54 #define GAPTOEXTRAPREVIEW 10
55 #define MAXPREVIEWWIDTH 120
56 #define MINGAPWIDTH 2
58 #define FONTNAMEBOXMRUENTRIESFILE "/user/config/fontnameboxmruentries"
60 using namespace ::com::sun::star;
62 class ImplColorListData
64 public:
65 Color aColor;
66 bool bColor;
68 ImplColorListData() : aColor( COL_BLACK ) { bColor = false; }
69 ImplColorListData( const Color& rColor ) : aColor( rColor ) { bColor = true; }
72 void ColorListBox::ImplInit()
74 pColorList = new ImpColorList();
76 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
77 aImageSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
78 EnableUserDraw( true );
79 SetUserItemSize( aImageSize );
82 void ColorListBox::ImplDestroyColorEntries()
84 for ( size_t n = pColorList->size(); n; )
85 delete (*pColorList)[ --n ];
86 pColorList->clear();
89 ColorListBox::ColorListBox( vcl::Window* pParent, WinBits nWinStyle ) :
90 ListBox( pParent, nWinStyle )
92 ImplInit();
93 SetEdgeBlending(true);
96 ColorListBox::ColorListBox( vcl::Window* pParent, const ResId& rResId ) :
97 ListBox( pParent, rResId )
99 ImplInit();
100 SetEdgeBlending(true);
103 VCL_BUILDER_DECL_FACTORY(ColorListBox)
105 bool bDropdown = VclBuilder::extractDropdown(rMap);
106 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
107 if (bDropdown)
108 nWinBits |= WB_DROPDOWN;
109 VclPtrInstance<ColorListBox> pListBox(pParent, nWinBits);
110 if (bDropdown)
111 pListBox->EnableAutoSize(true);
112 rRet = pListBox;
115 ColorListBox::~ColorListBox()
117 disposeOnce();
120 void ColorListBox::dispose()
122 if ( pColorList )
124 ImplDestroyColorEntries();
125 delete pColorList;
126 pColorList = NULL;
128 ListBox::dispose();
131 sal_Int32 ColorListBox::InsertEntry( const OUString& rStr, sal_Int32 nPos )
133 nPos = ListBox::InsertEntry( rStr, nPos );
134 if ( nPos != LISTBOX_ERROR )
136 ImplColorListData* pData = new ImplColorListData;
137 if ( static_cast<size_t>(nPos) < pColorList->size() )
139 ImpColorList::iterator it = pColorList->begin();
140 ::std::advance( it, nPos );
141 pColorList->insert( it, pData );
143 else
145 pColorList->push_back( pData );
146 nPos = pColorList->size() - 1;
149 return nPos;
152 sal_Int32 ColorListBox::InsertEntry( const Color& rColor, const OUString& rStr,
153 sal_Int32 nPos )
155 nPos = ListBox::InsertEntry( rStr, nPos );
156 if ( nPos != LISTBOX_ERROR )
158 ImplColorListData* pData = new ImplColorListData( rColor );
159 if ( static_cast<size_t>(nPos) < pColorList->size() )
161 ImpColorList::iterator it = pColorList->begin();
162 ::std::advance( it, nPos );
163 pColorList->insert( it, pData );
165 else
167 pColorList->push_back( pData );
168 nPos = pColorList->size() - 1;
171 return nPos;
174 void ColorListBox::InsertAutomaticEntryColor(const Color &rColor)
176 // insert the "Automatic"-entry always on the first position
177 InsertEntry( rColor, SVT_RESSTR(STR_SVT_AUTOMATIC_COLOR), 0 );
180 void ColorListBox::RemoveEntry( sal_Int32 nPos )
182 ListBox::RemoveEntry( nPos );
183 if ( 0 <= nPos && static_cast<size_t>(nPos) < pColorList->size() )
185 ImpColorList::iterator it = pColorList->begin();
186 ::std::advance( it, nPos );
187 delete *it;
188 pColorList->erase( it );
192 void ColorListBox::Clear()
194 ImplDestroyColorEntries();
195 ListBox::Clear();
198 void ColorListBox::CopyEntries( const ColorListBox& rBox )
200 // Liste leeren
201 ImplDestroyColorEntries();
203 // Daten kopieren
204 size_t nCount = rBox.pColorList->size();
205 for ( size_t n = 0; n < nCount; n++ )
207 ImplColorListData* pData = (*rBox.pColorList)[ n ];
208 sal_Int32 nPos = InsertEntry( rBox.GetEntry( n ), LISTBOX_APPEND );
209 if ( nPos != LISTBOX_ERROR )
211 if ( static_cast<size_t>(nPos) < pColorList->size() )
213 ImpColorList::iterator it = pColorList->begin();
214 ::std::advance( it, nPos );
215 pColorList->insert( it, new ImplColorListData( *pData ) );
217 else
219 pColorList->push_back( new ImplColorListData( *pData ) );
225 sal_Int32 ColorListBox::GetEntryPos( const Color& rColor ) const
227 for( sal_Int32 n = (sal_Int32) pColorList->size(); n; )
229 ImplColorListData* pData = (*pColorList)[ --n ];
230 if ( pData->bColor && ( pData->aColor == rColor ) )
231 return n;
233 return LISTBOX_ENTRY_NOTFOUND;
236 Color ColorListBox::GetEntryColor( sal_Int32 nPos ) const
238 Color aColor;
239 ImplColorListData* pData = ( 0 <= nPos && static_cast<size_t>(nPos) < pColorList->size() ) ?
240 (*pColorList)[ nPos ] : NULL;
241 if ( pData && pData->bColor )
242 aColor = pData->aColor;
243 return aColor;
246 void ColorListBox::UserDraw( const UserDrawEvent& rUDEvt )
248 size_t nPos = rUDEvt.GetItemId();
249 ImplColorListData* pData = ( nPos < pColorList->size() ) ? (*pColorList)[ nPos ] : NULL;
250 if ( pData )
252 if ( pData->bColor )
254 Point aPos( rUDEvt.GetRect().TopLeft() );
256 aPos.X() += 2;
257 aPos.Y() += ( rUDEvt.GetRect().GetHeight() - aImageSize.Height() ) / 2;
259 const Rectangle aRect(aPos, aImageSize);
261 vcl::RenderContext* pRenderContext = rUDEvt.GetRenderContext();
262 pRenderContext->Push();
263 pRenderContext->SetFillColor(pData->aColor);
264 pRenderContext->SetLineColor(pRenderContext->GetTextColor());
265 pRenderContext->DrawRect(aRect);
266 pRenderContext->Pop();
268 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
269 const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
271 if(nEdgeBlendingPercent)
273 const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
274 const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
275 const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
276 const BitmapEx aBlendFrame(createBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight));
278 if(!aBlendFrame.IsEmpty())
280 pRenderContext->DrawBitmapEx(aRect.TopLeft(), aBlendFrame);
284 ListBox::DrawEntry( rUDEvt, false, true, false );
286 else
287 ListBox::DrawEntry( rUDEvt, false, true, true );
289 else
290 ListBox::DrawEntry( rUDEvt, true, true, false );
293 BorderWidthImpl::BorderWidthImpl( BorderWidthImplFlags nFlags, double nRate1, double nRate2, double nRateGap ):
294 m_nFlags( nFlags ),
295 m_nRate1( nRate1 ),
296 m_nRate2( nRate2 ),
297 m_nRateGap( nRateGap )
301 BorderWidthImpl& BorderWidthImpl::operator= ( const BorderWidthImpl& r )
303 m_nFlags = r.m_nFlags;
304 m_nRate1 = r.m_nRate1;
305 m_nRate2 = r.m_nRate2;
306 m_nRateGap = r.m_nRateGap;
307 return *this;
310 bool BorderWidthImpl::operator== ( const BorderWidthImpl& r ) const
312 return ( m_nFlags == r.m_nFlags ) &&
313 ( m_nRate1 == r.m_nRate1 ) &&
314 ( m_nRate2 == r.m_nRate2 ) &&
315 ( m_nRateGap == r.m_nRateGap );
318 long BorderWidthImpl::GetLine1( long nWidth ) const
320 long result = static_cast<long>(m_nRate1);
321 if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 )
323 long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
324 long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
325 result = std::max<long>(0,
326 static_cast<long>((m_nRate1 * nWidth) + 0.5)
327 - (nConstant2 + nConstantD));
328 if (result == 0 && m_nRate1 > 0.0 && nWidth > 0)
329 { // fdo#51777: hack to essentially treat 1 twip DOUBLE border
330 result = 1; // as 1 twip SINGLE border
333 return result;
336 long BorderWidthImpl::GetLine2( long nWidth ) const
338 long result = static_cast<long>(m_nRate2);
339 if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2)
341 long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
342 long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
343 result = std::max<long>(0,
344 static_cast<long>((m_nRate2 * nWidth) + 0.5)
345 - (nConstant1 + nConstantD));
347 return result;
350 long BorderWidthImpl::GetGap( long nWidth ) const
352 long result = static_cast<long>(m_nRateGap);
353 if ( m_nFlags & BorderWidthImplFlags::CHANGE_DIST )
355 long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
356 long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
357 result = std::max<long>(0,
358 static_cast<long>((m_nRateGap * nWidth) + 0.5)
359 - (nConstant1 + nConstant2));
362 // Avoid having too small distances (less than 0.1pt)
363 if ( result < MINGAPWIDTH && m_nRate1 > 0 && m_nRate2 > 0 )
364 result = MINGAPWIDTH;
366 return result;
369 static double lcl_getGuessedWidth( long nTested, double nRate, bool nChanging )
371 double nWidth = -1.0;
372 if ( nChanging )
373 nWidth = double( nTested ) / nRate;
374 else
376 if ( double( nTested ) == nRate )
377 nWidth = nRate;
380 return nWidth;
383 long BorderWidthImpl::GuessWidth( long nLine1, long nLine2, long nGap )
385 std::vector< double > aToCompare;
386 bool bInvalid = false;
388 bool bLine1Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 );
389 double nWidth1 = lcl_getGuessedWidth( nLine1, m_nRate1, bLine1Change );
390 if ( bLine1Change )
391 aToCompare.push_back( nWidth1 );
392 else if ( !bLine1Change && nWidth1 < 0 )
393 bInvalid = true;
395 bool bLine2Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2 );
396 double nWidth2 = lcl_getGuessedWidth( nLine2, m_nRate2, bLine2Change );
397 if ( bLine2Change )
398 aToCompare.push_back( nWidth2 );
399 else if ( !bLine2Change && nWidth2 < 0 )
400 bInvalid = true;
402 bool bGapChange = bool( m_nFlags & BorderWidthImplFlags::CHANGE_DIST );
403 double nWidthGap = lcl_getGuessedWidth( nGap, m_nRateGap, bGapChange );
404 if ( bGapChange && nGap > MINGAPWIDTH )
405 aToCompare.push_back( nWidthGap );
406 else if ( !bGapChange && nWidthGap < 0 )
407 bInvalid = true;
409 // non-constant line width factors must sum to 1
410 assert((((bLine1Change) ? m_nRate1 : 0) +
411 ((bLine2Change) ? m_nRate2 : 0) +
412 ((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001 );
414 double nWidth = 0.0;
415 if ( (!bInvalid) && (!aToCompare.empty()) )
417 nWidth = *aToCompare.begin();
418 std::vector< double >::iterator pIt = aToCompare.begin();
419 while ( pIt != aToCompare.end() && !bInvalid )
421 bInvalid = ( nWidth != *pIt );
422 ++pIt;
424 nWidth = (bInvalid) ? 0.0 : nLine1 + nLine2 + nGap;
427 return nWidth;
430 /** Utility class storing the border line width, style and colors. The widths
431 are defined in Twips.
433 class ImpLineListData
435 private:
436 BorderWidthImpl m_aWidthImpl;
438 Color ( *m_pColor1Fn )( Color );
439 Color ( *m_pColor2Fn )( Color );
440 Color ( *m_pColorDistFn )( Color, Color );
442 long m_nMinWidth;
443 sal_uInt16 m_nStyle;
445 public:
446 ImpLineListData( BorderWidthImpl aWidthImpl, sal_uInt16 nStyle,
447 long nMinWidth=0, Color ( *pColor1Fn ) ( Color ) = &sameColor,
448 Color ( *pColor2Fn ) ( Color ) = &sameColor, Color ( *pColorDistFn ) ( Color, Color ) = &sameDistColor );
450 /** Returns the computed width of the line 1 in twips. */
451 long GetLine1ForWidth( long nWidth ) { return m_aWidthImpl.GetLine1( nWidth ); }
453 /** Returns the computed width of the line 2 in twips. */
454 long GetLine2ForWidth( long nWidth ) { return m_aWidthImpl.GetLine2( nWidth ); }
456 /** Returns the computed width of the gap in twips. */
457 long GetDistForWidth( long nWidth ) { return m_aWidthImpl.GetGap( nWidth ); }
459 Color GetColorLine1( const Color& aMain );
460 Color GetColorLine2( const Color& aMain );
461 Color GetColorDist( const Color& aMain, const Color& rDefault );
463 /** Returns the minimum width in twips */
464 long GetMinWidth( ) { return m_nMinWidth;}
465 sal_uInt16 GetStyle( ) { return m_nStyle;}
468 ImpLineListData::ImpLineListData( BorderWidthImpl aWidthImpl,
469 sal_uInt16 nStyle, long nMinWidth, Color ( *pColor1Fn )( Color ),
470 Color ( *pColor2Fn )( Color ), Color ( *pColorDistFn )( Color, Color ) ) :
471 m_aWidthImpl( aWidthImpl ),
472 m_pColor1Fn( pColor1Fn ),
473 m_pColor2Fn( pColor2Fn ),
474 m_pColorDistFn( pColorDistFn ),
475 m_nMinWidth( nMinWidth ),
476 m_nStyle( nStyle )
481 Color ImpLineListData::GetColorLine1( const Color& rMain )
483 return ( *m_pColor1Fn )( rMain );
486 Color ImpLineListData::GetColorLine2( const Color& rMain )
488 return ( *m_pColor2Fn )( rMain );
491 Color ImpLineListData::GetColorDist( const Color& rMain, const Color& rDefault )
493 return ( *m_pColorDistFn )( rMain, rDefault );
496 sal_uInt16 LineListBox::GetSelectEntryStyle( sal_Int32 nSelIndex ) const
498 sal_uInt16 nStyle = table::BorderLineStyle::SOLID;
499 sal_Int32 nPos = GetSelectEntryPos( nSelIndex );
500 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
502 if (!m_sNone.isEmpty())
503 nPos--;
504 nStyle = GetEntryStyle( nPos );
507 return nStyle;
511 void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, long nWidth, sal_uInt16 nDashing )
513 AntialiasingFlags nOldAA = rDev.GetAntialiasing();
514 rDev.SetAntialiasing( nOldAA & ~AntialiasingFlags::EnableB2dDraw );
516 long nPix = rDev.PixelToLogic(Size(1, 1)).Width();
517 basegfx::B2DPolyPolygon aPolygons = svtools::ApplyLineDashing(rPolygon, nDashing, nPix);
519 // Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line
520 if (rDev.GetMapMode().GetMapUnit() == MAP_PIXEL && nWidth == nPix)
521 nWidth = 0;
523 for ( sal_uInt32 i = 0; i < aPolygons.count( ); i++ )
525 basegfx::B2DPolygon aDash = aPolygons.getB2DPolygon( i );
526 basegfx::B2DPoint aStart = aDash.getB2DPoint( 0 );
527 basegfx::B2DPoint aEnd = aDash.getB2DPoint( aDash.count() - 1 );
529 basegfx::B2DVector aVector( aEnd - aStart );
530 aVector.normalize( );
531 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
533 const basegfx::B2DVector aWidthOffset( double( nWidth ) / 2 * aPerpendicular);
534 basegfx::B2DPolygon aDashPolygon;
535 aDashPolygon.append( aStart + aWidthOffset );
536 aDashPolygon.append( aEnd + aWidthOffset );
537 aDashPolygon.append( aEnd - aWidthOffset );
538 aDashPolygon.append( aStart - aWidthOffset );
539 aDashPolygon.setClosed( true );
541 rDev.DrawPolygon( aDashPolygon );
544 rDev.SetAntialiasing( nOldAA );
547 namespace svtools {
550 * Dashing array must start with a line width and end with a blank width.
552 std::vector<double> GetDashing( sal_uInt16 nDashing )
554 std::vector<double> aPattern;
555 switch (nDashing)
557 case table::BorderLineStyle::DOTTED:
558 aPattern.push_back( 1.0 ); // line
559 aPattern.push_back( 2.0 ); // blank
560 break;
561 case table::BorderLineStyle::DASHED:
562 aPattern.push_back( 16.0 ); // line
563 aPattern.push_back( 5.0 ); // blank
564 break;
565 case table::BorderLineStyle::FINE_DASHED:
566 aPattern.push_back( 6.0 ); // line
567 aPattern.push_back( 2.0 ); // blank
568 break;
569 case table::BorderLineStyle::DASH_DOT:
570 aPattern.push_back( 16.0 ); // line
571 aPattern.push_back( 5.0 ); // blank
572 aPattern.push_back( 5.0 ); // line
573 aPattern.push_back( 5.0 ); // blank
574 break;
575 case table::BorderLineStyle::DASH_DOT_DOT:
576 aPattern.push_back( 16.0 ); // line
577 aPattern.push_back( 5.0 ); // blank
578 aPattern.push_back( 5.0 ); // line
579 aPattern.push_back( 5.0 ); // blank
580 aPattern.push_back( 5.0 ); // line
581 aPattern.push_back( 5.0 ); // blank
582 break;
583 default:
587 return aPattern;
590 namespace {
592 class ApplyScale : std::unary_function<double, void>
594 double mfScale;
595 public:
596 ApplyScale( double fScale ) : mfScale(fScale) {}
597 void operator() ( double& rVal )
599 rVal *= mfScale;
605 std::vector<double> GetLineDashing( sal_uInt16 nDashing, double fScale )
607 std::vector<double> aPattern = GetDashing(nDashing);
608 std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
609 return aPattern;
612 basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, sal_uInt16 nDashing, double fScale )
614 std::vector<double> aPattern = GetDashing(nDashing);
615 std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
617 basegfx::B2DPolyPolygon aPolygons;
619 if (aPattern.empty())
620 aPolygons.append(rPolygon);
621 else
622 basegfx::tools::applyLineDashing(rPolygon, aPattern, &aPolygons);
624 return aPolygons;
627 void DrawLine( OutputDevice& rDev, const Point& rP1, const Point& rP2,
628 sal_uInt32 nWidth, sal_uInt16 nDashing )
630 DrawLine( rDev, basegfx::B2DPoint( rP1.X(), rP1.Y() ),
631 basegfx::B2DPoint( rP2.X(), rP2.Y( ) ), nWidth, nDashing );
634 void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rP1, const basegfx::B2DPoint& rP2,
635 sal_uInt32 nWidth, sal_uInt16 nDashing )
637 basegfx::B2DPolygon aPolygon;
638 aPolygon.append( rP1 );
639 aPolygon.append( rP2 );
640 lclDrawPolygon( rDev, aPolygon, nWidth, nDashing );
645 void LineListBox::ImpGetLine( long nLine1, long nLine2, long nDistance,
646 Color aColor1, Color aColor2, Color aColorDist,
647 sal_uInt16 nStyle, Bitmap& rBmp )
649 //TODO, rather than including the " " text to force
650 //the line height, better would be do drop
651 //this calculation and draw a bitmap of height
652 //equal to normal text line and center the
653 //line within that
654 long nMinWidth = GetTextWidth(OUString("----------"));
655 Size aSize = CalcSubEditSize();
656 aSize.Width() = std::max(nMinWidth, aSize.Width());
657 aSize.Width() -= aTxtSize.Width();
658 aSize.Width() -= 6;
659 aSize.Height() = aTxtSize.Height();
661 // SourceUnit nach Twips
662 if ( eSourceUnit == FUNIT_POINT )
664 nLine1 /= 5;
665 nLine2 /= 5;
666 nDistance /= 5;
669 // Linien malen
670 aSize = aVirDev->PixelToLogic( aSize );
671 long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
672 sal_uInt32 n1 = nLine1;
673 sal_uInt32 n2 = nLine2;
674 long nDist = nDistance;
675 n1 += nPix-1;
676 n1 -= n1%nPix;
677 if ( n2 )
679 nDist += nPix-1;
680 nDist -= nDist%nPix;
681 n2 += nPix-1;
682 n2 -= n2%nPix;
684 long nVirHeight = n1+nDist+n2;
685 if ( nVirHeight > aSize.Height() )
686 aSize.Height() = nVirHeight;
687 // negative width should not be drawn
688 if ( aSize.Width() > 0 )
690 Size aVirSize = aVirDev->LogicToPixel( aSize );
691 if ( aVirDev->GetOutputSizePixel() != aVirSize )
692 aVirDev->SetOutputSizePixel( aVirSize );
693 aVirDev->SetFillColor( aColorDist );
694 aVirDev->DrawRect( Rectangle( Point(), aSize ) );
696 aVirDev->SetFillColor( aColor1 );
698 double y1 = double( n1 ) / 2;
699 svtools::DrawLine( *aVirDev.get(), basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
701 if ( n2 )
703 double y2 = n1 + nDist + double( n2 ) / 2;
704 aVirDev->SetFillColor( aColor2 );
705 svtools::DrawLine( *aVirDev.get(), basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, table::BorderLineStyle::SOLID );
707 rBmp = aVirDev->GetBitmap( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
711 void LineListBox::ImplInit()
713 aTxtSize.Width() = GetTextWidth( OUString( " " ) );
714 aTxtSize.Height() = GetTextHeight();
715 pLineList = new ImpLineList();
716 eUnit = FUNIT_POINT;
717 eSourceUnit = FUNIT_POINT;
719 aVirDev->SetLineColor();
720 aVirDev->SetMapMode( MapMode( MAP_TWIP ) );
722 UpdatePaintLineColor();
725 LineListBox::LineListBox( vcl::Window* pParent, WinBits nWinStyle ) :
726 ListBox( pParent, nWinStyle ),
727 m_nWidth( 5 ),
728 m_sNone( ),
729 aVirDev( VclPtr<VirtualDevice>::Create() ),
730 aColor( COL_BLACK ),
731 maPaintCol( COL_BLACK )
733 ImplInit();
736 VCL_BUILDER_DECL_FACTORY(LineListBox)
738 bool bDropdown = VclBuilder::extractDropdown(rMap);
739 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
740 if (bDropdown)
741 nWinBits |= WB_DROPDOWN;
742 VclPtrInstance<LineListBox> pListBox(pParent, nWinBits);
743 if (bDropdown)
744 pListBox->EnableAutoSize(true);
745 rRet = pListBox;
748 LineListBox::~LineListBox()
750 disposeOnce();
753 void LineListBox::dispose()
755 for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
756 if ( (*pLineList)[ i ] ) {
757 delete (*pLineList)[ i ];
760 pLineList->clear();
761 delete pLineList;
762 ListBox::dispose();
765 sal_Int32 LineListBox::GetStylePos( sal_Int32 nListPos, long nWidth )
767 sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
768 if (!m_sNone.isEmpty())
769 nListPos--;
771 sal_Int32 n = 0;
772 size_t i = 0;
773 size_t nCount = pLineList->size();
774 while ( nPos == LISTBOX_ENTRY_NOTFOUND && i < nCount )
776 ImpLineListData* pData = (*pLineList)[ i ];
777 if ( pData && pData->GetMinWidth() <= nWidth )
779 if ( nListPos == n )
780 nPos = static_cast<sal_Int32>(i);
781 n++;
783 i++;
786 return nPos;
789 void LineListBox::SelectEntry( sal_uInt16 nStyle, bool bSelect )
791 sal_Int32 nPos = GetEntryPos( nStyle );
792 if ( nPos != LISTBOX_ENTRY_NOTFOUND )
793 ListBox::SelectEntryPos( nPos, bSelect );
796 void LineListBox::InsertEntry(
797 const BorderWidthImpl& rWidthImpl, sal_uInt16 nStyle, long nMinWidth,
798 ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
800 ImpLineListData* pData = new ImpLineListData(
801 rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn);
802 pLineList->push_back( pData );
805 sal_Int32 LineListBox::GetEntryPos( sal_uInt16 nStyle ) const
807 for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
808 ImpLineListData* pData = (*pLineList)[ i ];
809 if ( pData )
811 if ( GetEntryStyle( i ) == nStyle )
813 size_t nPos = i;
814 if (!m_sNone.isEmpty())
815 nPos ++;
816 return (sal_Int32)nPos;
820 return LISTBOX_ENTRY_NOTFOUND;
823 sal_uInt16 LineListBox::GetEntryStyle( sal_Int32 nPos ) const
825 ImpLineListData* pData = (0 <= nPos && static_cast<size_t>(nPos) < pLineList->size()) ? (*pLineList)[ nPos ] : NULL;
826 return ( pData ) ? pData->GetStyle() : table::BorderLineStyle::NONE;
829 bool LineListBox::UpdatePaintLineColor()
831 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
832 Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor );
834 bool bRet = aNewCol != maPaintCol;
836 if( bRet )
837 maPaintCol = aNewCol;
839 return bRet;
842 void LineListBox::UpdateEntries( long nOldWidth )
844 SetUpdateMode( false );
846 UpdatePaintLineColor( );
848 sal_Int32 nSelEntry = GetSelectEntryPos();
849 sal_Int32 nTypePos = GetStylePos( nSelEntry, nOldWidth );
851 // Remove the old entries
852 while ( GetEntryCount( ) > 0 )
853 ListBox::RemoveEntry( 0 );
855 // Add the new entries based on the defined width
856 if (!m_sNone.isEmpty())
857 ListBox::InsertEntry( m_sNone, LISTBOX_APPEND );
859 sal_uInt16 n = 0;
860 sal_uInt16 nCount = pLineList->size( );
861 while ( n < nCount )
863 ImpLineListData* pData = (*pLineList)[ n ];
864 if ( pData && pData->GetMinWidth() <= m_nWidth )
866 Bitmap aBmp;
867 ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
868 pData->GetLine2ForWidth( m_nWidth ),
869 pData->GetDistForWidth( m_nWidth ),
870 GetColorLine1( GetEntryCount( ) ),
871 GetColorLine2( GetEntryCount( ) ),
872 GetColorDist( GetEntryCount( ) ),
873 pData->GetStyle(), aBmp );
874 ListBox::InsertEntry(OUString(" "), Image(aBmp), LISTBOX_APPEND);
875 if ( n == nTypePos )
876 SelectEntryPos( GetEntryCount() - 1 );
878 else if ( n == nTypePos )
879 SetNoSelection();
880 n++;
883 SetUpdateMode( true );
884 Invalidate();
887 Color LineListBox::GetColorLine1( sal_Int32 nPos )
889 Color rResult = GetPaintColor( );
891 sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
892 ImpLineListData* pData = (*pLineList)[ nStyle ];
893 if ( pData )
894 rResult = pData->GetColorLine1( GetColor( ) );
896 return rResult;
899 Color LineListBox::GetColorLine2( sal_Int32 nPos )
901 Color rResult = GetPaintColor( );
903 sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
904 ImpLineListData* pData = (*pLineList)[ nStyle ];
905 if ( pData )
906 rResult = pData->GetColorLine2( GetColor( ) );
908 return rResult;
911 Color LineListBox::GetColorDist( sal_Int32 nPos )
913 Color rResult = GetSettings().GetStyleSettings().GetFieldColor();
915 sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
916 ImpLineListData* pData = (*pLineList)[ nStyle ];
917 if ( pData )
918 rResult = pData->GetColorDist( GetColor( ), rResult );
920 return rResult;
923 void LineListBox::DataChanged( const DataChangedEvent& rDCEvt )
925 ListBox::DataChanged( rDCEvt );
927 if( ( rDCEvt.GetType() == DataChangedEventType::SETTINGS ) && ( rDCEvt.GetFlags() & AllSettingsFlags::STYLE ) )
928 UpdateEntries( m_nWidth );
931 FontNameBox::FontNameBox( vcl::Window* pParent, WinBits nWinStyle ) :
932 ComboBox( pParent, nWinStyle )
934 mpFontList = NULL;
935 mbWYSIWYG = false;
936 InitFontMRUEntriesFile();
939 VCL_BUILDER_DECL_FACTORY(FontNameBox)
941 bool bDropdown = VclBuilder::extractDropdown(rMap);
942 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
943 if (bDropdown)
944 nWinBits |= WB_DROPDOWN;
945 VclPtrInstance<FontNameBox> pListBox(pParent, nWinBits);
946 if (bDropdown)
947 pListBox->EnableAutoSize(true);
948 rRet = pListBox;
951 FontNameBox::~FontNameBox()
953 disposeOnce();
956 void FontNameBox::dispose()
958 if (mpFontList)
960 SaveMRUEntries (maFontMRUEntriesFile);
961 ImplDestroyFontList();
963 ComboBox::dispose();
966 void FontNameBox::SaveMRUEntries( const OUString& aFontMRUEntriesFile, sal_Unicode cSep ) const
968 OString aEntries(OUStringToOString(GetMRUEntries(cSep),
969 RTL_TEXTENCODING_UTF8));
971 if (aEntries.isEmpty() || aFontMRUEntriesFile.isEmpty())
972 return;
974 SvFileStream aStream;
975 aStream.Open( aFontMRUEntriesFile, StreamMode::WRITE | StreamMode::TRUNC );
976 if( ! (aStream.IsOpen() && aStream.IsWritable()) )
978 SAL_WARN("svtools.control", "FontNameBox::SaveMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed\n");
979 return;
982 aStream.SetLineDelimiter( LINEEND_LF );
983 aStream.WriteLine( aEntries );
984 aStream.WriteLine( OString() );
987 void FontNameBox::LoadMRUEntries( const OUString& aFontMRUEntriesFile, sal_Unicode cSep )
989 if( aFontMRUEntriesFile.isEmpty() )
990 return;
992 SvFileStream aStream( aFontMRUEntriesFile, StreamMode::READ );
993 if( ! aStream.IsOpen() )
995 SAL_WARN("svtools.control", "FontNameBox::LoadMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed\n");
996 return;
999 OString aLine;
1000 aStream.ReadLine( aLine );
1001 OUString aEntries = OStringToOUString(aLine,
1002 RTL_TEXTENCODING_UTF8);
1003 SetMRUEntries( aEntries, cSep );
1006 void FontNameBox::InitFontMRUEntriesFile()
1008 OUString sUserConfigDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}");
1009 rtl::Bootstrap::expandMacros(sUserConfigDir);
1011 maFontMRUEntriesFile = sUserConfigDir;
1012 if( !maFontMRUEntriesFile.isEmpty() )
1014 maFontMRUEntriesFile += FONTNAMEBOXMRUENTRIESFILE;
1018 void FontNameBox::ImplDestroyFontList()
1020 delete mpFontList;
1021 mpFontList = NULL;
1024 void FontNameBox::Fill( const FontList* pList )
1026 // store old text and clear box
1027 OUString aOldText = GetText();
1028 OUString rEntries = GetMRUEntries();
1029 bool bLoadFromFile = rEntries.isEmpty();
1030 Clear();
1032 ImplDestroyFontList();
1033 mpFontList = new ImplFontList;
1035 // insert fonts
1036 sal_uInt16 nFontCount = pList->GetFontNameCount();
1037 for ( sal_uInt16 i = 0; i < nFontCount; i++ )
1039 const vcl::FontInfo& rFontInfo = pList->GetFontName( i );
1040 sal_uLong nIndex = InsertEntry( rFontInfo.GetName() );
1041 if ( nIndex != LISTBOX_ERROR )
1043 if ( nIndex < mpFontList->size() ) {
1044 ImplFontList::iterator it = mpFontList->begin();
1045 ::std::advance( it, nIndex );
1046 mpFontList->insert( it, rFontInfo );
1047 } else {
1048 mpFontList->push_back( rFontInfo );
1053 if ( bLoadFromFile )
1054 LoadMRUEntries (maFontMRUEntriesFile);
1055 else
1056 SetMRUEntries( rEntries );
1058 ImplCalcUserItemSize();
1060 // restore text
1061 if (!aOldText.isEmpty())
1062 SetText( aOldText );
1065 void FontNameBox::EnableWYSIWYG( bool bEnable )
1067 if ( bEnable != mbWYSIWYG )
1069 mbWYSIWYG = bEnable;
1070 EnableUserDraw( mbWYSIWYG );
1071 ImplCalcUserItemSize();
1075 void FontNameBox::ImplCalcUserItemSize()
1077 Size aUserItemSz;
1078 if ( mbWYSIWYG && mpFontList )
1080 aUserItemSz = Size(MAXPREVIEWWIDTH, GetTextHeight() );
1081 aUserItemSz.Height() *= 16;
1082 aUserItemSz.Height() /= 10;
1084 SetUserItemSize( aUserItemSz );
1087 namespace
1089 long shrinkFontToFit(OUString &rSampleText, long nH, vcl::Font &rFont, OutputDevice &rDevice, Rectangle &rTextRect)
1091 long nWidth = 0;
1093 Size aSize( rFont.GetSize() );
1095 //Make sure it fits in the available height
1096 while (aSize.Height() > 0)
1098 if (!rDevice.GetTextBoundRect(rTextRect, rSampleText, 0, 0))
1099 break;
1100 if (rTextRect.GetHeight() <= nH)
1102 nWidth = rTextRect.GetWidth();
1103 break;
1106 aSize.Height() -= EXTRAFONTSIZE;
1107 rFont.SetSize(aSize);
1108 rDevice.SetFont(rFont);
1111 return nWidth;
1115 void FontNameBox::UserDraw( const UserDrawEvent& rUDEvt )
1117 assert( mpFontList );
1119 vcl::FontInfo& rInfo = (*mpFontList)[ rUDEvt.GetItemId() ];
1120 Point aTopLeft = rUDEvt.GetRect().TopLeft();
1121 long nX = aTopLeft.X();
1122 long nH = rUDEvt.GetRect().GetHeight();
1124 if ( mbWYSIWYG )
1126 nX += IMGOUTERTEXTSPACE;
1128 const bool bSymbolFont = isSymbolFont(rInfo);
1129 vcl::RenderContext* pRenderContext = rUDEvt.GetRenderContext();
1131 Color aTextColor = pRenderContext->GetTextColor();
1132 vcl::Font aOldFont(pRenderContext->GetFont());
1133 Size aSize( aOldFont.GetSize() );
1134 aSize.Height() += EXTRAFONTSIZE;
1135 vcl::Font aFont( rInfo );
1136 aFont.SetSize( aSize );
1137 pRenderContext->SetFont(aFont);
1138 pRenderContext->SetTextColor(aTextColor);
1140 bool bUsingCorrectFont = true;
1141 Rectangle aTextRect;
1143 // Preview the font name
1144 OUString sFontName = rInfo.GetName();
1146 //If it shouldn't or can't draw its own name because it doesn't have the glyphs
1147 if (!canRenderNameOfSelectedFont(*pRenderContext))
1148 bUsingCorrectFont = false;
1149 else
1151 //Make sure it fits in the available height, shrinking the font if necessary
1152 bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, *pRenderContext, aTextRect) != 0;
1155 if (!bUsingCorrectFont)
1157 pRenderContext->SetFont(aOldFont);
1158 pRenderContext->GetTextBoundRect(aTextRect, sFontName, 0, 0);
1161 long nTextHeight = aTextRect.GetHeight();
1162 long nDesiredGap = (nH-nTextHeight)/2;
1163 long nVertAdjust = nDesiredGap - aTextRect.Top();
1164 Point aPos( nX, aTopLeft.Y() + nVertAdjust );
1165 pRenderContext->DrawText(aPos, sFontName);
1166 long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW;
1168 if (!bUsingCorrectFont)
1169 pRenderContext->SetFont(aFont);
1171 OUString sSampleText;
1173 if (!bSymbolFont)
1175 const bool bNameBeginsWithLatinText = rInfo.GetName()[0] <= 'z';
1177 if (bNameBeginsWithLatinText || !bUsingCorrectFont)
1178 sSampleText = makeShortRepresentativeTextForSelectedFont(*pRenderContext);
1181 //If we're not a symbol font, but could neither render our own name and
1182 //we can't determine what script it would like to render, then try a
1183 //few well known scripts
1184 if (sSampleText.isEmpty() && !bUsingCorrectFont)
1186 static const UScriptCode aScripts[] =
1188 USCRIPT_ARABIC,
1189 USCRIPT_HEBREW,
1191 USCRIPT_BENGALI,
1192 USCRIPT_GURMUKHI,
1193 USCRIPT_GUJARATI,
1194 USCRIPT_ORIYA,
1195 USCRIPT_TAMIL,
1196 USCRIPT_TELUGU,
1197 USCRIPT_KANNADA,
1198 USCRIPT_MALAYALAM,
1199 USCRIPT_SINHALA,
1200 USCRIPT_DEVANAGARI,
1202 USCRIPT_THAI,
1203 USCRIPT_LAO,
1204 USCRIPT_GEORGIAN,
1205 USCRIPT_TIBETAN,
1206 USCRIPT_SYRIAC,
1207 USCRIPT_MYANMAR,
1208 USCRIPT_ETHIOPIC,
1209 USCRIPT_KHMER,
1210 USCRIPT_MONGOLIAN,
1212 USCRIPT_KOREAN,
1213 USCRIPT_JAPANESE,
1214 USCRIPT_HAN,
1215 USCRIPT_SIMPLIFIED_HAN,
1216 USCRIPT_TRADITIONAL_HAN,
1218 USCRIPT_GREEK
1221 for (size_t i = 0; i < SAL_N_ELEMENTS(aScripts); ++i)
1223 OUString sText = makeShortRepresentativeTextForScript(aScripts[i]);
1224 if (!sText.isEmpty())
1226 bool bHasSampleTextGlyphs = (-1 == pRenderContext->HasGlyphs(aFont, sText));
1227 if (bHasSampleTextGlyphs)
1229 sSampleText = sText;
1230 break;
1235 static const UScriptCode aMinimalScripts[] =
1237 USCRIPT_HEBREW, //e.g. biblical hebrew
1238 USCRIPT_GREEK
1241 for (size_t i = 0; i < SAL_N_ELEMENTS(aMinimalScripts); ++i)
1243 OUString sText = makeShortMinimalTextForScript(aMinimalScripts[i]);
1244 if (!sText.isEmpty())
1246 bool bHasSampleTextGlyphs = (-1 == pRenderContext->HasGlyphs(aFont, sText));
1247 if (bHasSampleTextGlyphs)
1249 sSampleText = sText;
1250 break;
1256 //If we're a symbol font, or for some reason the font still couldn't
1257 //render something representative of what it would like to render then
1258 //make up some semi-random text that it *can* display
1259 if (bSymbolFont || (!bUsingCorrectFont && sSampleText.isEmpty()))
1260 sSampleText = makeShortRepresentativeSymbolTextForSelectedFont(*pRenderContext);
1262 if (!sSampleText.isEmpty())
1264 const Size &rItemSize = rUDEvt.GetWindow()->GetOutputSize();
1266 //leave a little border at the edge
1267 long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE;
1268 if (nSpace >= 0)
1270 //Make sure it fits in the available height, and get how wide that would be
1271 long nWidth = shrinkFontToFit(sSampleText, nH, aFont, *pRenderContext, aTextRect);
1272 //Chop letters off until it fits in the available width
1273 while (nWidth > nSpace || nWidth > MAXPREVIEWWIDTH)
1275 sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
1276 nWidth = pRenderContext->GetTextBoundRect(aTextRect, sSampleText, 0, 0) ?
1277 aTextRect.GetWidth() : 0;
1280 //center the text on the line
1281 if (!sSampleText.isEmpty() && nWidth)
1283 nTextHeight = aTextRect.GetHeight();
1284 nDesiredGap = (nH-nTextHeight)/2;
1285 nVertAdjust = nDesiredGap - aTextRect.Top();
1286 aPos = Point(nTextX + nSpace - nWidth, aTopLeft.Y() + nVertAdjust);
1287 pRenderContext->DrawText(aPos, sSampleText);
1292 pRenderContext->SetFont(aOldFont);
1293 DrawEntry( rUDEvt, false, false); // draw separator
1295 else
1297 DrawEntry( rUDEvt, true, true );
1301 FontStyleBox::FontStyleBox(vcl::Window* pParent, WinBits nBits)
1302 : ComboBox(pParent, nBits)
1304 //Use the standard texts to get an optimal size and stick to that size.
1305 //That should stop the character dialog dancing around.
1306 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_LIGHT));
1307 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_LIGHT_ITALIC));
1308 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_NORMAL));
1309 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_NORMAL_ITALIC));
1310 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BOLD));
1311 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BOLD_ITALIC));
1312 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BLACK));
1313 InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BLACK_ITALIC));
1314 aOptimalSize = GetOptimalSize();
1315 Clear();
1318 Size FontStyleBox::GetOptimalSize() const
1320 if (aOptimalSize.Width() || aOptimalSize.Height())
1321 return aOptimalSize;
1322 return ComboBox::GetOptimalSize();
1325 VCL_BUILDER_DECL_FACTORY(FontStyleBox)
1327 bool bDropdown = VclBuilder::extractDropdown(rMap);
1328 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
1329 if (bDropdown)
1330 nWinBits |= WB_DROPDOWN;
1331 VclPtrInstance<FontStyleBox> pListBox(pParent, nWinBits);
1332 if (bDropdown)
1333 pListBox->EnableAutoSize(true);
1334 rRet = pListBox;
1337 void FontStyleBox::Select()
1339 // keep text over fill operation
1340 aLastStyle = GetText();
1341 ComboBox::Select();
1344 void FontStyleBox::LoseFocus()
1346 // keep text over fill operation
1347 aLastStyle = GetText();
1348 ComboBox::LoseFocus();
1351 void FontStyleBox::Modify()
1353 CharClass aChrCls( ::comphelper::getProcessComponentContext(),
1354 GetSettings().GetLanguageTag() );
1355 OUString aStr = GetText();
1356 sal_Int32 nEntryCount = GetEntryCount();
1358 if ( GetEntryPos( aStr ) == COMBOBOX_ENTRY_NOTFOUND )
1360 aStr = aChrCls.uppercase(aStr);
1361 for ( sal_Int32 i = 0; i < nEntryCount; i++ )
1363 OUString aEntryText = aChrCls.uppercase(GetEntry(i));
1365 if ( aStr == aEntryText )
1367 SetText( GetEntry( i ) );
1368 break;
1373 ComboBox::Modify();
1376 void FontStyleBox::Fill( const OUString& rName, const FontList* pList )
1378 // note: this method must call ComboBox::SetText(),
1379 // else aLastStyle will overwritten
1380 // store prior selection position and clear box
1381 OUString aOldText = GetText();
1382 sal_Int32 nPos = GetEntryPos( aOldText );
1383 Clear();
1385 // does a font with this name already exist?
1386 sal_Handle hFontInfo = pList->GetFirstFontInfo( rName );
1387 if ( hFontInfo )
1389 OUString aStyleText;
1390 FontWeight eLastWeight = WEIGHT_DONTKNOW;
1391 FontItalic eLastItalic = ITALIC_NONE;
1392 FontWidth eLastWidth = WIDTH_DONTKNOW;
1393 bool bNormal = false;
1394 bool bItalic = false;
1395 bool bBold = false;
1396 bool bBoldItalic = false;
1397 bool bInsert = false;
1398 vcl::FontInfo aInfo;
1399 while ( hFontInfo )
1401 aInfo = FontList::GetFontInfo( hFontInfo );
1403 FontWeight eWeight = aInfo.GetWeight();
1404 FontItalic eItalic = aInfo.GetItalic();
1405 FontWidth eWidth = aInfo.GetWidthType();
1406 // Only if the attributes are different, we insert the
1407 // Font to avoid double Entries in different languages
1408 if ( (eWeight != eLastWeight) || (eItalic != eLastItalic) ||
1409 (eWidth != eLastWidth) )
1411 if ( bInsert )
1412 InsertEntry( aStyleText );
1414 if ( eWeight <= WEIGHT_NORMAL )
1416 if ( eItalic != ITALIC_NONE )
1417 bItalic = true;
1418 else
1419 bNormal = true;
1421 else
1423 if ( eItalic != ITALIC_NONE )
1424 bBoldItalic = true;
1425 else
1426 bBold = true;
1429 // For wrong StyleNames we replace this with the correct once
1430 aStyleText = pList->GetStyleName( aInfo );
1431 bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
1432 if ( !bInsert )
1434 aStyleText = pList->GetStyleName( eWeight, eItalic );
1435 bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
1438 eLastWeight = eWeight;
1439 eLastItalic = eItalic;
1440 eLastWidth = eWidth;
1442 else
1444 if ( bInsert )
1446 // If we have two names for the same attributes
1447 // we prefer the translated standard names
1448 const OUString& rAttrStyleText = pList->GetStyleName( eWeight, eItalic );
1449 if (rAttrStyleText != aStyleText)
1451 OUString aTempStyleText = pList->GetStyleName( aInfo );
1452 if (rAttrStyleText == aTempStyleText)
1453 aStyleText = rAttrStyleText;
1454 bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
1459 if ( !bItalic && (aStyleText == pList->GetItalicStr()) )
1460 bItalic = true;
1461 else if ( !bBold && (aStyleText == pList->GetBoldStr()) )
1462 bBold = true;
1463 else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) )
1464 bBoldItalic = true;
1466 hFontInfo = FontList::GetNextFontInfo( hFontInfo );
1469 if ( bInsert )
1470 InsertEntry( aStyleText );
1472 // certain style as copy
1473 if ( bNormal )
1475 if ( !bItalic )
1476 InsertEntry( pList->GetItalicStr() );
1477 if ( !bBold )
1478 InsertEntry( pList->GetBoldStr() );
1480 if ( !bBoldItalic )
1482 if ( bNormal || bItalic || bBold )
1483 InsertEntry( pList->GetBoldItalicStr() );
1485 if (!aOldText.isEmpty())
1487 if ( GetEntryPos( aLastStyle ) != LISTBOX_ENTRY_NOTFOUND )
1488 ComboBox::SetText( aLastStyle );
1489 else
1491 if ( nPos >= GetEntryCount() )
1492 ComboBox::SetText( GetEntry( 0 ) );
1493 else
1494 ComboBox::SetText( GetEntry( nPos ) );
1498 else
1500 // insert standard styles if no font
1501 InsertEntry( pList->GetNormalStr() );
1502 InsertEntry( pList->GetItalicStr() );
1503 InsertEntry( pList->GetBoldStr() );
1504 InsertEntry( pList->GetBoldItalicStr() );
1505 if (!aOldText.isEmpty())
1507 if ( nPos > GetEntryCount() )
1508 ComboBox::SetText( GetEntry( 0 ) );
1509 else
1510 ComboBox::SetText( GetEntry( nPos ) );
1515 FontSizeBox::FontSizeBox( vcl::Window* pParent, WinBits nWinSize ) :
1516 MetricBox( pParent, nWinSize )
1518 ImplInit();
1521 VCL_BUILDER_DECL_FACTORY(FontSizeBox)
1523 bool bDropdown = VclBuilder::extractDropdown(rMap);
1524 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
1525 if (bDropdown)
1526 nWinBits |= WB_DROPDOWN;
1527 VclPtrInstance<FontSizeBox> pListBox(pParent, nWinBits);
1528 if (bDropdown)
1529 pListBox->EnableAutoSize(true);
1530 rRet = pListBox;
1533 void FontSizeBox::ImplInit()
1535 EnableAutocomplete( false );
1537 bRelativeMode = false;
1538 bPtRelative = false;
1539 bRelative = false;
1540 bStdSize = false;
1541 pFontList = NULL;
1543 SetShowTrailingZeros( false );
1544 SetDecimalDigits( 1 );
1545 SetMin( 20 );
1546 SetMax( 9999 );
1547 SetProminentEntryType( ProminentEntry::MIDDLE );
1550 void FontSizeBox::Reformat()
1552 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1553 if ( !bRelativeMode || !aFontSizeNames.IsEmpty() )
1555 long nNewValue = aFontSizeNames.Name2Size( GetText() );
1556 if ( nNewValue)
1558 mnLastValue = nNewValue;
1559 return;
1563 MetricBox::Reformat();
1566 void FontSizeBox::Modify()
1568 MetricBox::Modify();
1570 if ( bRelativeMode )
1572 OUString aStr = comphelper::string::stripStart(GetText(), ' ');
1574 bool bNewMode = bRelative;
1575 bool bOldPtRelMode = bPtRelative;
1577 if ( bRelative )
1579 bPtRelative = false;
1580 const sal_Unicode* pStr = aStr.getStr();
1581 while ( *pStr )
1583 if ( ((*pStr < '0') || (*pStr > '9')) && (*pStr != '%') && !unicode::isSpace(*pStr) )
1585 if ( ('-' == *pStr || '+' == *pStr) && !bPtRelative )
1586 bPtRelative = true;
1587 else if ( bPtRelative && 'p' == *pStr && 't' == *++pStr )
1589 else
1591 bNewMode = false;
1592 break;
1595 pStr++;
1598 else if (!aStr.isEmpty())
1600 if ( -1 != aStr.indexOf('%') )
1602 bNewMode = true;
1603 bPtRelative = false;
1606 if ( '-' == aStr[0] || '+' == aStr[0] )
1608 bNewMode = true;
1609 bPtRelative = true;
1613 if ( bNewMode != bRelative || bPtRelative != bOldPtRelMode )
1614 SetRelative( bNewMode );
1618 void FontSizeBox::Fill( const vcl::FontInfo* pInfo, const FontList* pList )
1620 // remember for relative mode
1621 pFontList = pList;
1623 // no font sizes need to be set for relative mode
1624 if ( bRelative )
1625 return;
1627 // query font sizes
1628 const sal_IntPtr* pTempAry;
1629 const sal_IntPtr* pAry = 0;
1631 if( pInfo )
1633 aFontInfo = *pInfo;
1634 pAry = pList->GetSizeAry( *pInfo );
1636 else
1638 pAry = FontList::GetStdSizeAry();
1641 // first insert font size names (for simplified/traditional chinese)
1642 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1643 if ( pAry == FontList::GetStdSizeAry() )
1645 // for standard sizes we don't need to bother
1646 if ( bStdSize && GetEntryCount() && aFontSizeNames.IsEmpty() )
1647 return;
1648 bStdSize = true;
1650 else
1651 bStdSize = false;
1653 Selection aSelection = GetSelection();
1654 OUString aStr = GetText();
1656 Clear();
1657 sal_Int32 nPos = 0;
1659 if ( !aFontSizeNames.IsEmpty() )
1661 if ( pAry == FontList::GetStdSizeAry() )
1663 // for scalable fonts all font size names
1664 sal_uLong nCount = aFontSizeNames.Count();
1665 for( sal_uLong i = 0; i < nCount; i++ )
1667 OUString aSizeName = aFontSizeNames.GetIndexName( i );
1668 sal_IntPtr nSize = aFontSizeNames.GetIndexSize( i );
1669 ComboBox::InsertEntry( aSizeName, nPos );
1670 ComboBox::SetEntryData( nPos, reinterpret_cast<void*>(-nSize) ); // mark as special
1671 nPos++;
1674 else
1676 // for fixed size fonts only selectable font size names
1677 pTempAry = pAry;
1678 while ( *pTempAry )
1680 OUString aSizeName = aFontSizeNames.Size2Name( *pTempAry );
1681 if ( !aSizeName.isEmpty() )
1683 ComboBox::InsertEntry( aSizeName, nPos );
1684 ComboBox::SetEntryData( nPos, reinterpret_cast<void*>(-(*pTempAry)) ); // mark as special
1685 nPos++;
1687 pTempAry++;
1692 // then insert numerical font size values
1693 pTempAry = pAry;
1694 while ( *pTempAry )
1696 InsertValue( *pTempAry, FUNIT_NONE, nPos );
1697 ComboBox::SetEntryData( nPos, reinterpret_cast<void*>(*pTempAry) );
1698 nPos++;
1699 pTempAry++;
1702 SetText( aStr );
1703 SetSelection( aSelection );
1706 void FontSizeBox::EnableRelativeMode( sal_uInt16 nMin, sal_uInt16 nMax, sal_uInt16 nStep )
1708 bRelativeMode = true;
1709 nRelMin = nMin;
1710 nRelMax = nMax;
1711 nRelStep = nStep;
1712 SetUnit( FUNIT_POINT );
1715 void FontSizeBox::EnablePtRelativeMode( short nMin, short nMax, short nStep )
1717 bRelativeMode = true;
1718 nPtRelMin = nMin;
1719 nPtRelMax = nMax;
1720 nPtRelStep = nStep;
1721 SetUnit( FUNIT_POINT );
1724 void FontSizeBox::SetRelative( bool bNewRelative )
1726 if ( bRelativeMode )
1728 Selection aSelection = GetSelection();
1729 OUString aStr = comphelper::string::stripStart(GetText(), ' ');
1731 if ( bNewRelative )
1733 bRelative = true;
1734 bStdSize = false;
1736 if ( bPtRelative )
1738 Clear(); //clear early because SetDecimalDigits is a slow recalc
1740 SetDecimalDigits( 1 );
1741 SetMin( nPtRelMin );
1742 SetMax( nPtRelMax );
1743 SetUnit( FUNIT_POINT );
1745 short i = nPtRelMin, n = 0;
1746 // JP 30.06.98: more than 100 values are not useful
1747 while ( i <= nPtRelMax && n++ < 100 )
1749 InsertValue( i );
1750 i = i + nPtRelStep;
1753 else
1755 Clear(); //clear early because SetDecimalDigits is a slow recalc
1757 SetDecimalDigits( 0 );
1758 SetMin( nRelMin );
1759 SetMax( nRelMax );
1760 SetUnit( FUNIT_PERCENT );
1762 sal_uInt16 i = nRelMin;
1763 while ( i <= nRelMax )
1765 InsertValue( i );
1766 i = i + nRelStep;
1770 else
1772 if (pFontList)
1773 Clear(); //clear early because SetDecimalDigits is a slow recalc
1774 bRelative = bPtRelative = false;
1775 SetDecimalDigits( 1 );
1776 SetMin( 20 );
1777 SetMax( 9999 );
1778 SetUnit( FUNIT_POINT );
1779 if ( pFontList )
1780 Fill( &aFontInfo, pFontList );
1783 SetText( aStr );
1784 SetSelection( aSelection );
1788 OUString FontSizeBox::CreateFieldText( sal_Int64 nValue ) const
1790 OUString sRet( MetricBox::CreateFieldText( nValue ) );
1791 if ( bRelativeMode && bPtRelative && (0 <= nValue) && !sRet.isEmpty() )
1792 sRet = "+" + sRet;
1793 return sRet;
1796 void FontSizeBox::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit )
1798 if ( !bRelative )
1800 sal_Int64 nTempValue = MetricField::ConvertValue( nNewValue, GetBaseValue(), GetDecimalDigits(), eInUnit, GetUnit() );
1801 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1802 // conversion loses precision; however font sizes should
1803 // never have a problem with that
1804 OUString aName = aFontSizeNames.Size2Name( static_cast<long>(nTempValue) );
1805 if ( !aName.isEmpty() && (GetEntryPos( aName ) != LISTBOX_ENTRY_NOTFOUND) )
1807 mnLastValue = nTempValue;
1808 SetText( aName );
1809 mnFieldValue = mnLastValue;
1810 SetEmptyFieldValueData( false );
1811 return;
1815 MetricBox::SetValue( nNewValue, eInUnit );
1818 void FontSizeBox::SetValue( sal_Int64 nNewValue )
1820 SetValue( nNewValue, FUNIT_NONE );
1823 sal_Int64 FontSizeBox::GetValue( FieldUnit eOutUnit ) const
1825 if ( !bRelative )
1827 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1828 sal_Int64 nValue = aFontSizeNames.Name2Size( GetText() );
1829 if ( nValue)
1830 return MetricField::ConvertValue( nValue, GetBaseValue(), GetDecimalDigits(), GetUnit(), eOutUnit );
1833 return MetricBox::GetValue( eOutUnit );
1836 sal_Int64 FontSizeBox::GetValue() const
1838 // implementation not inline, because it is a virtual function
1839 return GetValue( FUNIT_NONE );
1842 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */