1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <config_folders.h>
21
22 #include <i18nutil/unicode.hxx>
23 #include <tools/stream.hxx>
24 #include <vcl/builder.hxx>
25 #include <vcl/customweld.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/field.hxx>
29 #include <vcl/settings.hxx>
30 #include <vcl/image.hxx>
31 #include <vcl/virdev.hxx>
32 #include <sal/macros.h>
33 #include <sal/log.hxx>
34 #include <comphelper/processfactory.hxx>
35 #include <comphelper/string.hxx>
36 #include <unotools/charclass.hxx>
37 #include <unotools/fontoptions.hxx>
38 #include <unotools/localedatawrapper.hxx>
39
40 #include <svtools/borderline.hxx>
41 #include <svtools/sampletext.hxx>
42 #include <svtools/svtresid.hxx>
43 #include <svtools/strings.hrc>
44 #include <svtools/ctrlbox.hxx>
45 #include <svtools/ctrltool.hxx>
46 #include <svtools/borderhelper.hxx>
47 #include <svtools/valueset.hxx>
48
49 #include <basegfx/polygon/b2dpolygon.hxx>
50 #include <basegfx/polygon/b2dpolygontools.hxx>
51 #include <editeng/borderline.hxx>
52
53 #include <rtl/bootstrap.hxx>
54
55 #include <borderline.hrc>
56
57 #include <stdio.h>
58
59 #define IMGOUTERTEXTSPACE 5
60 #define EXTRAFONTSIZE 5
61 #define GAPTOEXTRAPREVIEW 10
62 #define MAXPREVIEWWIDTH 120
63 #define MINGAPWIDTH 2
64
65 #define FONTNAMEBOXMRUENTRIESFILE "/user/config/fontnameboxmruentries"
66
67
BorderWidthImpl(BorderWidthImplFlags nFlags,double nRate1,double nRate2,double nRateGap)68 BorderWidthImpl::BorderWidthImpl( BorderWidthImplFlags nFlags, double nRate1, double nRate2, double nRateGap ):
69 m_nFlags( nFlags ),
70 m_nRate1( nRate1 ),
71 m_nRate2( nRate2 ),
72 m_nRateGap( nRateGap )
73 {
74 }
75
operator ==(const BorderWidthImpl & r) const76 bool BorderWidthImpl::operator== ( const BorderWidthImpl& r ) const
77 {
78 return ( m_nFlags == r.m_nFlags ) &&
79 ( m_nRate1 == r.m_nRate1 ) &&
80 ( m_nRate2 == r.m_nRate2 ) &&
81 ( m_nRateGap == r.m_nRateGap );
82 }
83
GetLine1(long nWidth) const84 long BorderWidthImpl::GetLine1( long nWidth ) const
85 {
86 long result = static_cast<long>(m_nRate1);
87 if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 )
88 {
89 long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
90 long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
91 result = std::max<long>(0,
92 static_cast<long>((m_nRate1 * nWidth) + 0.5)
93 - (nConstant2 + nConstantD));
94 if (result == 0 && m_nRate1 > 0.0 && nWidth > 0)
95 { // fdo#51777: hack to essentially treat 1 twip DOUBLE border
96 result = 1; // as 1 twip SINGLE border
97 }
98 }
99 return result;
100 }
101
GetLine2(long nWidth) const102 long BorderWidthImpl::GetLine2( long nWidth ) const
103 {
104 long result = static_cast<long>(m_nRate2);
105 if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2)
106 {
107 long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
108 long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
109 result = std::max<long>(0,
110 static_cast<long>((m_nRate2 * nWidth) + 0.5)
111 - (nConstant1 + nConstantD));
112 }
113 return result;
114 }
115
GetGap(long nWidth) const116 long BorderWidthImpl::GetGap( long nWidth ) const
117 {
118 long result = static_cast<long>(m_nRateGap);
119 if ( m_nFlags & BorderWidthImplFlags::CHANGE_DIST )
120 {
121 long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
122 long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
123 result = std::max<long>(0,
124 static_cast<long>((m_nRateGap * nWidth) + 0.5)
125 - (nConstant1 + nConstant2));
126 }
127
128 // Avoid having too small distances (less than 0.1pt)
129 if ( result < MINGAPWIDTH && m_nRate1 > 0 && m_nRate2 > 0 )
130 result = MINGAPWIDTH;
131
132 return result;
133 }
134
lcl_getGuessedWidth(long nTested,double nRate,bool bChanging)135 static double lcl_getGuessedWidth( long nTested, double nRate, bool bChanging )
136 {
137 double nWidth = -1.0;
138 if ( bChanging )
139 nWidth = double( nTested ) / nRate;
140 else
141 {
142 if ( rtl::math::approxEqual(double( nTested ), nRate) )
143 nWidth = nRate;
144 }
145
146 return nWidth;
147 }
148
GuessWidth(long nLine1,long nLine2,long nGap)149 long BorderWidthImpl::GuessWidth( long nLine1, long nLine2, long nGap )
150 {
151 std::vector< double > aToCompare;
152 bool bInvalid = false;
153
154 bool bLine1Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 );
155 double nWidth1 = lcl_getGuessedWidth( nLine1, m_nRate1, bLine1Change );
156 if ( bLine1Change )
157 aToCompare.push_back( nWidth1 );
158 else if (nWidth1 < 0)
159 bInvalid = true;
160
161 bool bLine2Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2 );
162 double nWidth2 = lcl_getGuessedWidth( nLine2, m_nRate2, bLine2Change );
163 if ( bLine2Change )
164 aToCompare.push_back( nWidth2 );
165 else if (nWidth2 < 0)
166 bInvalid = true;
167
168 bool bGapChange = bool( m_nFlags & BorderWidthImplFlags::CHANGE_DIST );
169 double nWidthGap = lcl_getGuessedWidth( nGap, m_nRateGap, bGapChange );
170 if ( bGapChange && nGap >= MINGAPWIDTH )
171 aToCompare.push_back( nWidthGap );
172 else if ( !bGapChange && nWidthGap < 0 )
173 bInvalid = true;
174
175 // non-constant line width factors must sum to 1
176 assert((((bLine1Change) ? m_nRate1 : 0) +
177 ((bLine2Change) ? m_nRate2 : 0) +
178 ((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001 );
179
180 double nWidth = 0.0;
181 if ( (!bInvalid) && (!aToCompare.empty()) )
182 {
183 nWidth = *aToCompare.begin();
184 for (auto const& elem : aToCompare)
185 {
186 bInvalid = ( nWidth != elem );
187 if (bInvalid)
188 break;
189 }
190 nWidth = bInvalid ? 0.0 : nLine1 + nLine2 + nGap;
191 }
192
193 return nWidth;
194 }
195
lclDrawPolygon(OutputDevice & rDev,const basegfx::B2DPolygon & rPolygon,long nWidth,SvxBorderLineStyle nDashing)196 static void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, long nWidth, SvxBorderLineStyle nDashing )
197 {
198 AntialiasingFlags nOldAA = rDev.GetAntialiasing();
199 rDev.SetAntialiasing( nOldAA & ~AntialiasingFlags::EnableB2dDraw );
200
201 long nPix = rDev.PixelToLogic(Size(1, 1)).Width();
202 basegfx::B2DPolyPolygon aPolygons = svtools::ApplyLineDashing(rPolygon, nDashing, nPix);
203
204 // Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line
205 if (rDev.GetMapMode().GetMapUnit() == MapUnit::MapPixel && nWidth == nPix)
206 nWidth = 0;
207
208 for ( sal_uInt32 i = 0; i < aPolygons.count( ); i++ )
209 {
210 const basegfx::B2DPolygon& aDash = aPolygons.getB2DPolygon( i );
211 basegfx::B2DPoint aStart = aDash.getB2DPoint( 0 );
212 basegfx::B2DPoint aEnd = aDash.getB2DPoint( aDash.count() - 1 );
213
214 basegfx::B2DVector aVector( aEnd - aStart );
215 aVector.normalize( );
216 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
217
218 const basegfx::B2DVector aWidthOffset( double( nWidth ) / 2 * aPerpendicular);
219 basegfx::B2DPolygon aDashPolygon;
220 aDashPolygon.append( aStart + aWidthOffset );
221 aDashPolygon.append( aEnd + aWidthOffset );
222 aDashPolygon.append( aEnd - aWidthOffset );
223 aDashPolygon.append( aStart - aWidthOffset );
224 aDashPolygon.setClosed( true );
225
226 rDev.DrawPolygon( aDashPolygon );
227 }
228
229 rDev.SetAntialiasing( nOldAA );
230 }
231
232 namespace svtools {
233
234 /**
235 * Dashing array must start with a line width and end with a blank width.
236 */
GetDashing(SvxBorderLineStyle nDashing)237 static std::vector<double> GetDashing( SvxBorderLineStyle nDashing )
238 {
239 std::vector<double> aPattern;
240 switch (nDashing)
241 {
242 case SvxBorderLineStyle::DOTTED:
243 aPattern.push_back( 1.0 ); // line
244 aPattern.push_back( 2.0 ); // blank
245 break;
246 case SvxBorderLineStyle::DASHED:
247 aPattern.push_back( 16.0 ); // line
248 aPattern.push_back( 5.0 ); // blank
249 break;
250 case SvxBorderLineStyle::FINE_DASHED:
251 aPattern.push_back( 6.0 ); // line
252 aPattern.push_back( 2.0 ); // blank
253 break;
254 case SvxBorderLineStyle::DASH_DOT:
255 aPattern.push_back( 16.0 ); // line
256 aPattern.push_back( 5.0 ); // blank
257 aPattern.push_back( 5.0 ); // line
258 aPattern.push_back( 5.0 ); // blank
259 break;
260 case SvxBorderLineStyle::DASH_DOT_DOT:
261 aPattern.push_back( 16.0 ); // line
262 aPattern.push_back( 5.0 ); // blank
263 aPattern.push_back( 5.0 ); // line
264 aPattern.push_back( 5.0 ); // blank
265 aPattern.push_back( 5.0 ); // line
266 aPattern.push_back( 5.0 ); // blank
267 break;
268 default:
269 ;
270 }
271
272 return aPattern;
273 }
274
275 namespace {
276
277 class ApplyScale
278 {
279 double const mfScale;
280 public:
ApplyScale(double fScale)281 explicit ApplyScale( double fScale ) : mfScale(fScale) {}
operator ()(double & rVal)282 void operator() ( double& rVal )
283 {
284 rVal *= mfScale;
285 }
286 };
287
288 }
289
GetLineDashing(SvxBorderLineStyle nDashing,double fScale)290 std::vector<double> GetLineDashing( SvxBorderLineStyle nDashing, double fScale )
291 {
292 std::vector<double> aPattern = GetDashing(nDashing);
293 std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
294 return aPattern;
295 }
296
ApplyLineDashing(const basegfx::B2DPolygon & rPolygon,SvxBorderLineStyle nDashing,double fScale)297 basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, SvxBorderLineStyle nDashing, double fScale )
298 {
299 std::vector<double> aPattern = GetDashing(nDashing);
300 std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
301
302 basegfx::B2DPolyPolygon aPolygons;
303
304 if (aPattern.empty())
305 aPolygons.append(rPolygon);
306 else
307 basegfx::utils::applyLineDashing(rPolygon, aPattern, &aPolygons);
308
309 return aPolygons;
310 }
311
DrawLine(OutputDevice & rDev,const Point & rP1,const Point & rP2,sal_uInt32 nWidth,SvxBorderLineStyle nDashing)312 void DrawLine( OutputDevice& rDev, const Point& rP1, const Point& rP2,
313 sal_uInt32 nWidth, SvxBorderLineStyle nDashing )
314 {
315 DrawLine( rDev, basegfx::B2DPoint( rP1.X(), rP1.Y() ),
316 basegfx::B2DPoint( rP2.X(), rP2.Y( ) ), nWidth, nDashing );
317 }
318
DrawLine(OutputDevice & rDev,const basegfx::B2DPoint & rP1,const basegfx::B2DPoint & rP2,sal_uInt32 nWidth,SvxBorderLineStyle nDashing)319 void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rP1, const basegfx::B2DPoint& rP2,
320 sal_uInt32 nWidth, SvxBorderLineStyle nDashing )
321 {
322 basegfx::B2DPolygon aPolygon;
323 aPolygon.append( rP1 );
324 aPolygon.append( rP2 );
325 lclDrawPolygon( rDev, aPolygon, nWidth, nDashing );
326 }
327
328 }
329
FontNameBox(vcl::Window * pParent,WinBits nWinStyle)330 FontNameBox::FontNameBox( vcl::Window* pParent, WinBits nWinStyle ) :
331 ComboBox( pParent, nWinStyle )
332 {
333 EnableSelectAll();
334 mbWYSIWYG = false;
335 InitFontMRUEntriesFile();
336 }
337
makeFontNameBox(VclPtr<vcl::Window> & rRet,const VclPtr<vcl::Window> & pParent,VclBuilder::stringmap & rMap)338 extern "C" SAL_DLLPUBLIC_EXPORT void makeFontNameBox(VclPtr<vcl::Window> & rRet, const VclPtr<vcl::Window> & pParent, VclBuilder::stringmap & rMap)
339 {
340 static_assert(std::is_same_v<std::remove_pointer_t<VclBuilder::customMakeWidget>,
341 decltype(makeFontNameBox)>);
342 bool bDropdown = BuilderUtils::extractDropdown(rMap);
343 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
344 if (bDropdown)
345 nWinBits |= WB_DROPDOWN;
346 VclPtrInstance<FontNameBox> pListBox(pParent, nWinBits);
347 if (bDropdown)
348 pListBox->EnableAutoSize(true);
349 rRet = pListBox;
350 }
351
~FontNameBox()352 FontNameBox::~FontNameBox()
353 {
354 disposeOnce();
355 }
356
dispose()357 void FontNameBox::dispose()
358 {
359 if (mpFontList)
360 {
361 SaveMRUEntries (maFontMRUEntriesFile);
362 ImplDestroyFontList();
363 }
364 ComboBox::dispose();
365 }
366
SaveMRUEntries(const OUString & aFontMRUEntriesFile) const367 void FontNameBox::SaveMRUEntries( const OUString& aFontMRUEntriesFile ) const
368 {
369 OString aEntries(OUStringToOString(GetMRUEntries(),
370 RTL_TEXTENCODING_UTF8));
371
372 if (aEntries.isEmpty() || aFontMRUEntriesFile.isEmpty())
373 return;
374
375 SvFileStream aStream;
376 aStream.Open( aFontMRUEntriesFile, StreamMode::WRITE | StreamMode::TRUNC );
377 if( ! (aStream.IsOpen() && aStream.IsWritable()) )
378 {
379 SAL_INFO("svtools.control", "FontNameBox::SaveMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed");
380 return;
381 }
382
383 aStream.SetLineDelimiter( LINEEND_LF );
384 aStream.WriteLine( aEntries );
385 aStream.WriteLine( OString() );
386 }
387
LoadMRUEntries(const OUString & aFontMRUEntriesFile)388 void FontNameBox::LoadMRUEntries( const OUString& aFontMRUEntriesFile )
389 {
390 if (aFontMRUEntriesFile.isEmpty())
391 return;
392
393 SvtFontOptions aFontOpt;
394 if (!aFontOpt.IsFontHistoryEnabled())
395 return;
396
397 SvFileStream aStream( aFontMRUEntriesFile, StreamMode::READ );
398 if( ! aStream.IsOpen() )
399 {
400 SAL_INFO("svtools.control", "FontNameBox::LoadMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed");
401 return;
402 }
403
404 OString aLine;
405 aStream.ReadLine( aLine );
406 OUString aEntries = OStringToOUString(aLine,
407 RTL_TEXTENCODING_UTF8);
408 SetMRUEntries( aEntries );
409 }
410
InitFontMRUEntriesFile()411 void FontNameBox::InitFontMRUEntriesFile()
412 {
413 OUString sUserConfigDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}");
414 rtl::Bootstrap::expandMacros(sUserConfigDir);
415
416 maFontMRUEntriesFile = sUserConfigDir;
417 if( !maFontMRUEntriesFile.isEmpty() )
418 {
419 maFontMRUEntriesFile += FONTNAMEBOXMRUENTRIESFILE;
420 }
421 }
422
ImplDestroyFontList()423 void FontNameBox::ImplDestroyFontList()
424 {
425 mpFontList.reset();
426 }
427
Fill(const FontList * pList)428 void FontNameBox::Fill( const FontList* pList )
429 {
430 // store old text and clear box
431 OUString aOldText = GetText();
432 OUString rEntries = GetMRUEntries();
433 bool bLoadFromFile = rEntries.isEmpty();
434 Clear();
435
436 ImplDestroyFontList();
437 mpFontList.reset(new ImplFontList);
438
439 // insert fonts
440 sal_uInt16 nFontCount = pList->GetFontNameCount();
441 for ( sal_uInt16 i = 0; i < nFontCount; i++ )
442 {
443 const FontMetric& rFontMetric = pList->GetFontName( i );
444 sal_Int32 nIndex = InsertEntry( rFontMetric.GetFamilyName() );
445 if ( nIndex < static_cast<sal_Int32>(mpFontList->size()) ) {
446 ImplFontList::iterator it = mpFontList->begin();
447 ::std::advance( it, nIndex );
448 mpFontList->insert( it, rFontMetric );
449 } else {
450 mpFontList->push_back( rFontMetric );
451 }
452 }
453
454 if ( bLoadFromFile )
455 LoadMRUEntries (maFontMRUEntriesFile);
456 else
457 SetMRUEntries( rEntries );
458
459 ImplCalcUserItemSize();
460
461 // restore text
462 if (!aOldText.isEmpty())
463 SetText( aOldText );
464 }
465
EnableWYSIWYG(bool bEnable)466 void FontNameBox::EnableWYSIWYG( bool bEnable )
467 {
468 if ( bEnable != mbWYSIWYG )
469 {
470 mbWYSIWYG = bEnable;
471 EnableUserDraw( mbWYSIWYG );
472 ImplCalcUserItemSize();
473 }
474 }
475
ImplCalcUserItemSize()476 void FontNameBox::ImplCalcUserItemSize()
477 {
478 Size aUserItemSz;
479 if ( mbWYSIWYG && mpFontList )
480 {
481 aUserItemSz = Size(MAXPREVIEWWIDTH, GetTextHeight() );
482 aUserItemSz.setHeight( aUserItemSz.Height() * 16 );
483 aUserItemSz.setHeight( aUserItemSz.Height() / 10 );
484 }
485 SetUserItemSize( aUserItemSz );
486 }
487
488 namespace
489 {
shrinkFontToFit(OUString const & rSampleText,long nH,vcl::Font & rFont,OutputDevice & rDevice,tools::Rectangle & rTextRect)490 long shrinkFontToFit(OUString const &rSampleText, long nH, vcl::Font &rFont, OutputDevice &rDevice, tools::Rectangle &rTextRect)
491 {
492 long nWidth = 0;
493
494 Size aSize( rFont.GetFontSize() );
495
496 //Make sure it fits in the available height
497 while (aSize.Height() > 0)
498 {
499 if (!rDevice.GetTextBoundRect(rTextRect, rSampleText))
500 break;
501 if (rTextRect.GetHeight() <= nH)
502 {
503 nWidth = rTextRect.GetWidth();
504 break;
505 }
506
507 aSize.AdjustHeight( -(EXTRAFONTSIZE) );
508 rFont.SetFontSize(aSize);
509 rDevice.SetFont(rFont);
510 }
511
512 return nWidth;
513 }
514 }
515
UserDraw(const UserDrawEvent & rUDEvt)516 void FontNameBox::UserDraw( const UserDrawEvent& rUDEvt )
517 {
518 assert( mpFontList );
519
520 FontMetric& rFontMetric = (*mpFontList)[ rUDEvt.GetItemId() ];
521 Point aTopLeft = rUDEvt.GetRect().TopLeft();
522 long nX = aTopLeft.X();
523 long nH = rUDEvt.GetRect().GetHeight();
524
525 if ( mbWYSIWYG )
526 {
527 nX += IMGOUTERTEXTSPACE;
528
529 const bool bSymbolFont = isSymbolFont(rFontMetric);
530 vcl::RenderContext* pRenderContext = rUDEvt.GetRenderContext();
531
532 Color aTextColor = pRenderContext->GetTextColor();
533 vcl::Font aOldFont(pRenderContext->GetFont());
534 Size aSize( aOldFont.GetFontSize() );
535 aSize.AdjustHeight(EXTRAFONTSIZE );
536 vcl::Font aFont( rFontMetric );
537 aFont.SetFontSize( aSize );
538 pRenderContext->SetFont(aFont);
539 pRenderContext->SetTextColor(aTextColor);
540
541 bool bUsingCorrectFont = true;
542 tools::Rectangle aTextRect;
543
544 // Preview the font name
545 const OUString& sFontName = rFontMetric.GetFamilyName();
546
547 //If it shouldn't or can't draw its own name because it doesn't have the glyphs
548 if (!canRenderNameOfSelectedFont(*pRenderContext))
549 bUsingCorrectFont = false;
550 else
551 {
552 //Make sure it fits in the available height, shrinking the font if necessary
553 bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, *pRenderContext, aTextRect) != 0;
554 }
555
556 if (!bUsingCorrectFont)
557 {
558 pRenderContext->SetFont(aOldFont);
559 pRenderContext->GetTextBoundRect(aTextRect, sFontName);
560 }
561
562 long nTextHeight = aTextRect.GetHeight();
563 long nDesiredGap = (nH-nTextHeight)/2;
564 long nVertAdjust = nDesiredGap - aTextRect.Top();
565 Point aPos( nX, aTopLeft.Y() + nVertAdjust );
566 pRenderContext->DrawText(aPos, sFontName);
567 long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW;
568
569 if (!bUsingCorrectFont)
570 pRenderContext->SetFont(aFont);
571
572 OUString sSampleText;
573
574 if (!bSymbolFont)
575 {
576 const bool bNameBeginsWithLatinText = rFontMetric.GetFamilyName()[0] <= 'z';
577
578 if (bNameBeginsWithLatinText || !bUsingCorrectFont)
579 sSampleText = makeShortRepresentativeTextForSelectedFont(*pRenderContext);
580 }
581
582 //If we're not a symbol font, but could neither render our own name and
583 //we can't determine what script it would like to render, then try a
584 //few well known scripts
585 if (sSampleText.isEmpty() && !bUsingCorrectFont)
586 {
587 static const UScriptCode aScripts[] =
588 {
589 USCRIPT_ARABIC,
590 USCRIPT_HEBREW,
591
592 USCRIPT_BENGALI,
593 USCRIPT_GURMUKHI,
594 USCRIPT_GUJARATI,
595 USCRIPT_ORIYA,
596 USCRIPT_TAMIL,
597 USCRIPT_TELUGU,
598 USCRIPT_KANNADA,
599 USCRIPT_MALAYALAM,
600 USCRIPT_SINHALA,
601 USCRIPT_DEVANAGARI,
602
603 USCRIPT_THAI,
604 USCRIPT_LAO,
605 USCRIPT_GEORGIAN,
606 USCRIPT_TIBETAN,
607 USCRIPT_SYRIAC,
608 USCRIPT_MYANMAR,
609 USCRIPT_ETHIOPIC,
610 USCRIPT_KHMER,
611 USCRIPT_MONGOLIAN,
612
613 USCRIPT_KOREAN,
614 USCRIPT_JAPANESE,
615 USCRIPT_HAN,
616 USCRIPT_SIMPLIFIED_HAN,
617 USCRIPT_TRADITIONAL_HAN,
618
619 USCRIPT_GREEK
620 };
621
622 for (const UScriptCode& rScript : aScripts)
623 {
624 OUString sText = makeShortRepresentativeTextForScript(rScript);
625 if (!sText.isEmpty())
626 {
627 bool bHasSampleTextGlyphs = (-1 == pRenderContext->HasGlyphs(aFont, sText));
628 if (bHasSampleTextGlyphs)
629 {
630 sSampleText = sText;
631 break;
632 }
633 }
634 }
635
636 static const UScriptCode aMinimalScripts[] =
637 {
638 USCRIPT_HEBREW, //e.g. biblical hebrew
639 USCRIPT_GREEK
640 };
641
642 for (const UScriptCode& rMinimalScript : aMinimalScripts)
643 {
644 OUString sText = makeShortMinimalTextForScript(rMinimalScript);
645 if (!sText.isEmpty())
646 {
647 bool bHasSampleTextGlyphs = (-1 == pRenderContext->HasGlyphs(aFont, sText));
648 if (bHasSampleTextGlyphs)
649 {
650 sSampleText = sText;
651 break;
652 }
653 }
654 }
655 }
656
657 //If we're a symbol font, or for some reason the font still couldn't
658 //render something representative of what it would like to render then
659 //make up some semi-random text that it *can* display
660 if (bSymbolFont || (!bUsingCorrectFont && sSampleText.isEmpty()))
661 sSampleText = makeShortRepresentativeSymbolTextForSelectedFont(*pRenderContext);
662
663 if (!sSampleText.isEmpty())
664 {
665 const Size &rItemSize = rUDEvt.GetWindow()->GetOutputSize();
666
667 //leave a little border at the edge
668 long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE;
669 if (nSpace >= 0)
670 {
671 //Make sure it fits in the available height, and get how wide that would be
672 long nWidth = shrinkFontToFit(sSampleText, nH, aFont, *pRenderContext, aTextRect);
673 //Chop letters off until it fits in the available width
674 while (nWidth > nSpace || nWidth > MAXPREVIEWWIDTH)
675 {
676 sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
677 nWidth = pRenderContext->GetTextBoundRect(aTextRect, sSampleText) ?
678 aTextRect.GetWidth() : 0;
679 }
680
681 //center the text on the line
682 if (!sSampleText.isEmpty() && nWidth)
683 {
684 nTextHeight = aTextRect.GetHeight();
685 nDesiredGap = (nH-nTextHeight)/2;
686 nVertAdjust = nDesiredGap - aTextRect.Top();
687 aPos = Point(nTextX + nSpace - nWidth, aTopLeft.Y() + nVertAdjust);
688 pRenderContext->DrawText(aPos, sSampleText);
689 }
690 }
691 }
692
693 pRenderContext->SetFont(aOldFont);
694 DrawEntry( rUDEvt, false, false); // draw separator
695 }
696 else
697 {
698 DrawEntry( rUDEvt, true, true );
699 }
700 }
701
FontStyleBox(vcl::Window * pParent,WinBits nBits)702 FontStyleBox::FontStyleBox(vcl::Window* pParent, WinBits nBits)
703 : ComboBox(pParent, nBits)
704 {
705 //Use the standard texts to get an optimal size and stick to that size.
706 //That should stop the character dialog dancing around.
707 InsertEntry(SvtResId(STR_SVT_STYLE_LIGHT));
708 InsertEntry(SvtResId(STR_SVT_STYLE_LIGHT_ITALIC));
709 InsertEntry(SvtResId(STR_SVT_STYLE_NORMAL));
710 InsertEntry(SvtResId(STR_SVT_STYLE_NORMAL_ITALIC));
711 InsertEntry(SvtResId(STR_SVT_STYLE_BOLD));
712 InsertEntry(SvtResId(STR_SVT_STYLE_BOLD_ITALIC));
713 InsertEntry(SvtResId(STR_SVT_STYLE_BLACK));
714 InsertEntry(SvtResId(STR_SVT_STYLE_BLACK_ITALIC));
715 aOptimalSize = GetOptimalSize();
716 Clear();
717 }
718
GetOptimalSize() const719 Size FontStyleBox::GetOptimalSize() const
720 {
721 if (aOptimalSize.Width() || aOptimalSize.Height())
722 return aOptimalSize;
723 return ComboBox::GetOptimalSize();
724 }
725
makeFontStyleBox(VclPtr<vcl::Window> & rRet,const VclPtr<vcl::Window> & pParent,VclBuilder::stringmap & rMap)726 extern "C" SAL_DLLPUBLIC_EXPORT void makeFontStyleBox(VclPtr<vcl::Window> & rRet, const VclPtr<vcl::Window> & pParent, VclBuilder::stringmap & rMap)
727 {
728 static_assert(std::is_same_v<std::remove_pointer_t<VclBuilder::customMakeWidget>,
729 decltype(makeFontStyleBox)>);
730 bool bDropdown = BuilderUtils::extractDropdown(rMap);
731 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
732 if (bDropdown)
733 nWinBits |= WB_DROPDOWN;
734 VclPtrInstance<FontStyleBox> pListBox(pParent, nWinBits);
735 if (bDropdown)
736 pListBox->EnableAutoSize(true);
737 rRet = pListBox;
738 }
739
Modify()740 void FontStyleBox::Modify()
741 {
742 CharClass aChrCls( ::comphelper::getProcessComponentContext(),
743 GetSettings().GetLanguageTag() );
744 OUString aStr = GetText();
745 sal_Int32 nEntryCount = GetEntryCount();
746
747 if ( GetEntryPos( aStr ) == COMBOBOX_ENTRY_NOTFOUND )
748 {
749 aStr = aChrCls.uppercase(aStr);
750 for ( sal_Int32 i = 0; i < nEntryCount; i++ )
751 {
752 OUString aEntryText = aChrCls.uppercase(GetEntry(i));
753
754 if ( aStr == aEntryText )
755 {
756 SetText( GetEntry( i ) );
757 break;
758 }
759 }
760 }
761
762 ComboBox::Modify();
763 }
764
765
SvtFontStyleBox(std::unique_ptr<weld::ComboBox> p)766 SvtFontStyleBox::SvtFontStyleBox(std::unique_ptr<weld::ComboBox> p)
767 : m_xComboBox(std::move(p))
768 {
769 //Use the standard texts to get an optimal size and stick to that size.
770 //That should stop the character dialog dancing around.
771 auto nMaxLen = m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHT)).Width();
772 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHT_ITALIC)).Width());
773 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMAL)).Width());
774 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMAL_ITALIC)).Width());
775 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLD)).Width());
776 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLD_ITALIC)).Width());
777 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACK)).Width());
778 nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACK_ITALIC)).Width());
779 m_xComboBox->set_entry_width_chars(std::ceil(nMaxLen / m_xComboBox->get_approximate_digit_width()));
780 }
781
Fill(const OUString & rName,const FontList * pList)782 void SvtFontStyleBox::Fill( const OUString& rName, const FontList* pList )
783 {
784 m_xComboBox->freeze();
785 OUString aOldText = m_xComboBox->get_active_text();
786 int nPos = m_xComboBox->get_active();
787 m_xComboBox->clear();
788
789 // does a font with this name already exist?
790 sal_Handle hFontMetric = pList->GetFirstFontMetric( rName );
791 if ( hFontMetric )
792 {
793 OUString aStyleText;
794 FontWeight eLastWeight = WEIGHT_DONTKNOW;
795 FontItalic eLastItalic = ITALIC_NONE;
796 FontWidth eLastWidth = WIDTH_DONTKNOW;
797 bool bNormal = false;
798 bool bItalic = false;
799 bool bBold = false;
800 bool bBoldItalic = false;
801 bool bInsert = false;
802 FontMetric aFontMetric;
803 while ( hFontMetric )
804 {
805 aFontMetric = FontList::GetFontMetric( hFontMetric );
806
807 FontWeight eWeight = aFontMetric.GetWeight();
808 FontItalic eItalic = aFontMetric.GetItalic();
809 FontWidth eWidth = aFontMetric.GetWidthType();
810 // Only if the attributes are different, we insert the
811 // Font to avoid double Entries in different languages
812 if ( (eWeight != eLastWeight) || (eItalic != eLastItalic) ||
813 (eWidth != eLastWidth) )
814 {
815 if ( bInsert )
816 m_xComboBox->append_text(aStyleText);
817
818 if ( eWeight <= WEIGHT_NORMAL )
819 {
820 if ( eItalic != ITALIC_NONE )
821 bItalic = true;
822 else
823 bNormal = true;
824 }
825 else
826 {
827 if ( eItalic != ITALIC_NONE )
828 bBoldItalic = true;
829 else
830 bBold = true;
831 }
832
833 // For wrong StyleNames we replace this with the correct once
834 aStyleText = pList->GetStyleName( aFontMetric );
835 bInsert = m_xComboBox->find_text(aStyleText) == -1;
836 if ( !bInsert )
837 {
838 aStyleText = pList->GetStyleName( eWeight, eItalic );
839 bInsert = m_xComboBox->find_text(aStyleText) == -1;
840 }
841
842 eLastWeight = eWeight;
843 eLastItalic = eItalic;
844 eLastWidth = eWidth;
845 }
846 else
847 {
848 if ( bInsert )
849 {
850 // If we have two names for the same attributes
851 // we prefer the translated standard names
852 const OUString& rAttrStyleText = pList->GetStyleName( eWeight, eItalic );
853 if (rAttrStyleText != aStyleText)
854 {
855 OUString aTempStyleText = pList->GetStyleName( aFontMetric );
856 if (rAttrStyleText == aTempStyleText)
857 aStyleText = rAttrStyleText;
858 bInsert = m_xComboBox->find_text(aStyleText) == -1;
859 }
860 }
861 }
862
863 if ( !bItalic && (aStyleText == pList->GetItalicStr()) )
864 bItalic = true;
865 else if ( !bBold && (aStyleText == pList->GetBoldStr()) )
866 bBold = true;
867 else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) )
868 bBoldItalic = true;
869
870 hFontMetric = FontList::GetNextFontMetric( hFontMetric );
871 }
872
873 if ( bInsert )
874 m_xComboBox->append_text(aStyleText);
875
876 // certain style as copy
877 if ( bNormal )
878 {
879 if ( !bItalic )
880 m_xComboBox->append_text(pList->GetItalicStr());
881 if ( !bBold )
882 m_xComboBox->append_text(pList->GetBoldStr());
883 }
884 if ( !bBoldItalic )
885 {
886 if ( bNormal || bItalic || bBold )
887 m_xComboBox->append_text(pList->GetBoldItalicStr());
888 }
889 if (!aOldText.isEmpty())
890 {
891 int nFound = m_xComboBox->find_text(aOldText);
892 if (nFound != -1)
893 m_xComboBox->set_active(nFound);
894 else
895 {
896 if (nPos >= m_xComboBox->get_count())
897 m_xComboBox->set_active(0);
898 else
899 m_xComboBox->set_active(nPos);
900 }
901 }
902 }
903 else
904 {
905 // insert standard styles if no font
906 m_xComboBox->append_text(pList->GetNormalStr());
907 m_xComboBox->append_text(pList->GetItalicStr());
908 m_xComboBox->append_text(pList->GetBoldStr());
909 m_xComboBox->append_text(pList->GetBoldItalicStr());
910 if (!aOldText.isEmpty())
911 {
912 if (nPos >= m_xComboBox->get_count())
913 m_xComboBox->set_active(0);
914 else
915 m_xComboBox->set_active(nPos);
916 }
917 }
918 m_xComboBox->thaw();
919 }
920
FontSizeBox(vcl::Window * pParent,WinBits nWinSize)921 FontSizeBox::FontSizeBox( vcl::Window* pParent, WinBits nWinSize ) :
922 MetricBox( pParent, nWinSize )
923 {
924 EnableSelectAll();
925 ImplInit();
926 }
927
makeFontSizeBox(VclPtr<vcl::Window> & rRet,const VclPtr<vcl::Window> & pParent,VclBuilder::stringmap & rMap)928 extern "C" SAL_DLLPUBLIC_EXPORT void makeFontSizeBox(VclPtr<vcl::Window> & rRet, const VclPtr<vcl::Window> & pParent, VclBuilder::stringmap & rMap)
929 {
930 static_assert(std::is_same_v<std::remove_pointer_t<VclBuilder::customMakeWidget>,
931 decltype(makeFontSizeBox)>);
932 bool bDropdown = BuilderUtils::extractDropdown(rMap);
933 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
934 if (bDropdown)
935 nWinBits |= WB_DROPDOWN;
936 VclPtrInstance<FontSizeBox> pListBox(pParent, nWinBits);
937 if (bDropdown)
938 pListBox->EnableAutoSize(true);
939 rRet = pListBox;
940 }
941
ImplInit()942 void FontSizeBox::ImplInit()
943 {
944 EnableAutocomplete( false );
945
946 bStdSize = false;
947
948 SetShowTrailingZeros( false );
949 SetDecimalDigits( 1 );
950 SetMin( 20 );
951 SetMax( 9999 );
952 SetProminentEntryType( ProminentEntry::MIDDLE );
953 }
954
Reformat()955 void FontSizeBox::Reformat()
956 {
957 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
958 long nNewValue = aFontSizeNames.Name2Size( GetText() );
959 if ( nNewValue)
960 {
961 mnLastValue = nNewValue;
962 return;
963 }
964
965 MetricBox::Reformat();
966 }
967
Fill(const FontMetric * pFontMetric,const FontList * pList)968 void FontSizeBox::Fill( const FontMetric* pFontMetric, const FontList* pList )
969 {
970 // query font sizes
971 const sal_IntPtr* pTempAry;
972 const sal_IntPtr* pAry = nullptr;
973
974 if( pFontMetric )
975 {
976 pAry = pList->GetSizeAry( *pFontMetric );
977 }
978 else
979 {
980 pAry = FontList::GetStdSizeAry();
981 }
982
983 // first insert font size names (for simplified/traditional chinese)
984 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
985 if ( pAry == FontList::GetStdSizeAry() )
986 {
987 // for standard sizes we don't need to bother
988 if ( bStdSize && GetEntryCount() && aFontSizeNames.IsEmpty() )
989 return;
990 bStdSize = true;
991 }
992 else
993 bStdSize = false;
994
995 Selection aSelection = GetSelection();
996 OUString aStr = GetText();
997
998 Clear();
999 sal_Int32 nPos = 0;
1000
1001 if ( !aFontSizeNames.IsEmpty() )
1002 {
1003 if ( pAry == FontList::GetStdSizeAry() )
1004 {
1005 // for scalable fonts all font size names
1006 sal_Int32 nCount = aFontSizeNames.Count();
1007 for( sal_Int32 i = 0; i < nCount; i++ )
1008 {
1009 OUString aSizeName = aFontSizeNames.GetIndexName( i );
1010 sal_Int32 nSize = aFontSizeNames.GetIndexSize( i );
1011 ComboBox::InsertEntry( aSizeName, nPos );
1012 ComboBox::SetEntryData( nPos, reinterpret_cast<void*>(-nSize) ); // mark as special
1013 nPos++;
1014 }
1015 }
1016 else
1017 {
1018 // for fixed size fonts only selectable font size names
1019 pTempAry = pAry;
1020 while ( *pTempAry )
1021 {
1022 OUString aSizeName = aFontSizeNames.Size2Name( *pTempAry );
1023 if ( !aSizeName.isEmpty() )
1024 {
1025 ComboBox::InsertEntry( aSizeName, nPos );
1026 ComboBox::SetEntryData( nPos, reinterpret_cast<void*>(-(*pTempAry)) ); // mark as special
1027 nPos++;
1028 }
1029 pTempAry++;
1030 }
1031 }
1032 }
1033
1034 // then insert numerical font size values
1035 pTempAry = pAry;
1036 while ( *pTempAry )
1037 {
1038 InsertValue( *pTempAry, FieldUnit::NONE, nPos );
1039 ComboBox::SetEntryData( nPos, reinterpret_cast<void*>(*pTempAry) );
1040 nPos++;
1041 pTempAry++;
1042 }
1043
1044 SetText( aStr );
1045 SetSelection( aSelection );
1046 }
1047
SetValue(sal_Int64 nNewValue,FieldUnit eInUnit)1048 void FontSizeBox::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit )
1049 {
1050 sal_Int64 nTempValue = MetricField::ConvertValue( nNewValue, GetBaseValue(), GetDecimalDigits(), eInUnit, GetUnit() );
1051 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1052 // conversion loses precision; however font sizes should
1053 // never have a problem with that
1054 OUString aName = aFontSizeNames.Size2Name( static_cast<long>(nTempValue) );
1055 if ( !aName.isEmpty() && (GetEntryPos( aName ) != LISTBOX_ENTRY_NOTFOUND) )
1056 {
1057 mnLastValue = nTempValue;
1058 SetText( aName );
1059 mnFieldValue = mnLastValue;
1060 SetEmptyFieldValueData( false );
1061 return;
1062 }
1063
1064 MetricBox::SetValue( nNewValue, eInUnit );
1065 }
1066
SetValue(sal_Int64 nNewValue)1067 void FontSizeBox::SetValue( sal_Int64 nNewValue )
1068 {
1069 SetValue( nNewValue, FieldUnit::NONE );
1070 }
1071
GetValueFromStringUnit(const OUString & rStr,FieldUnit eOutUnit) const1072 sal_Int64 FontSizeBox::GetValueFromStringUnit(const OUString& rStr, FieldUnit eOutUnit) const
1073 {
1074 FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
1075 sal_Int64 nValue = aFontSizeNames.Name2Size( rStr );
1076 if ( nValue )
1077 return MetricField::ConvertValue( nValue, GetBaseValue(), GetDecimalDigits(), GetUnit(), eOutUnit );
1078
1079 return MetricBox::GetValueFromStringUnit( rStr, eOutUnit );
1080 }
1081
SvtFontSizeBox(std::unique_ptr<weld::ComboBox> p)1082 SvtFontSizeBox::SvtFontSizeBox(std::unique_ptr<weld::ComboBox> p)
1083 : pFontList(nullptr)
1084 , nSavedValue(0)
1085 , nMin(20)
1086 , nMax(9999)
1087 , eUnit(FieldUnit::POINT)
1088 , nDecimalDigits(1)
1089 , nRelMin(0)
1090 , nRelMax(0)
1091 , nRelStep(0)
1092 , nPtRelMin(0)
1093 , nPtRelMax(0)
1094 , nPtRelStep(0)
1095 , bRelativeMode(false)
1096 , bRelative(false)
1097 , bPtRelative(false)
1098 , bStdSize(false)
1099 , m_xComboBox(std::move(p))
1100 {
1101 m_xComboBox->set_entry_width_chars(std::ceil(m_xComboBox->get_pixel_size(format_number(105)).Width() /
1102 m_xComboBox->get_approximate_digit_width()));
1103 m_xComboBox->connect_focus_out(LINK(this, SvtFontSizeBox, ReformatHdl));
1104 m_xComboBox->connect_changed(LINK(this, SvtFontSizeBox, ModifyHdl));
1105 }
1106
IMPL_LINK_NOARG(SvtFontSizeBox,ReformatHdl,weld::Widget &,void)1107 IMPL_LINK_NOARG(SvtFontSizeBox, ReformatHdl, weld::Widget&, void)
1108 {
1109 FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1110 if (!bRelativeMode || !aFontSizeNames.IsEmpty())
1111 {
1112 if (aFontSizeNames.Name2Size(m_xComboBox->get_active_text()) != 0)
1113 return;
1114 }
1115
1116 set_value(get_value());
1117 }
1118
IMPL_LINK(SvtFontSizeBox,ModifyHdl,weld::ComboBox &,rBox,void)1119 IMPL_LINK(SvtFontSizeBox, ModifyHdl, weld::ComboBox&, rBox, void)
1120 {
1121 if (bRelativeMode)
1122 {
1123 OUString aStr = comphelper::string::stripStart(rBox.get_active_text(), ' ');
1124
1125 bool bNewMode = bRelative;
1126 bool bOldPtRelMode = bPtRelative;
1127
1128 if ( bRelative )
1129 {
1130 bPtRelative = false;
1131 const sal_Unicode* pStr = aStr.getStr();
1132 while ( *pStr )
1133 {
1134 if ( ((*pStr < '0') || (*pStr > '9')) && (*pStr != '%') && !unicode::isSpace(*pStr) )
1135 {
1136 if ( ('-' == *pStr || '+' == *pStr) && !bPtRelative )
1137 bPtRelative = true;
1138 else if ( bPtRelative && 'p' == *pStr && 't' == *++pStr )
1139 ;
1140 else
1141 {
1142 bNewMode = false;
1143 break;
1144 }
1145 }
1146 pStr++;
1147 }
1148 }
1149 else if (!aStr.isEmpty())
1150 {
1151 if ( -1 != aStr.indexOf('%') )
1152 {
1153 bNewMode = true;
1154 bPtRelative = false;
1155 }
1156
1157 if ( '-' == aStr[0] || '+' == aStr[0] )
1158 {
1159 bNewMode = true;
1160 bPtRelative = true;
1161 }
1162 }
1163
1164 if ( bNewMode != bRelative || bPtRelative != bOldPtRelMode )
1165 SetRelative( bNewMode );
1166 }
1167 m_aChangeHdl.Call(rBox);
1168 }
1169
Fill(const FontMetric * pFontMetric,const FontList * pList)1170 void SvtFontSizeBox::Fill( const FontMetric* pFontMetric, const FontList* pList )
1171 {
1172 // remember for relative mode
1173 pFontList = pList;
1174
1175 // no font sizes need to be set for relative mode
1176 if ( bRelative )
1177 return;
1178
1179 // query font sizes
1180 const sal_IntPtr* pTempAry;
1181 const sal_IntPtr* pAry = nullptr;
1182
1183 if( pFontMetric )
1184 {
1185 aFontMetric = *pFontMetric;
1186 pAry = pList->GetSizeAry( *pFontMetric );
1187 }
1188 else
1189 {
1190 pAry = FontList::GetStdSizeAry();
1191 }
1192
1193 // first insert font size names (for simplified/traditional chinese)
1194 FontSizeNames aFontSizeNames( Application::GetSettings().GetUILanguageTag().getLanguageType() );
1195 if ( pAry == FontList::GetStdSizeAry() )
1196 {
1197 // for standard sizes we don't need to bother
1198 if (bStdSize && m_xComboBox->get_count() && aFontSizeNames.IsEmpty())
1199 return;
1200 bStdSize = true;
1201 }
1202 else
1203 bStdSize = false;
1204
1205 int nSelectionStart, nSelectionEnd;
1206 m_xComboBox->get_entry_selection_bounds(nSelectionStart, nSelectionEnd);
1207 OUString aStr = m_xComboBox->get_active_text();
1208
1209 m_xComboBox->freeze();
1210 m_xComboBox->clear();
1211 int nPos = 0;
1212
1213 if ( !aFontSizeNames.IsEmpty() )
1214 {
1215 if ( pAry == FontList::GetStdSizeAry() )
1216 {
1217 // for scalable fonts all font size names
1218 sal_uLong nCount = aFontSizeNames.Count();
1219 for( sal_uLong i = 0; i < nCount; i++ )
1220 {
1221 OUString aSizeName = aFontSizeNames.GetIndexName( i );
1222 sal_IntPtr nSize = aFontSizeNames.GetIndexSize( i );
1223 OUString sId(OUString::number(-nSize)); // mark as special
1224 m_xComboBox->insert(nPos, aSizeName, &sId, nullptr, nullptr);
1225 nPos++;
1226 }
1227 }
1228 else
1229 {
1230 // for fixed size fonts only selectable font size names
1231 pTempAry = pAry;
1232 while ( *pTempAry )
1233 {
1234 OUString aSizeName = aFontSizeNames.Size2Name( *pTempAry );
1235 if ( !aSizeName.isEmpty() )
1236 {
1237 OUString sId(OUString::number(-(*pTempAry))); // mark as special
1238 m_xComboBox->insert(nPos, aSizeName, &sId, nullptr, nullptr);
1239 nPos++;
1240 }
1241 pTempAry++;
1242 }
1243 }
1244 }
1245
1246 // then insert numerical font size values
1247 pTempAry = pAry;
1248 while (*pTempAry)
1249 {
1250 InsertValue(*pTempAry);
1251 ++pTempAry;
1252 }
1253
1254 m_xComboBox->set_entry_text(aStr);
1255 m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
1256 m_xComboBox->thaw();
1257 }
1258
EnableRelativeMode(sal_uInt16 nNewMin,sal_uInt16 nNewMax,sal_uInt16 nStep)1259 void SvtFontSizeBox::EnableRelativeMode( sal_uInt16 nNewMin, sal_uInt16 nNewMax, sal_uInt16 nStep )
1260 {
1261 bRelativeMode = true;
1262 nRelMin = nNewMin;
1263 nRelMax = nNewMax;
1264 nRelStep = nStep;
1265 SetUnit(FieldUnit::POINT);
1266 }
1267
EnablePtRelativeMode(short nNewMin,short nNewMax,short nStep)1268 void SvtFontSizeBox::EnablePtRelativeMode( short nNewMin, short nNewMax, short nStep )
1269 {
1270 bRelativeMode = true;
1271 nPtRelMin = nNewMin;
1272 nPtRelMax = nNewMax;
1273 nPtRelStep = nStep;
1274 SetUnit(FieldUnit::POINT);
1275 }
1276
InsertValue(int i)1277 void SvtFontSizeBox::InsertValue(int i)
1278 {
1279 OUString sNumber(OUString::number(i));
1280 m_xComboBox->append(sNumber, format_number(i));
1281 }
1282
SetRelative(bool bNewRelative)1283 void SvtFontSizeBox::SetRelative( bool bNewRelative )
1284 {
1285 if ( !bRelativeMode )
1286 return;
1287
1288 int nSelectionStart, nSelectionEnd;
1289 m_xComboBox->get_entry_selection_bounds(nSelectionStart, nSelectionEnd);
1290 OUString aStr = comphelper::string::stripStart(m_xComboBox->get_active_text(), ' ');
1291
1292 if (bNewRelative)
1293 {
1294 bRelative = true;
1295 bStdSize = false;
1296
1297 m_xComboBox->clear();
1298
1299 if (bPtRelative)
1300 {
1301 SetDecimalDigits( 1 );
1302 SetRange(nPtRelMin, nPtRelMax);
1303 SetUnit(FieldUnit::POINT);
1304
1305 short i = nPtRelMin, n = 0;
1306 // JP 30.06.98: more than 100 values are not useful
1307 while ( i <= nPtRelMax && n++ < 100 )
1308 {
1309 InsertValue( i );
1310 i = i + nPtRelStep;
1311 }
1312 }
1313 else
1314 {
1315 SetDecimalDigits(0);
1316 SetRange(nRelMin, nRelMax);
1317 SetUnit(FieldUnit::PERCENT);
1318
1319 sal_uInt16 i = nRelMin;
1320 while ( i <= nRelMax )
1321 {
1322 InsertValue( i );
1323 i = i + nRelStep;
1324 }
1325 }
1326 }
1327 else
1328 {
1329 if (pFontList)
1330 m_xComboBox->clear();
1331 bRelative = bPtRelative = false;
1332 SetDecimalDigits(1);
1333 SetRange(20, 9999);
1334 SetUnit(FieldUnit::POINT);
1335 if ( pFontList)
1336 Fill( &aFontMetric, pFontList );
1337 }
1338
1339 m_xComboBox->set_entry_text(aStr);
1340 m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
1341 }
1342
format_number(int nValue) const1343 OUString SvtFontSizeBox::format_number(int nValue) const
1344 {
1345 OUString sRet;
1346
1347 //pawn percent off to icu to decide whether percent is separated from its number for this locale
1348 if (eUnit == FieldUnit::PERCENT)
1349 {
1350 double fValue = nValue;
1351 fValue /= weld::SpinButton::Power10(nDecimalDigits);
1352 sRet = unicode::formatPercent(fValue, Application::GetSettings().GetUILanguageTag());
1353 }
1354 else
1355 {
1356 const SvtSysLocale aSysLocale;
1357 const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
1358 sRet = rLocaleData.getNum(nValue, nDecimalDigits, true, false);
1359 if (eUnit != FieldUnit::NONE && eUnit != FieldUnit::DEGREE)
1360 sRet += " ";
1361 assert(eUnit != FieldUnit::PERCENT);
1362 sRet += weld::MetricSpinButton::MetricToString(eUnit);
1363 }
1364
1365 if (bRelativeMode && bPtRelative && (0 <= nValue) && !sRet.isEmpty())
1366 sRet = "+" + sRet;
1367
1368 return sRet;
1369 }
1370
SetValue(int nNewValue,FieldUnit eInUnit)1371 void SvtFontSizeBox::SetValue(int nNewValue, FieldUnit eInUnit)
1372 {
1373 auto nTempValue = MetricField::ConvertValue(nNewValue, 0, GetDecimalDigits(), eInUnit, GetUnit());
1374 if (nTempValue < nMin)
1375 nTempValue = nMin;
1376 else if (nTempValue > nMax)
1377 nTempValue = nMax;
1378 if (!bRelative)
1379 {
1380 FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1381 // conversion loses precision; however font sizes should
1382 // never have a problem with that
1383 OUString aName = aFontSizeNames.Size2Name(nTempValue);
1384 if (!aName.isEmpty() && m_xComboBox->find_text(aName) != -1)
1385 {
1386 m_xComboBox->set_active_text(aName);
1387 return;
1388 }
1389 }
1390 OUString aResult = format_number(nTempValue);
1391 const int nFound = m_xComboBox->find_text(aResult);
1392 if (nFound != -1)
1393 m_xComboBox->set_active(nFound);
1394 else
1395 m_xComboBox->set_entry_text(aResult);
1396 }
1397
set_value(int nNewValue)1398 void SvtFontSizeBox::set_value(int nNewValue)
1399 {
1400 SetValue(nNewValue, eUnit);
1401 }
1402
get_value() const1403 int SvtFontSizeBox::get_value() const
1404 {
1405 OUString aStr = m_xComboBox->get_active_text();
1406 if (!bRelative)
1407 {
1408 FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1409 auto nValue = aFontSizeNames.Name2Size(aStr);
1410 if (nValue)
1411 return MetricField::ConvertValue(nValue, 0, GetDecimalDigits(), GetUnit(), GetUnit());
1412 }
1413
1414 const SvtSysLocale aSysLocale;
1415 const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
1416 double fResult(0.0);
1417 MetricFormatter::TextToValue(aStr, fResult, 0, GetDecimalDigits(), rLocaleData, GetUnit());
1418 if (!aStr.isEmpty())
1419 {
1420 if (fResult < nMin)
1421 fResult = nMin;
1422 else if (fResult > nMax)
1423 fResult = nMax;
1424 }
1425 return fResult;
1426 }
1427
GetSelectEntryStyle() const1428 SvxBorderLineStyle SvtLineListBox::GetSelectEntryStyle() const
1429 {
1430 if (m_xLineSet->IsNoSelection())
1431 return SvxBorderLineStyle::NONE;
1432 auto nId = m_xLineSet->GetSelectedItemId();
1433 return static_cast<SvxBorderLineStyle>(nId - 1);
1434 }
1435
1436 namespace
1437 {
getPreviewSize(const weld::Widget & rControl)1438 Size getPreviewSize(const weld::Widget& rControl)
1439 {
1440 return Size(rControl.get_approximate_digit_width() * 15, rControl.get_text_height());
1441 }
1442 }
1443
ImpGetLine(long nLine1,long nLine2,long nDistance,Color aColor1,Color aColor2,Color aColorDist,SvxBorderLineStyle nStyle,BitmapEx & rBmp)1444 void SvtLineListBox::ImpGetLine( long nLine1, long nLine2, long nDistance,
1445 Color aColor1, Color aColor2, Color aColorDist,
1446 SvxBorderLineStyle nStyle, BitmapEx& rBmp )
1447 {
1448 Size aSize(getPreviewSize(*m_xControl));
1449
1450 // SourceUnit to Twips
1451 if ( eSourceUnit == FieldUnit::POINT )
1452 {
1453 nLine1 /= 5;
1454 nLine2 /= 5;
1455 nDistance /= 5;
1456 }
1457
1458 // Paint the lines
1459 aSize = aVirDev->PixelToLogic( aSize );
1460 long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
1461 sal_uInt32 n1 = nLine1;
1462 sal_uInt32 n2 = nLine2;
1463 long nDist = nDistance;
1464 n1 += nPix-1;
1465 n1 -= n1%nPix;
1466 if ( n2 )
1467 {
1468 nDist += nPix-1;
1469 nDist -= nDist%nPix;
1470 n2 += nPix-1;
1471 n2 -= n2%nPix;
1472 }
1473 long nVirHeight = n1+nDist+n2;
1474 if ( nVirHeight > aSize.Height() )
1475 aSize.setHeight( nVirHeight );
1476 // negative width should not be drawn
1477 if ( aSize.Width() <= 0 )
1478 return;
1479
1480 Size aVirSize = aVirDev->LogicToPixel( aSize );
1481 if ( aVirDev->GetOutputSizePixel() != aVirSize )
1482 aVirDev->SetOutputSizePixel( aVirSize );
1483 aVirDev->SetFillColor( aColorDist );
1484 aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) );
1485
1486 aVirDev->SetFillColor( aColor1 );
1487
1488 double y1 = double( n1 ) / 2;
1489 svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
1490
1491 if ( n2 )
1492 {
1493 double y2 = n1 + nDist + double( n2 ) / 2;
1494 aVirDev->SetFillColor( aColor2 );
1495 svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID );
1496 }
1497 rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
1498 }
1499
1500 namespace
1501 {
GetLineStyleName(SvxBorderLineStyle eStyle)1502 OUString GetLineStyleName(SvxBorderLineStyle eStyle)
1503 {
1504 OUString sRet;
1505 for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE); ++i)
1506 {
1507 if (eStyle == RID_SVXSTR_BORDERLINE[i].second)
1508 {
1509 sRet = SvtResId(RID_SVXSTR_BORDERLINE[i].first);
1510 break;
1511 }
1512 }
1513 return sRet;
1514 }
1515 }
1516
SvtLineListBox(std::unique_ptr<weld::MenuButton> pControl)1517 SvtLineListBox::SvtLineListBox(std::unique_ptr<weld::MenuButton> pControl)
1518 : m_xControl(std::move(pControl))
1519 , m_xBuilder(Application::CreateBuilder(m_xControl.get(), "svt/ui/linewindow.ui"))
1520 , m_xTopLevel(m_xBuilder->weld_widget("line_popup_window"))
1521 , m_xNoneButton(m_xBuilder->weld_button("none_line_button"))
1522 , m_xLineSet(new SvtValueSet(nullptr))
1523 , m_xLineSetWin(new weld::CustomWeld(*m_xBuilder, "lineset", *m_xLineSet))
1524 , m_nWidth( 5 )
1525 , aVirDev(VclPtr<VirtualDevice>::Create())
1526 , aColor(COL_BLACK)
1527 , maPaintCol(COL_BLACK)
1528 {
1529 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1530 m_xLineSet->SetStyle(WinBits(WB_FLATVALUESET | WB_NO_DIRECTSELECT | WB_TABSTOP));
1531 m_xLineSet->SetItemHeight(rStyleSettings.GetListBoxPreviewDefaultPixelSize().Height() + 1);
1532 m_xLineSet->SetColCount(1);
1533 m_xLineSet->SetSelectHdl(LINK(this, SvtLineListBox, ValueSelectHdl));
1534
1535 m_xNoneButton->connect_clicked(LINK(this, SvtLineListBox, NoneHdl));
1536
1537 m_xTopLevel->connect_focus_in(LINK(this, SvtLineListBox, FocusHdl));
1538 m_xControl->set_popover(m_xTopLevel.get());
1539 m_xControl->connect_toggled(LINK(this, SvtLineListBox, ToggleHdl));
1540
1541 // lock size to these maxes height/width so it doesn't jump around in size
1542 m_xControl->set_label(GetLineStyleName(SvxBorderLineStyle::NONE));
1543 Size aNonePrefSize = m_xControl->get_preferred_size();
1544 m_xControl->set_label("");
1545 aVirDev->SetOutputSizePixel(getPreviewSize(*m_xControl));
1546 m_xControl->set_image(aVirDev);
1547 Size aSolidPrefSize = m_xControl->get_preferred_size();
1548 m_xControl->set_size_request(std::max(aNonePrefSize.Width(), aSolidPrefSize.Width()),
1549 std::max(aNonePrefSize.Height(), aSolidPrefSize.Height()));
1550
1551 eSourceUnit = FieldUnit::POINT;
1552
1553 aVirDev->SetLineColor();
1554 aVirDev->SetMapMode(MapMode(MapUnit::MapTwip));
1555
1556 UpdatePaintLineColor();
1557 }
1558
IMPL_LINK_NOARG(SvtLineListBox,FocusHdl,weld::Widget &,void)1559 IMPL_LINK_NOARG(SvtLineListBox, FocusHdl, weld::Widget&, void)
1560 {
1561 if (GetSelectEntryStyle() == SvxBorderLineStyle::NONE)
1562 m_xNoneButton->grab_focus();
1563 else
1564 m_xLineSet->GrabFocus();
1565 }
1566
IMPL_LINK(SvtLineListBox,ToggleHdl,weld::ToggleButton &,rButton,void)1567 IMPL_LINK(SvtLineListBox, ToggleHdl, weld::ToggleButton&, rButton, void)
1568 {
1569 if (rButton.get_active())
1570 FocusHdl(*m_xTopLevel);
1571 }
1572
IMPL_LINK_NOARG(SvtLineListBox,NoneHdl,weld::Button &,void)1573 IMPL_LINK_NOARG(SvtLineListBox, NoneHdl, weld::Button&, void)
1574 {
1575 SelectEntry(SvxBorderLineStyle::NONE);
1576 ValueSelectHdl(nullptr);
1577 }
1578
~SvtLineListBox()1579 SvtLineListBox::~SvtLineListBox()
1580 {
1581 }
1582
GetStylePos(sal_Int32 nListPos)1583 sal_Int32 SvtLineListBox::GetStylePos( sal_Int32 nListPos )
1584 {
1585 sal_Int32 nPos = LISTBOX_ENTRY_NOTFOUND;
1586 --nListPos;
1587
1588 sal_Int32 n = 0;
1589 size_t i = 0;
1590 size_t nCount = m_vLineList.size();
1591 while ( nPos == LISTBOX_ENTRY_NOTFOUND && i < nCount )
1592 {
1593 if ( nListPos == n )
1594 nPos = static_cast<sal_Int32>(i);
1595 n++;
1596 i++;
1597 }
1598
1599 return nPos;
1600 }
1601
SelectEntry(SvxBorderLineStyle nStyle)1602 void SvtLineListBox::SelectEntry(SvxBorderLineStyle nStyle)
1603 {
1604 if (nStyle == SvxBorderLineStyle::NONE)
1605 m_xLineSet->SetNoSelection();
1606 else
1607 m_xLineSet->SelectItem(static_cast<sal_Int16>(nStyle) + 1);
1608 UpdatePreview();
1609 }
1610
InsertEntry(const BorderWidthImpl & rWidthImpl,SvxBorderLineStyle nStyle,long nMinWidth,ColorFunc pColor1Fn,ColorFunc pColor2Fn,ColorDistFunc pColorDistFn)1611 void SvtLineListBox::InsertEntry(
1612 const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, long nMinWidth,
1613 ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
1614 {
1615 m_vLineList.emplace_back(new ImpLineListData(
1616 rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn));
1617 }
1618
UpdatePaintLineColor()1619 void SvtLineListBox::UpdatePaintLineColor()
1620 {
1621 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
1622 Color aNewCol(rSettings.GetWindowColor().IsDark() ? rSettings.GetLabelTextColor() : aColor);
1623
1624 bool bRet = aNewCol != maPaintCol;
1625
1626 if( bRet )
1627 maPaintCol = aNewCol;
1628 }
1629
UpdateEntries()1630 void SvtLineListBox::UpdateEntries()
1631 {
1632 UpdatePaintLineColor( );
1633
1634 SvxBorderLineStyle eSelected = GetSelectEntryStyle();
1635
1636 // Remove the old entries
1637 m_xLineSet->Clear();
1638
1639 // Add the new entries based on the defined width
1640
1641 sal_uInt16 n = 0;
1642 sal_uInt16 nCount = m_vLineList.size( );
1643 while ( n < nCount )
1644 {
1645 auto& pData = m_vLineList[ n ];
1646 BitmapEx aBmp;
1647 ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
1648 pData->GetLine2ForWidth( m_nWidth ),
1649 pData->GetDistForWidth( m_nWidth ),
1650 GetColorLine1(m_xLineSet->GetItemCount()),
1651 GetColorLine2(m_xLineSet->GetItemCount()),
1652 GetColorDist(m_xLineSet->GetItemCount()),
1653 pData->GetStyle(), aBmp );
1654 sal_Int16 nItemId = static_cast<sal_Int16>(pData->GetStyle()) + 1;
1655 m_xLineSet->InsertItem(nItemId, Image(aBmp), GetLineStyleName(pData->GetStyle()));
1656 if (pData->GetStyle() == eSelected)
1657 m_xLineSet->SelectItem(nItemId);
1658 n++;
1659 }
1660
1661 m_xLineSet->SetOptimalSize();
1662 }
1663
GetColorLine1(sal_Int32 nPos)1664 Color SvtLineListBox::GetColorLine1( sal_Int32 nPos )
1665 {
1666 sal_Int32 nStyle = GetStylePos( nPos );
1667 if (nStyle == LISTBOX_ENTRY_NOTFOUND)
1668 return GetPaintColor( );
1669 auto& pData = m_vLineList[ nStyle ];
1670 return pData->GetColorLine1( GetColor( ) );
1671 }
1672
GetColorLine2(sal_Int32 nPos)1673 Color SvtLineListBox::GetColorLine2( sal_Int32 nPos )
1674 {
1675 sal_Int32 nStyle = GetStylePos(nPos);
1676 if (nStyle == LISTBOX_ENTRY_NOTFOUND)
1677 return GetPaintColor( );
1678 auto& pData = m_vLineList[ nStyle ];
1679 return pData->GetColorLine2( GetColor( ) );
1680 }
1681
GetColorDist(sal_Int32 nPos)1682 Color SvtLineListBox::GetColorDist( sal_Int32 nPos )
1683 {
1684 const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
1685 Color rResult = rSettings.GetFieldColor();
1686
1687 sal_Int32 nStyle = GetStylePos( nPos );
1688 if (nStyle == LISTBOX_ENTRY_NOTFOUND)
1689 return rResult;
1690 auto& pData = m_vLineList[ nStyle ];
1691 return pData->GetColorDist( GetColor( ), rResult );
1692 }
1693
IMPL_LINK_NOARG(SvtLineListBox,StyleUpdated,weld::Widget &,void)1694 IMPL_LINK_NOARG(SvtLineListBox, StyleUpdated, weld::Widget&, void)
1695 {
1696 UpdateEntries();
1697 }
1698
IMPL_LINK_NOARG(SvtLineListBox,ValueSelectHdl,SvtValueSet *,void)1699 IMPL_LINK_NOARG(SvtLineListBox, ValueSelectHdl, SvtValueSet*, void)
1700 {
1701 maSelectHdl.Call(*this);
1702 UpdatePreview();
1703 if (m_xControl->get_active())
1704 m_xControl->set_active(false);
1705 }
1706
UpdatePreview()1707 void SvtLineListBox::UpdatePreview()
1708 {
1709 SvxBorderLineStyle eStyle = GetSelectEntryStyle();
1710 for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE); ++i)
1711 {
1712 if (eStyle == RID_SVXSTR_BORDERLINE[i].second)
1713 {
1714 m_xControl->set_label(SvtResId(RID_SVXSTR_BORDERLINE[i].first));
1715 break;
1716 }
1717 }
1718
1719 if (eStyle == SvxBorderLineStyle::NONE)
1720 {
1721 m_xControl->set_image(nullptr);
1722 m_xControl->set_label(GetLineStyleName(SvxBorderLineStyle::NONE));
1723 }
1724 else
1725 {
1726 Image aImage(m_xLineSet->GetItemImage(m_xLineSet->GetSelectedItemId()));
1727 m_xControl->set_label("");
1728 const auto nPos = (aVirDev->GetOutputSizePixel().Height() - aImage.GetSizePixel().Height()) / 2;
1729 aVirDev->Push(PushFlags::MAPMODE);
1730 aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
1731 aVirDev->Erase();
1732 aVirDev->DrawImage(Point(0, nPos), aImage);
1733 m_xControl->set_image(aVirDev.get());
1734 aVirDev->Pop();
1735 }
1736 }
1737
SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl)1738 SvtCalendarBox::SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl)
1739 : m_xControl(std::move(pControl))
1740 , m_xBuilder(Application::CreateBuilder(m_xControl.get(), "svt/ui/datewindow.ui"))
1741 , m_xTopLevel(m_xBuilder->weld_widget("date_popup_window"))
1742 , m_xCalendar(m_xBuilder->weld_calendar("date"))
1743 {
1744 m_xControl->set_popover(m_xTopLevel.get());
1745 m_xCalendar->connect_selected(LINK(this, SvtCalendarBox, SelectHdl));
1746 m_xCalendar->connect_activated(LINK(this, SvtCalendarBox, ActivateHdl));
1747 }
1748
set_date(const Date & rDate)1749 void SvtCalendarBox::set_date(const Date& rDate)
1750 {
1751 m_xCalendar->set_date(rDate);
1752 set_label_from_date();
1753 }
1754
set_label_from_date()1755 void SvtCalendarBox::set_label_from_date()
1756 {
1757 const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
1758 m_xControl->set_label(rLocaleData.getDate(m_xCalendar->get_date()));
1759 }
1760
IMPL_LINK_NOARG(SvtCalendarBox,SelectHdl,weld::Calendar &,void)1761 IMPL_LINK_NOARG(SvtCalendarBox, SelectHdl, weld::Calendar&, void)
1762 {
1763 set_label_from_date();
1764 }
1765
IMPL_LINK_NOARG(SvtCalendarBox,ActivateHdl,weld::Calendar &,void)1766 IMPL_LINK_NOARG(SvtCalendarBox, ActivateHdl, weld::Calendar&, void)
1767 {
1768 if (m_xControl->get_active())
1769 m_xControl->set_active(false);
1770 m_aActivatedHdl.Call(*this);
1771 }
1772
~SvtCalendarBox()1773 SvtCalendarBox::~SvtCalendarBox()
1774 {
1775 }
1776
1777 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1778