1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
21 #include <config_folders.h>
23 #include <comphelper/lok.hxx>
24 #include <i18nutil/unicode.hxx>
25 #include <officecfg/Office/Common.hxx>
26 #include <tools/stream.hxx>
27 #include <vcl/customweld.hxx>
28 #include <vcl/event.hxx>
29 #include <vcl/svapp.hxx>
30 #include <vcl/fieldvalues.hxx>
31 #include <vcl/settings.hxx>
32 #include <vcl/image.hxx>
33 #include <vcl/virdev.hxx>
34 #include <vcl/weldutils.hxx>
35 #include <rtl/math.hxx>
36 #include <sal/macros.h>
37 #include <sal/log.hxx>
38 #include <comphelper/string.hxx>
39 #include <unotools/localedatawrapper.hxx>
40 #include <unotools/syslocale.hxx>
42 #include <svtools/borderline.hxx>
43 #include <svtools/sampletext.hxx>
44 #include <svtools/svtresid.hxx>
45 #include <svtools/strings.hrc>
46 #include <svtools/ctrlbox.hxx>
47 #include <svtools/ctrltool.hxx>
48 #include <svtools/borderhelper.hxx>
49 #include <svtools/valueset.hxx>
51 #include <basegfx/polygon/b2dpolygon.hxx>
52 #include <basegfx/polygon/b2dpolygontools.hxx>
53 #include <editeng/borderline.hxx>
55 #include <rtl/bootstrap.hxx>
57 #include <borderline.hrc>
61 #define IMGOUTERTEXTSPACE 5
62 #define EXTRAFONTSIZE 5
63 #define GAPTOEXTRAPREVIEW 10
66 constexpr OUStringLiteral FONTNAMEBOXMRUENTRIESFILE
= u
"/user/config/fontnameboxmruentries";
69 BorderWidthImpl::BorderWidthImpl( BorderWidthImplFlags nFlags
, double nRate1
, double nRate2
, double nRateGap
):
73 m_nRateGap( nRateGap
)
77 bool BorderWidthImpl::operator== ( const BorderWidthImpl
& r
) const
79 return ( m_nFlags
== r
.m_nFlags
) &&
80 ( m_nRate1
== r
.m_nRate1
) &&
81 ( m_nRate2
== r
.m_nRate2
) &&
82 ( m_nRateGap
== r
.m_nRateGap
);
85 tools::Long
BorderWidthImpl::GetLine1( tools::Long nWidth
) const
87 tools::Long result
= static_cast<tools::Long
>(m_nRate1
);
88 if ( m_nFlags
& BorderWidthImplFlags::CHANGE_LINE1
)
90 tools::Long
const nConstant2
= (m_nFlags
& BorderWidthImplFlags::CHANGE_LINE2
) ? 0 : m_nRate2
;
91 tools::Long
const nConstantD
= (m_nFlags
& BorderWidthImplFlags::CHANGE_DIST
) ? 0 : m_nRateGap
;
92 result
= std::max
<tools::Long
>(0,
93 static_cast<tools::Long
>((m_nRate1
* nWidth
) + 0.5)
94 - (nConstant2
+ nConstantD
));
95 if (result
== 0 && m_nRate1
> 0.0 && nWidth
> 0)
96 { // fdo#51777: hack to essentially treat 1 twip DOUBLE border
97 result
= 1; // as 1 twip SINGLE border
103 tools::Long
BorderWidthImpl::GetLine2( tools::Long nWidth
) const
105 tools::Long result
= static_cast<tools::Long
>(m_nRate2
);
106 if ( m_nFlags
& BorderWidthImplFlags::CHANGE_LINE2
)
108 tools::Long
const nConstant1
= (m_nFlags
& BorderWidthImplFlags::CHANGE_LINE1
) ? 0 : m_nRate1
;
109 tools::Long
const nConstantD
= (m_nFlags
& BorderWidthImplFlags::CHANGE_DIST
) ? 0 : m_nRateGap
;
110 result
= std::max
<tools::Long
>(0,
111 static_cast<tools::Long
>((m_nRate2
* nWidth
) + 0.5)
112 - (nConstant1
+ nConstantD
));
117 tools::Long
BorderWidthImpl::GetGap( tools::Long nWidth
) const
119 tools::Long result
= static_cast<tools::Long
>(m_nRateGap
);
120 if ( m_nFlags
& BorderWidthImplFlags::CHANGE_DIST
)
122 tools::Long
const nConstant1
= (m_nFlags
& BorderWidthImplFlags::CHANGE_LINE1
) ? 0 : m_nRate1
;
123 tools::Long
const nConstant2
= (m_nFlags
& BorderWidthImplFlags::CHANGE_LINE2
) ? 0 : m_nRate2
;
124 result
= std::max
<tools::Long
>(0,
125 static_cast<tools::Long
>((m_nRateGap
* nWidth
) + 0.5)
126 - (nConstant1
+ nConstant2
));
129 // Avoid having too small distances (less than 0.1pt)
130 if ( result
< MINGAPWIDTH
&& m_nRate1
> 0 && m_nRate2
> 0 )
131 result
= MINGAPWIDTH
;
136 static double lcl_getGuessedWidth( tools::Long nTested
, double nRate
, bool bChanging
)
138 double nWidth
= -1.0;
140 nWidth
= double( nTested
) / nRate
;
143 if ( rtl::math::approxEqual(double( nTested
), nRate
) )
150 tools::Long
BorderWidthImpl::GuessWidth( tools::Long nLine1
, tools::Long nLine2
, tools::Long nGap
)
152 std::vector
< double > aToCompare
;
153 bool bInvalid
= false;
155 bool bLine1Change
= bool( m_nFlags
& BorderWidthImplFlags::CHANGE_LINE1
);
156 double nWidth1
= lcl_getGuessedWidth( nLine1
, m_nRate1
, bLine1Change
);
158 aToCompare
.push_back( nWidth1
);
159 else if (nWidth1
< 0)
162 bool bLine2Change
= bool( m_nFlags
& BorderWidthImplFlags::CHANGE_LINE2
);
163 double nWidth2
= lcl_getGuessedWidth( nLine2
, m_nRate2
, bLine2Change
);
165 aToCompare
.push_back( nWidth2
);
166 else if (nWidth2
< 0)
169 bool bGapChange
= bool( m_nFlags
& BorderWidthImplFlags::CHANGE_DIST
);
170 double nWidthGap
= lcl_getGuessedWidth( nGap
, m_nRateGap
, bGapChange
);
171 if ( bGapChange
&& nGap
>= MINGAPWIDTH
)
172 aToCompare
.push_back( nWidthGap
);
173 else if ( !bGapChange
&& nWidthGap
< 0 )
176 // non-constant line width factors must sum to 1
177 assert((((bLine1Change
) ? m_nRate1
: 0) +
178 ((bLine2Change
) ? m_nRate2
: 0) +
179 ((bGapChange
) ? m_nRateGap
: 0)) - 1.0 < 0.00001 );
182 if ( (!bInvalid
) && (!aToCompare
.empty()) )
184 nWidth
= *aToCompare
.begin();
185 for (auto const& elem
: aToCompare
)
187 bInvalid
= ( nWidth
!= elem
);
191 nWidth
= bInvalid
? 0.0 : nLine1
+ nLine2
+ nGap
;
197 static void lclDrawPolygon( OutputDevice
& rDev
, const basegfx::B2DPolygon
& rPolygon
, tools::Long nWidth
, SvxBorderLineStyle nDashing
)
199 AntialiasingFlags nOldAA
= rDev
.GetAntialiasing();
200 rDev
.SetAntialiasing( nOldAA
& ~AntialiasingFlags::Enable
);
202 tools::Long nPix
= rDev
.PixelToLogic(Size(1, 1)).Width();
203 basegfx::B2DPolyPolygon aPolygons
= svtools::ApplyLineDashing(rPolygon
, nDashing
, nPix
);
205 // Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line
206 if (rDev
.GetMapMode().GetMapUnit() == MapUnit::MapPixel
&& nWidth
== nPix
)
209 for ( sal_uInt32 i
= 0; i
< aPolygons
.count( ); i
++ )
211 const basegfx::B2DPolygon
& aDash
= aPolygons
.getB2DPolygon( i
);
212 basegfx::B2DPoint aStart
= aDash
.getB2DPoint( 0 );
213 basegfx::B2DPoint aEnd
= aDash
.getB2DPoint( aDash
.count() - 1 );
215 basegfx::B2DVector
aVector( aEnd
- aStart
);
216 aVector
.normalize( );
217 const basegfx::B2DVector
aPerpendicular(basegfx::getPerpendicular(aVector
));
219 const basegfx::B2DVector
aWidthOffset( double( nWidth
) / 2 * aPerpendicular
);
220 basegfx::B2DPolygon aDashPolygon
;
221 aDashPolygon
.append( aStart
+ aWidthOffset
);
222 aDashPolygon
.append( aEnd
+ aWidthOffset
);
223 aDashPolygon
.append( aEnd
- aWidthOffset
);
224 aDashPolygon
.append( aStart
- aWidthOffset
);
225 aDashPolygon
.setClosed( true );
227 rDev
.DrawPolygon( aDashPolygon
);
230 rDev
.SetAntialiasing( nOldAA
);
236 * Dashing array must start with a line width and end with a blank width.
238 static std::vector
<double> GetDashing( SvxBorderLineStyle nDashing
)
240 std::vector
<double> aPattern
;
243 case SvxBorderLineStyle::DOTTED
:
244 aPattern
.push_back( 1.0 ); // line
245 aPattern
.push_back( 2.0 ); // blank
247 case SvxBorderLineStyle::DASHED
:
248 aPattern
.push_back( 16.0 ); // line
249 aPattern
.push_back( 5.0 ); // blank
251 case SvxBorderLineStyle::FINE_DASHED
:
252 aPattern
.push_back( 6.0 ); // line
253 aPattern
.push_back( 2.0 ); // blank
255 case SvxBorderLineStyle::DASH_DOT
:
256 aPattern
.push_back( 16.0 ); // line
257 aPattern
.push_back( 5.0 ); // blank
258 aPattern
.push_back( 5.0 ); // line
259 aPattern
.push_back( 5.0 ); // blank
261 case SvxBorderLineStyle::DASH_DOT_DOT
:
262 aPattern
.push_back( 16.0 ); // line
263 aPattern
.push_back( 5.0 ); // blank
264 aPattern
.push_back( 5.0 ); // line
265 aPattern
.push_back( 5.0 ); // blank
266 aPattern
.push_back( 5.0 ); // line
267 aPattern
.push_back( 5.0 ); // blank
282 explicit ApplyScale( double fScale
) : mfScale(fScale
) {}
283 void operator() ( double& rVal
)
291 std::vector
<double> GetLineDashing( SvxBorderLineStyle nDashing
, double fScale
)
293 std::vector
<double> aPattern
= GetDashing(nDashing
);
294 std::for_each(aPattern
.begin(), aPattern
.end(), ApplyScale(fScale
));
298 basegfx::B2DPolyPolygon
ApplyLineDashing( const basegfx::B2DPolygon
& rPolygon
, SvxBorderLineStyle nDashing
, double fScale
)
300 std::vector
<double> aPattern
= GetDashing(nDashing
);
301 std::for_each(aPattern
.begin(), aPattern
.end(), ApplyScale(fScale
));
303 basegfx::B2DPolyPolygon aPolygons
;
305 if (aPattern
.empty())
306 aPolygons
.append(rPolygon
);
308 basegfx::utils::applyLineDashing(rPolygon
, aPattern
, &aPolygons
);
313 void DrawLine( OutputDevice
& rDev
, const Point
& rP1
, const Point
& rP2
,
314 sal_uInt32 nWidth
, SvxBorderLineStyle nDashing
)
316 DrawLine( rDev
, basegfx::B2DPoint( rP1
.X(), rP1
.Y() ),
317 basegfx::B2DPoint( rP2
.X(), rP2
.Y( ) ), nWidth
, nDashing
);
320 void DrawLine( OutputDevice
& rDev
, const basegfx::B2DPoint
& rP1
, const basegfx::B2DPoint
& rP2
,
321 sal_uInt32 nWidth
, SvxBorderLineStyle nDashing
)
323 basegfx::B2DPolygon aPolygon
;
324 aPolygon
.append( rP1
);
325 aPolygon
.append( rP2
);
326 lclDrawPolygon( rDev
, aPolygon
, nWidth
, nDashing
);
331 static Size gUserItemSz
;
332 static int gFontNameBoxes
;
333 static size_t gPreviewsPerDevice
;
334 static std::vector
<VclPtr
<VirtualDevice
>> gFontPreviewVirDevs
;
335 static std::vector
<OUString
> gRenderedFontNames
;
339 void calcCustomItemSize(const weld::ComboBox
& rComboBox
)
341 gUserItemSz
= Size(rComboBox
.get_approximate_digit_width() * 52, rComboBox
.get_text_height());
342 gUserItemSz
.setHeight(gUserItemSz
.Height() * 16);
343 gUserItemSz
.setHeight(gUserItemSz
.Height() / 10);
345 size_t nMaxDeviceHeight
= SAL_MAX_INT16
/ 2; // see limitXCreatePixmap
346 gPreviewsPerDevice
= nMaxDeviceHeight
/ gUserItemSz
.Height();
350 IMPL_LINK(FontNameBox
, SettingsChangedHdl
, VclSimpleEvent
&, rEvent
, void)
352 if (rEvent
.GetId() != VclEventId::ApplicationDataChanged
)
355 DataChangedEvent
* pData
= static_cast<DataChangedEvent
*>(static_cast<VclWindowEvent
&>(rEvent
).GetData());
356 if (pData
->GetType() == DataChangedEventType::SETTINGS
)
358 gFontPreviewVirDevs
.clear();
359 gRenderedFontNames
.clear();
360 calcCustomItemSize(*m_xComboBox
);
361 if (mbWYSIWYG
&& mpFontList
&& !mpFontList
->empty())
363 mnPreviewProgress
= 0;
364 maUpdateIdle
.Start();
369 FontNameBox::FontNameBox(std::unique_ptr
<weld::ComboBox
> p
)
370 : m_xComboBox(std::move(p
))
371 , mnPreviewProgress(0)
373 , maUpdateIdle("FontNameBox Preview Update")
376 InitFontMRUEntriesFile();
378 maUpdateIdle
.SetPriority(TaskPriority::LOWEST
);
379 maUpdateIdle
.SetInvokeHandler(LINK(this, FontNameBox
, UpdateHdl
));
381 Application::AddEventListener(LINK(this, FontNameBox
, SettingsChangedHdl
));
384 FontNameBox::~FontNameBox()
386 Application::RemoveEventListener(LINK(this, FontNameBox
, SettingsChangedHdl
));
390 SaveMRUEntries (maFontMRUEntriesFile
);
391 ImplDestroyFontList();
396 for (auto &rDev
: gFontPreviewVirDevs
)
397 rDev
.disposeAndClear();
398 gFontPreviewVirDevs
.clear();
399 gRenderedFontNames
.clear();
403 void FontNameBox::SaveMRUEntries(const OUString
& aFontMRUEntriesFile
) const
405 OString
aEntries(OUStringToOString(m_xComboBox
->get_mru_entries(),
406 RTL_TEXTENCODING_UTF8
));
408 if (aEntries
.isEmpty() || aFontMRUEntriesFile
.isEmpty())
411 SvFileStream aStream
;
412 aStream
.Open( aFontMRUEntriesFile
, StreamMode::WRITE
| StreamMode::TRUNC
);
413 if( ! (aStream
.IsOpen() && aStream
.IsWritable()) )
415 SAL_INFO("svtools.control", "FontNameBox::SaveMRUEntries: opening mru entries file " << aFontMRUEntriesFile
<< " failed");
419 aStream
.SetLineDelimiter( LINEEND_LF
);
420 aStream
.WriteLine( aEntries
);
421 aStream
.WriteLine( "" );
424 void FontNameBox::LoadMRUEntries( const OUString
& aFontMRUEntriesFile
)
426 if (aFontMRUEntriesFile
.isEmpty())
429 if (!officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::get())
432 SvFileStream
aStream( aFontMRUEntriesFile
, StreamMode::READ
);
433 if( ! aStream
.IsOpen() )
435 SAL_INFO("svtools.control", "FontNameBox::LoadMRUEntries: opening mru entries file " << aFontMRUEntriesFile
<< " failed");
440 aStream
.ReadLine( aLine
);
441 OUString aEntries
= OStringToOUString(aLine
,
442 RTL_TEXTENCODING_UTF8
);
443 m_xComboBox
->set_mru_entries(aEntries
);
446 void FontNameBox::InitFontMRUEntriesFile()
448 OUString
sUserConfigDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}");
449 rtl::Bootstrap::expandMacros(sUserConfigDir
);
451 maFontMRUEntriesFile
= sUserConfigDir
;
452 if( !maFontMRUEntriesFile
.isEmpty() )
454 maFontMRUEntriesFile
+= FONTNAMEBOXMRUENTRIESFILE
;
458 void FontNameBox::ImplDestroyFontList()
461 mnPreviewProgress
= 0;
465 void FontNameBox::Fill( const FontList
* pList
)
467 // store old text and clear box
468 OUString aOldText
= m_xComboBox
->get_active_text();
469 OUString rEntries
= m_xComboBox
->get_mru_entries();
470 bool bLoadFromFile
= rEntries
.isEmpty();
471 m_xComboBox
->freeze();
472 m_xComboBox
->clear();
474 ImplDestroyFontList();
475 mpFontList
.reset(new ImplFontList
);
478 size_t nFontCount
= pList
->GetFontNameCount();
479 for (size_t i
= 0; i
< nFontCount
; ++i
)
481 const FontMetric
& rFontMetric
= pList
->GetFontName(i
);
482 m_xComboBox
->append(OUString::number(i
), rFontMetric
.GetFamilyName());
483 mpFontList
->push_back(rFontMetric
);
487 LoadMRUEntries(maFontMRUEntriesFile
);
489 m_xComboBox
->set_mru_entries(rEntries
);
493 if (mbWYSIWYG
&& nFontCount
)
495 assert(mnPreviewProgress
== 0 && "ImplDestroyFontList wasn't called");
496 maUpdateIdle
.Start();
500 if (!aOldText
.isEmpty())
501 set_active_or_entry_text(aOldText
);
504 void FontNameBox::EnableWYSIWYG(bool bEnable
)
506 if (comphelper::LibreOfficeKit::isActive())
508 if (mbWYSIWYG
== bEnable
)
514 calcCustomItemSize(*m_xComboBox
);
515 m_xComboBox
->connect_custom_get_size(LINK(this, FontNameBox
, CustomGetSizeHdl
));
516 m_xComboBox
->connect_custom_render(LINK(this, FontNameBox
, CustomRenderHdl
));
520 m_xComboBox
->connect_custom_get_size(Link
<OutputDevice
&, Size
>());
521 m_xComboBox
->connect_custom_render(Link
<weld::ComboBox::render_args
, void>());
523 m_xComboBox
->set_custom_renderer(mbWYSIWYG
);
526 IMPL_LINK_NOARG(FontNameBox
, CustomGetSizeHdl
, OutputDevice
&, Size
)
528 return mbWYSIWYG
? gUserItemSz
: Size();
533 tools::Long
shrinkFontToFit(OUString
const &rSampleText
, tools::Long nH
, vcl::Font
&rFont
, OutputDevice
&rDevice
, tools::Rectangle
&rTextRect
)
535 tools::Long nWidth
= 0;
537 Size
aSize( rFont
.GetFontSize() );
539 //Make sure it fits in the available height
540 while (aSize
.Height() > 0)
542 if (!rDevice
.GetTextBoundRect(rTextRect
, rSampleText
))
544 if (rTextRect
.GetHeight() <= nH
)
546 nWidth
= rTextRect
.GetWidth();
550 aSize
.AdjustHeight( -(EXTRAFONTSIZE
) );
551 rFont
.SetFontSize(aSize
);
552 rDevice
.SetFont(rFont
);
559 IMPL_LINK_NOARG(FontNameBox
, UpdateHdl
, Timer
*, void)
561 CachePreview(mnPreviewProgress
++, nullptr);
562 // tdf#132536 limit to ~25 pre-rendered for now. The font caches look
563 // b0rked, the massive charmaps are ~never swapped out, and don't count
564 // towards the size of a font in the font cache.
565 if (mnPreviewProgress
< std::min
<size_t>(25, mpFontList
->size()))
566 maUpdateIdle
.Start();
569 static void DrawPreview(const FontMetric
& rFontMetric
, const Point
& rTopLeft
, OutputDevice
& rDevice
, bool bSelected
)
571 rDevice
.Push(vcl::PushFlags::TEXTCOLOR
);
573 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
575 rDevice
.SetTextColor(rStyleSettings
.GetHighlightTextColor());
577 rDevice
.SetTextColor(rStyleSettings
.GetDialogTextColor());
579 tools::Long nX
= rTopLeft
.X();
580 tools::Long nH
= gUserItemSz
.Height();
582 nX
+= IMGOUTERTEXTSPACE
;
584 const bool bSymbolFont
= isSymbolFont(rFontMetric
);
586 vcl::Font
aOldFont(rDevice
.GetFont());
587 Size
aSize( aOldFont
.GetFontSize() );
588 aSize
.AdjustHeight(EXTRAFONTSIZE
);
589 vcl::Font
aFont( rFontMetric
);
590 aFont
.SetFontSize( aSize
);
591 rDevice
.SetFont(aFont
);
593 bool bUsingCorrectFont
= true;
594 tools::Rectangle aTextRect
;
596 // Preview the font name
597 const OUString
& sFontName
= rFontMetric
.GetFamilyName();
599 //If it shouldn't or can't draw its own name because it doesn't have the glyphs
600 if (!canRenderNameOfSelectedFont(rDevice
))
601 bUsingCorrectFont
= false;
604 //Make sure it fits in the available height, shrinking the font if necessary
605 bUsingCorrectFont
= shrinkFontToFit(sFontName
, nH
, aFont
, rDevice
, aTextRect
) != 0;
608 if (!bUsingCorrectFont
)
610 rDevice
.SetFont(aOldFont
);
611 rDevice
.GetTextBoundRect(aTextRect
, sFontName
);
614 tools::Long nTextHeight
= aTextRect
.GetHeight();
615 tools::Long nDesiredGap
= (nH
-nTextHeight
)/2;
616 tools::Long nVertAdjust
= nDesiredGap
- aTextRect
.Top();
617 Point
aPos( nX
, rTopLeft
.Y() + nVertAdjust
);
618 rDevice
.DrawText(aPos
, sFontName
);
619 tools::Long nTextX
= aPos
.X() + aTextRect
.GetWidth() + GAPTOEXTRAPREVIEW
;
621 if (!bUsingCorrectFont
)
622 rDevice
.SetFont(aFont
);
624 OUString sSampleText
;
628 const bool bNameBeginsWithLatinText
= rFontMetric
.GetFamilyName()[0] <= 'z';
630 if (bNameBeginsWithLatinText
|| !bUsingCorrectFont
)
631 sSampleText
= makeShortRepresentativeTextForSelectedFont(rDevice
);
634 //If we're not a symbol font, but could neither render our own name and
635 //we can't determine what script it would like to render, then try a
636 //few well known scripts
637 if (sSampleText
.isEmpty() && !bUsingCorrectFont
)
639 static const UScriptCode aScripts
[] =
668 USCRIPT_SIMPLIFIED_HAN
,
669 USCRIPT_TRADITIONAL_HAN
,
674 for (const UScriptCode
& rScript
: aScripts
)
676 OUString sText
= makeShortRepresentativeTextForScript(rScript
);
677 if (!sText
.isEmpty())
679 bool bHasSampleTextGlyphs
= (-1 == rDevice
.HasGlyphs(aFont
, sText
));
680 if (bHasSampleTextGlyphs
)
688 static const UScriptCode aMinimalScripts
[] =
690 USCRIPT_HEBREW
, //e.g. biblical hebrew
694 for (const UScriptCode
& rMinimalScript
: aMinimalScripts
)
696 OUString sText
= makeShortMinimalTextForScript(rMinimalScript
);
697 if (!sText
.isEmpty())
699 bool bHasSampleTextGlyphs
= (-1 == rDevice
.HasGlyphs(aFont
, sText
));
700 if (bHasSampleTextGlyphs
)
709 //If we're a symbol font, or for some reason the font still couldn't
710 //render something representative of what it would like to render then
711 //make up some semi-random text that it *can* display
712 if (bSymbolFont
|| (!bUsingCorrectFont
&& sSampleText
.isEmpty()))
713 sSampleText
= makeShortRepresentativeSymbolTextForSelectedFont(rDevice
);
715 if (!sSampleText
.isEmpty())
717 const Size
&rItemSize
= gUserItemSz
;
719 //leave a little border at the edge
720 tools::Long nSpace
= rItemSize
.Width() - nTextX
- IMGOUTERTEXTSPACE
;
723 //Make sure it fits in the available height, and get how wide that would be
724 tools::Long nWidth
= shrinkFontToFit(sSampleText
, nH
, aFont
, rDevice
, aTextRect
);
725 //Chop letters off until it fits in the available width
726 while (nWidth
> nSpace
|| nWidth
> gUserItemSz
.Width())
728 sSampleText
= sSampleText
.copy(0, sSampleText
.getLength()-1);
729 nWidth
= rDevice
.GetTextBoundRect(aTextRect
, sSampleText
) ?
730 aTextRect
.GetWidth() : 0;
733 //center the text on the line
734 if (!sSampleText
.isEmpty() && nWidth
)
736 nTextHeight
= aTextRect
.GetHeight();
737 nDesiredGap
= (nH
-nTextHeight
)/2;
738 nVertAdjust
= nDesiredGap
- aTextRect
.Top();
739 aPos
= Point(nTextX
+ nSpace
- nWidth
, rTopLeft
.Y() + nVertAdjust
);
740 rDevice
.DrawText(aPos
, sSampleText
);
745 rDevice
.SetFont(aOldFont
);
749 OutputDevice
& FontNameBox::CachePreview(size_t nIndex
, Point
* pTopLeft
)
751 SolarMutexGuard aGuard
;
752 const FontMetric
& rFontMetric
= (*mpFontList
)[nIndex
];
753 const OUString
& rFontName
= rFontMetric
.GetFamilyName();
755 size_t nPreviewIndex
;
756 auto xFind
= std::find(gRenderedFontNames
.begin(), gRenderedFontNames
.end(), rFontName
);
757 bool bPreviewAvailable
= xFind
!= gRenderedFontNames
.end();
758 if (!bPreviewAvailable
)
760 nPreviewIndex
= gRenderedFontNames
.size();
761 gRenderedFontNames
.push_back(rFontName
);
764 nPreviewIndex
= std::distance(gRenderedFontNames
.begin(), xFind
);
766 size_t nPage
= nPreviewIndex
/ gPreviewsPerDevice
;
767 size_t nIndexInPage
= nPreviewIndex
- (nPage
* gPreviewsPerDevice
);
769 Point
aTopLeft(0, gUserItemSz
.Height() * nIndexInPage
);
771 if (!bPreviewAvailable
)
773 if (nPage
>= gFontPreviewVirDevs
.size())
775 gFontPreviewVirDevs
.emplace_back(m_xComboBox
->create_render_virtual_device());
776 VirtualDevice
& rDevice
= *gFontPreviewVirDevs
.back();
777 rDevice
.SetOutputSizePixel(Size(gUserItemSz
.Width(), gUserItemSz
.Height() * gPreviewsPerDevice
));
778 weld::SetPointFont(rDevice
, m_xComboBox
->get_font());
779 assert(gFontPreviewVirDevs
.size() == nPage
+ 1);
782 DrawPreview(rFontMetric
, aTopLeft
, *gFontPreviewVirDevs
.back(), false);
786 *pTopLeft
= aTopLeft
;
788 return *gFontPreviewVirDevs
[nPage
];
791 IMPL_LINK(FontNameBox
, CustomRenderHdl
, weld::ComboBox::render_args
, aPayload
, void)
793 vcl::RenderContext
& rRenderContext
= std::get
<0>(aPayload
);
794 const ::tools::Rectangle
& rRect
= std::get
<1>(aPayload
);
795 bool bSelected
= std::get
<2>(aPayload
);
796 const OUString
& rId
= std::get
<3>(aPayload
);
798 sal_uInt32 nIndex
= rId
.toUInt32();
800 Point
aDestPoint(rRect
.TopLeft());
801 auto nMargin
= (rRect
.GetHeight() - gUserItemSz
.Height()) / 2;
802 aDestPoint
.AdjustY(nMargin
);
806 const FontMetric
& rFontMetric
= (*mpFontList
)[nIndex
];
807 DrawPreview(rFontMetric
, aDestPoint
, rRenderContext
, true);
811 // use cache of unselected entries
813 OutputDevice
& rDevice
= CachePreview(nIndex
, &aTopLeft
);
815 rRenderContext
.DrawOutDev(aDestPoint
, gUserItemSz
,
816 aTopLeft
, gUserItemSz
,
821 void FontNameBox::set_active_or_entry_text(const OUString
& rText
)
823 const int nFound
= m_xComboBox
->find_text(rText
);
825 m_xComboBox
->set_active(nFound
);
826 m_xComboBox
->set_entry_text(rText
);
829 FontStyleBox::FontStyleBox(std::unique_ptr
<weld::ComboBox
> p
)
830 : m_xComboBox(std::move(p
))
832 //Use the standard texts to get an optimal size and stick to that size.
833 //That should stop the character dialog dancing around.
834 auto nMaxLen
= m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHT
)).Width();
835 nMaxLen
= std::max(nMaxLen
, m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHT_ITALIC
)).Width());
836 nMaxLen
= std::max(nMaxLen
, m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMAL
)).Width());
837 nMaxLen
= std::max(nMaxLen
, m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMAL_ITALIC
)).Width());
838 nMaxLen
= std::max(nMaxLen
, m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLD
)).Width());
839 nMaxLen
= std::max(nMaxLen
, m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLD_ITALIC
)).Width());
840 nMaxLen
= std::max(nMaxLen
, m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACK
)).Width());
841 nMaxLen
= std::max(nMaxLen
, m_xComboBox
->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACK_ITALIC
)).Width());
842 m_xComboBox
->set_entry_width_chars(std::ceil(nMaxLen
/ m_xComboBox
->get_approximate_digit_width()));
845 void FontStyleBox::Fill( const OUString
& rName
, const FontList
* pList
)
847 OUString aOldText
= m_xComboBox
->get_active_text();
848 int nPos
= m_xComboBox
->get_active();
850 m_xComboBox
->freeze();
851 m_xComboBox
->clear();
853 // does a font with this name already exist?
854 sal_Handle hFontMetric
= pList
->GetFirstFontMetric( rName
);
858 FontWeight eLastWeight
= WEIGHT_DONTKNOW
;
859 FontItalic eLastItalic
= ITALIC_NONE
;
860 FontWidth eLastWidth
= WIDTH_DONTKNOW
;
861 bool bNormal
= false;
862 bool bItalic
= false;
864 bool bBoldItalic
= false;
865 bool bInsert
= false;
866 FontMetric aFontMetric
;
867 while ( hFontMetric
)
869 aFontMetric
= FontList::GetFontMetric( hFontMetric
);
871 FontWeight eWeight
= aFontMetric
.GetWeight();
872 FontItalic eItalic
= aFontMetric
.GetItalic();
873 FontWidth eWidth
= aFontMetric
.GetWidthType();
874 // Only if the attributes are different, we insert the
875 // Font to avoid double Entries in different languages
876 if ( (eWeight
!= eLastWeight
) || (eItalic
!= eLastItalic
) ||
877 (eWidth
!= eLastWidth
) )
880 m_xComboBox
->append_text(aStyleText
);
882 if ( eWeight
<= WEIGHT_NORMAL
)
884 if ( eItalic
!= ITALIC_NONE
)
891 if ( eItalic
!= ITALIC_NONE
)
897 // For wrong StyleNames we replace this with the correct once
898 aStyleText
= pList
->GetStyleName( aFontMetric
);
899 bInsert
= m_xComboBox
->find_text(aStyleText
) == -1;
902 aStyleText
= pList
->GetStyleName( eWeight
, eItalic
);
903 bInsert
= m_xComboBox
->find_text(aStyleText
) == -1;
906 eLastWeight
= eWeight
;
907 eLastItalic
= eItalic
;
914 // If we have two names for the same attributes
915 // we prefer the translated standard names
916 const OUString
& rAttrStyleText
= pList
->GetStyleName( eWeight
, eItalic
);
917 if (rAttrStyleText
!= aStyleText
)
919 OUString aTempStyleText
= pList
->GetStyleName( aFontMetric
);
920 if (rAttrStyleText
== aTempStyleText
)
921 aStyleText
= rAttrStyleText
;
922 bInsert
= m_xComboBox
->find_text(aStyleText
) == -1;
927 if ( !bItalic
&& (aStyleText
== pList
->GetItalicStr()) )
929 else if ( !bBold
&& (aStyleText
== pList
->GetBoldStr()) )
931 else if ( !bBoldItalic
&& (aStyleText
== pList
->GetBoldItalicStr()) )
934 hFontMetric
= FontList::GetNextFontMetric( hFontMetric
);
938 m_xComboBox
->append_text(aStyleText
);
940 // certain style as copy
944 m_xComboBox
->append_text(pList
->GetItalicStr());
946 m_xComboBox
->append_text(pList
->GetBoldStr());
950 if ( bNormal
|| bItalic
|| bBold
)
951 m_xComboBox
->append_text(pList
->GetBoldItalicStr());
956 // insert standard styles if no font
957 m_xComboBox
->append_text(pList
->GetNormalStr());
958 m_xComboBox
->append_text(pList
->GetItalicStr());
959 m_xComboBox
->append_text(pList
->GetBoldStr());
960 m_xComboBox
->append_text(pList
->GetBoldItalicStr());
965 if (!aOldText
.isEmpty())
967 int nFound
= m_xComboBox
->find_text(aOldText
);
969 m_xComboBox
->set_active(nFound
);
972 if (nPos
>= m_xComboBox
->get_count())
973 m_xComboBox
->set_active(0);
975 m_xComboBox
->set_active(nPos
);
980 FontSizeBox::FontSizeBox(std::unique_ptr
<weld::ComboBox
> p
)
985 , eUnit(FieldUnit::POINT
)
993 , bRelativeMode(false)
997 , m_xComboBox(std::move(p
))
999 m_xComboBox
->set_entry_width_chars(std::ceil(m_xComboBox
->get_pixel_size(format_number(105)).Width() /
1000 m_xComboBox
->get_approximate_digit_width()));
1001 m_xComboBox
->connect_focus_out(LINK(this, FontSizeBox
, ReformatHdl
));
1002 m_xComboBox
->connect_changed(LINK(this, FontSizeBox
, ModifyHdl
));
1005 void FontSizeBox::set_active_or_entry_text(const OUString
& rText
)
1007 const int nFound
= m_xComboBox
->find_text(rText
);
1009 m_xComboBox
->set_active(nFound
);
1010 m_xComboBox
->set_entry_text(rText
);
1013 IMPL_LINK(FontSizeBox
, ReformatHdl
, weld::Widget
&, rWidget
, void)
1015 FontSizeNames
aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1016 if (!bRelativeMode
|| !aFontSizeNames
.IsEmpty())
1018 if (aFontSizeNames
.Name2Size(m_xComboBox
->get_active_text()) != 0)
1022 set_value(get_value());
1024 m_aFocusOutHdl
.Call(rWidget
);
1027 IMPL_LINK(FontSizeBox
, ModifyHdl
, weld::ComboBox
&, rBox
, void)
1031 OUString aStr
= comphelper::string::stripStart(rBox
.get_active_text(), ' ');
1033 bool bNewMode
= bRelative
;
1034 bool bOldPtRelMode
= bPtRelative
;
1038 bPtRelative
= false;
1039 const sal_Unicode
* pStr
= aStr
.getStr();
1042 if ( ((*pStr
< '0') || (*pStr
> '9')) && (*pStr
!= '%') && !unicode::isSpace(*pStr
) )
1044 if ( ('-' == *pStr
|| '+' == *pStr
) && !bPtRelative
)
1046 else if ( bPtRelative
&& 'p' == *pStr
&& 't' == *++pStr
)
1057 else if (!aStr
.isEmpty())
1059 if ( -1 != aStr
.indexOf('%') )
1062 bPtRelative
= false;
1065 if ( '-' == aStr
[0] || '+' == aStr
[0] )
1072 if ( bNewMode
!= bRelative
|| bPtRelative
!= bOldPtRelMode
)
1073 SetRelative( bNewMode
);
1075 m_aChangeHdl
.Call(rBox
);
1078 void FontSizeBox::Fill( const FontList
* pList
)
1080 // remember for relative mode
1083 // no font sizes need to be set for relative mode
1088 const int* pTempAry
;
1089 const int* pAry
= nullptr;
1091 pAry
= FontList::GetStdSizeAry();
1093 // first insert font size names (for simplified/traditional chinese)
1094 FontSizeNames
aFontSizeNames( Application::GetSettings().GetUILanguageTag().getLanguageType() );
1095 if ( pAry
== FontList::GetStdSizeAry() )
1097 // for standard sizes we don't need to bother
1098 if (bStdSize
&& m_xComboBox
->get_count() && aFontSizeNames
.IsEmpty())
1105 int nSelectionStart
, nSelectionEnd
;
1106 m_xComboBox
->get_entry_selection_bounds(nSelectionStart
, nSelectionEnd
);
1107 OUString aStr
= m_xComboBox
->get_active_text();
1109 m_xComboBox
->freeze();
1110 m_xComboBox
->clear();
1113 if ( !aFontSizeNames
.IsEmpty() )
1115 if ( pAry
== FontList::GetStdSizeAry() )
1117 // for scalable fonts all font size names
1118 sal_uLong nCount
= aFontSizeNames
.Count();
1119 for( sal_uLong i
= 0; i
< nCount
; i
++ )
1121 OUString aSizeName
= aFontSizeNames
.GetIndexName( i
);
1122 int nSize
= aFontSizeNames
.GetIndexSize( i
);
1123 OUString
sId(OUString::number(-nSize
)); // mark as special
1124 m_xComboBox
->insert(nPos
, aSizeName
, &sId
, nullptr, nullptr);
1130 // for fixed size fonts only selectable font size names
1134 OUString aSizeName
= aFontSizeNames
.Size2Name( *pTempAry
);
1135 if ( !aSizeName
.isEmpty() )
1137 OUString
sId(OUString::number(-(*pTempAry
))); // mark as special
1138 m_xComboBox
->insert(nPos
, aSizeName
, &sId
, nullptr, nullptr);
1146 // then insert numerical font size values
1150 InsertValue(*pTempAry
);
1154 set_active_or_entry_text(aStr
);
1155 m_xComboBox
->select_entry_region(nSelectionStart
, nSelectionEnd
);
1156 m_xComboBox
->thaw();
1159 void FontSizeBox::EnableRelativeMode( sal_uInt16 nNewMin
, sal_uInt16 nNewMax
, sal_uInt16 nStep
)
1161 bRelativeMode
= true;
1165 SetUnit(FieldUnit::POINT
);
1168 void FontSizeBox::EnablePtRelativeMode( short nNewMin
, short nNewMax
, short nStep
)
1170 bRelativeMode
= true;
1171 nPtRelMin
= nNewMin
;
1172 nPtRelMax
= nNewMax
;
1174 SetUnit(FieldUnit::POINT
);
1177 void FontSizeBox::InsertValue(int i
)
1179 OUString
sNumber(OUString::number(i
));
1180 m_xComboBox
->append(sNumber
, format_number(i
));
1183 void FontSizeBox::SetRelative( bool bNewRelative
)
1185 if ( !bRelativeMode
)
1188 int nSelectionStart
, nSelectionEnd
;
1189 m_xComboBox
->get_entry_selection_bounds(nSelectionStart
, nSelectionEnd
);
1190 OUString aStr
= comphelper::string::stripStart(m_xComboBox
->get_active_text(), ' ');
1197 m_xComboBox
->clear();
1201 SetDecimalDigits( 1 );
1202 SetRange(nPtRelMin
, nPtRelMax
);
1203 SetUnit(FieldUnit::POINT
);
1205 short i
= nPtRelMin
, n
= 0;
1206 // JP 30.06.98: more than 100 values are not useful
1207 while ( i
<= nPtRelMax
&& n
++ < 100 )
1215 SetDecimalDigits(0);
1216 SetRange(nRelMin
, nRelMax
);
1217 SetUnit(FieldUnit::PERCENT
);
1219 sal_uInt16 i
= nRelMin
;
1220 while ( i
<= nRelMax
)
1230 m_xComboBox
->clear();
1231 bRelative
= bPtRelative
= false;
1232 SetDecimalDigits(1);
1234 SetUnit(FieldUnit::POINT
);
1239 set_active_or_entry_text(aStr
);
1240 m_xComboBox
->select_entry_region(nSelectionStart
, nSelectionEnd
);
1243 OUString
FontSizeBox::format_number(int nValue
) const
1247 //pawn percent off to icu to decide whether percent is separated from its number for this locale
1248 if (eUnit
== FieldUnit::PERCENT
)
1250 double fValue
= nValue
;
1251 fValue
/= weld::SpinButton::Power10(nDecimalDigits
);
1252 sRet
= unicode::formatPercent(fValue
, Application::GetSettings().GetUILanguageTag());
1256 const SvtSysLocale aSysLocale
;
1257 const LocaleDataWrapper
& rLocaleData
= aSysLocale
.GetLocaleData();
1258 sRet
= rLocaleData
.getNum(nValue
, nDecimalDigits
, true, false);
1259 if (eUnit
!= FieldUnit::NONE
&& eUnit
!= FieldUnit::DEGREE
)
1261 assert(eUnit
!= FieldUnit::PERCENT
);
1262 sRet
+= weld::MetricSpinButton::MetricToString(eUnit
);
1265 if (bRelativeMode
&& bPtRelative
&& (0 <= nValue
) && !sRet
.isEmpty())
1271 void FontSizeBox::SetValue(int nNewValue
, FieldUnit eInUnit
)
1273 auto nTempValue
= vcl::ConvertValue(nNewValue
, 0, GetDecimalDigits(), eInUnit
, GetUnit());
1274 if (nTempValue
< nMin
)
1276 else if (nTempValue
> nMax
)
1280 FontSizeNames
aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1281 // conversion loses precision; however font sizes should
1282 // never have a problem with that
1283 OUString aName
= aFontSizeNames
.Size2Name(nTempValue
);
1284 if (!aName
.isEmpty() && m_xComboBox
->find_text(aName
) != -1)
1286 m_xComboBox
->set_active_text(aName
);
1290 OUString aResult
= format_number(nTempValue
);
1291 set_active_or_entry_text(aResult
);
1294 void FontSizeBox::set_value(int nNewValue
)
1296 SetValue(nNewValue
, eUnit
);
1299 int FontSizeBox::get_value() const
1301 OUString aStr
= m_xComboBox
->get_active_text();
1304 FontSizeNames
aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
1305 auto nValue
= aFontSizeNames
.Name2Size(aStr
);
1307 return vcl::ConvertValue(nValue
, 0, GetDecimalDigits(), GetUnit(), GetUnit());
1310 const SvtSysLocale aSysLocale
;
1311 const LocaleDataWrapper
& rLocaleData
= aSysLocale
.GetLocaleData();
1312 double fResult(0.0);
1313 (void)vcl::TextToValue(aStr
, fResult
, 0, GetDecimalDigits(), rLocaleData
, GetUnit());
1314 if (!aStr
.isEmpty())
1318 else if (fResult
> nMax
)
1324 SvxBorderLineStyle
SvtLineListBox::GetSelectEntryStyle() const
1326 if (m_xLineSet
->IsNoSelection())
1327 return SvxBorderLineStyle::NONE
;
1328 auto nId
= m_xLineSet
->GetSelectedItemId();
1329 return static_cast<SvxBorderLineStyle
>(nId
- 1);
1334 Size
getPreviewSize(const weld::Widget
& rControl
)
1336 return Size(rControl
.get_approximate_digit_width() * 15, rControl
.get_text_height());
1340 void SvtLineListBox::ImpGetLine( tools::Long nLine1
, tools::Long nLine2
, tools::Long nDistance
,
1341 Color aColor1
, Color aColor2
, Color aColorDist
,
1342 SvxBorderLineStyle nStyle
, BitmapEx
& rBmp
)
1344 Size
aSize(getPreviewSize(*m_xControl
));
1346 // SourceUnit to Twips
1347 if ( eSourceUnit
== FieldUnit::POINT
)
1355 aSize
= aVirDev
->PixelToLogic( aSize
);
1356 tools::Long nPix
= aVirDev
->PixelToLogic( Size( 0, 1 ) ).Height();
1357 sal_uInt32 n1
= nLine1
;
1358 sal_uInt32 n2
= nLine2
;
1359 tools::Long nDist
= nDistance
;
1365 nDist
-= nDist
%nPix
;
1369 tools::Long nVirHeight
= n1
+nDist
+n2
;
1370 if ( nVirHeight
> aSize
.Height() )
1371 aSize
.setHeight( nVirHeight
);
1372 // negative width should not be drawn
1373 if ( aSize
.Width() <= 0 )
1376 Size aVirSize
= aVirDev
->LogicToPixel( aSize
);
1377 if ( aVirDev
->GetOutputSizePixel() != aVirSize
)
1378 aVirDev
->SetOutputSizePixel( aVirSize
);
1379 aVirDev
->SetFillColor( aColorDist
);
1380 aVirDev
->DrawRect( tools::Rectangle( Point(), aSize
) );
1382 aVirDev
->SetFillColor( aColor1
);
1384 double y1
= double( n1
) / 2;
1385 svtools::DrawLine( *aVirDev
, basegfx::B2DPoint( 0, y1
), basegfx::B2DPoint( aSize
.Width( ), y1
), n1
, nStyle
);
1389 double y2
= n1
+ nDist
+ double( n2
) / 2;
1390 aVirDev
->SetFillColor( aColor2
);
1391 svtools::DrawLine( *aVirDev
, basegfx::B2DPoint( 0, y2
), basegfx::B2DPoint( aSize
.Width(), y2
), n2
, SvxBorderLineStyle::SOLID
);
1393 rBmp
= aVirDev
->GetBitmapEx( Point(), Size( aSize
.Width(), n1
+nDist
+n2
) );
1396 SvtLineListBox::SvtLineListBox(std::unique_ptr
<weld::MenuButton
> pControl
)
1397 : m_xControl(std::move(pControl
))
1398 , m_xBuilder(Application::CreateBuilder(m_xControl
.get(), "svt/ui/linewindow.ui"))
1399 , m_xTopLevel(m_xBuilder
->weld_widget("line_popup_window"))
1400 , m_xNoneButton(m_xBuilder
->weld_button("none_line_button"))
1401 , m_xLineSet(new ValueSet(nullptr))
1402 , m_xLineSetWin(new weld::CustomWeld(*m_xBuilder
, "lineset", *m_xLineSet
))
1404 , aVirDev(VclPtr
<VirtualDevice
>::Create())
1406 , maPaintCol(COL_BLACK
)
1408 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
1409 m_xLineSet
->SetStyle(WinBits(WB_FLATVALUESET
| WB_NO_DIRECTSELECT
| WB_TABSTOP
));
1410 m_xLineSet
->SetItemHeight(rStyleSettings
.GetListBoxPreviewDefaultPixelSize().Height() + 1);
1411 m_xLineSet
->SetColCount(1);
1412 m_xLineSet
->SetSelectHdl(LINK(this, SvtLineListBox
, ValueSelectHdl
));
1414 m_xNoneButton
->connect_clicked(LINK(this, SvtLineListBox
, NoneHdl
));
1416 m_xTopLevel
->connect_focus_in(LINK(this, SvtLineListBox
, FocusHdl
));
1417 m_xControl
->set_popover(m_xTopLevel
.get());
1418 m_xControl
->connect_toggled(LINK(this, SvtLineListBox
, ToggleHdl
));
1420 // lock size to these maxes height/width so it doesn't jump around in size
1421 m_xControl
->set_label(GetLineStyleName(SvxBorderLineStyle::NONE
));
1422 Size aNonePrefSize
= m_xControl
->get_preferred_size();
1423 m_xControl
->set_label("");
1424 aVirDev
->SetOutputSizePixel(getPreviewSize(*m_xControl
));
1425 m_xControl
->set_image(aVirDev
);
1426 Size aSolidPrefSize
= m_xControl
->get_preferred_size();
1427 m_xControl
->set_size_request(std::max(aNonePrefSize
.Width(), aSolidPrefSize
.Width()),
1428 std::max(aNonePrefSize
.Height(), aSolidPrefSize
.Height()));
1430 eSourceUnit
= FieldUnit::POINT
;
1432 aVirDev
->SetLineColor();
1433 aVirDev
->SetMapMode(MapMode(MapUnit::MapTwip
));
1435 UpdatePaintLineColor();
1438 IMPL_LINK_NOARG(SvtLineListBox
, FocusHdl
, weld::Widget
&, void)
1440 if (GetSelectEntryStyle() == SvxBorderLineStyle::NONE
)
1441 m_xNoneButton
->grab_focus();
1443 m_xLineSet
->GrabFocus();
1446 IMPL_LINK(SvtLineListBox
, ToggleHdl
, weld::Toggleable
&, rButton
, void)
1448 if (rButton
.get_active())
1449 FocusHdl(*m_xTopLevel
);
1452 IMPL_LINK_NOARG(SvtLineListBox
, NoneHdl
, weld::Button
&, void)
1454 SelectEntry(SvxBorderLineStyle::NONE
);
1455 ValueSelectHdl(nullptr);
1458 SvtLineListBox::~SvtLineListBox()
1462 OUString
SvtLineListBox::GetLineStyleName(SvxBorderLineStyle eStyle
)
1465 for (sal_uInt32 i
= 0; i
< SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE
); ++i
)
1467 if (eStyle
== RID_SVXSTR_BORDERLINE
[i
].second
)
1469 sRet
= SvtResId(RID_SVXSTR_BORDERLINE
[i
].first
);
1476 sal_Int32
SvtLineListBox::GetStylePos( sal_Int32 nListPos
) const
1478 sal_Int32 nPos
= -1;
1483 size_t nCount
= m_vLineList
.size();
1484 while ( nPos
== -1 && i
< nCount
)
1486 if ( nListPos
== n
)
1487 nPos
= static_cast<sal_Int32
>(i
);
1495 void SvtLineListBox::SelectEntry(SvxBorderLineStyle nStyle
)
1497 if (nStyle
== SvxBorderLineStyle::NONE
)
1498 m_xLineSet
->SetNoSelection();
1500 m_xLineSet
->SelectItem(static_cast<sal_Int16
>(nStyle
) + 1);
1504 void SvtLineListBox::InsertEntry(
1505 const BorderWidthImpl
& rWidthImpl
, SvxBorderLineStyle nStyle
, tools::Long nMinWidth
,
1506 ColorFunc pColor1Fn
, ColorFunc pColor2Fn
, ColorDistFunc pColorDistFn
)
1508 m_vLineList
.emplace_back(new ImpLineListData(
1509 rWidthImpl
, nStyle
, nMinWidth
, pColor1Fn
, pColor2Fn
, pColorDistFn
));
1512 void SvtLineListBox::UpdatePaintLineColor()
1514 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
1515 Color
aNewCol(rSettings
.GetWindowColor().IsDark() ? rSettings
.GetLabelTextColor() : aColor
);
1517 bool bRet
= aNewCol
!= maPaintCol
;
1520 maPaintCol
= aNewCol
;
1523 void SvtLineListBox::UpdateEntries()
1525 UpdatePaintLineColor( );
1527 SvxBorderLineStyle eSelected
= GetSelectEntryStyle();
1529 // Remove the old entries
1530 m_xLineSet
->Clear();
1532 // Add the new entries based on the defined width
1535 sal_uInt16 nCount
= m_vLineList
.size( );
1536 while ( n
< nCount
)
1538 auto& pData
= m_vLineList
[ n
];
1540 ImpGetLine( pData
->GetLine1ForWidth( m_nWidth
),
1541 pData
->GetLine2ForWidth( m_nWidth
),
1542 pData
->GetDistForWidth( m_nWidth
),
1543 GetColorLine1(m_xLineSet
->GetItemCount()),
1544 GetColorLine2(m_xLineSet
->GetItemCount()),
1545 GetColorDist(m_xLineSet
->GetItemCount()),
1546 pData
->GetStyle(), aBmp
);
1547 sal_Int16 nItemId
= static_cast<sal_Int16
>(pData
->GetStyle()) + 1;
1548 m_xLineSet
->InsertItem(nItemId
, Image(aBmp
), GetLineStyleName(pData
->GetStyle()));
1549 if (pData
->GetStyle() == eSelected
)
1550 m_xLineSet
->SelectItem(nItemId
);
1554 m_xLineSet
->SetOptimalSize();
1557 Color
SvtLineListBox::GetColorLine1( sal_Int32 nPos
)
1559 sal_Int32 nStyle
= GetStylePos( nPos
);
1561 return GetPaintColor( );
1562 auto& pData
= m_vLineList
[ nStyle
];
1563 return pData
->GetColorLine1( GetColor( ) );
1566 Color
SvtLineListBox::GetColorLine2( sal_Int32 nPos
)
1568 sal_Int32 nStyle
= GetStylePos(nPos
);
1570 return GetPaintColor( );
1571 auto& pData
= m_vLineList
[ nStyle
];
1572 return pData
->GetColorLine2( GetColor( ) );
1575 Color
SvtLineListBox::GetColorDist( sal_Int32 nPos
)
1577 const StyleSettings
& rSettings
= Application::GetSettings().GetStyleSettings();
1578 Color rResult
= rSettings
.GetFieldColor();
1580 sal_Int32 nStyle
= GetStylePos( nPos
);
1583 auto& pData
= m_vLineList
[ nStyle
];
1584 return pData
->GetColorDist( GetColor( ), rResult
);
1587 IMPL_LINK_NOARG(SvtLineListBox
, ValueSelectHdl
, ValueSet
*, void)
1589 maSelectHdl
.Call(*this);
1591 if (m_xControl
->get_active())
1592 m_xControl
->set_active(false);
1595 void SvtLineListBox::UpdatePreview()
1597 SvxBorderLineStyle eStyle
= GetSelectEntryStyle();
1598 for (sal_uInt32 i
= 0; i
< SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE
); ++i
)
1600 if (eStyle
== RID_SVXSTR_BORDERLINE
[i
].second
)
1602 m_xControl
->set_label(SvtResId(RID_SVXSTR_BORDERLINE
[i
].first
));
1607 if (eStyle
== SvxBorderLineStyle::NONE
)
1609 m_xControl
->set_image(nullptr);
1610 m_xControl
->set_label(GetLineStyleName(SvxBorderLineStyle::NONE
));
1614 Image
aImage(m_xLineSet
->GetItemImage(m_xLineSet
->GetSelectedItemId()));
1615 m_xControl
->set_label("");
1616 const auto nPos
= (aVirDev
->GetOutputSizePixel().Height() - aImage
.GetSizePixel().Height()) / 2;
1617 aVirDev
->Push(vcl::PushFlags::MAPMODE
);
1618 aVirDev
->SetMapMode(MapMode(MapUnit::MapPixel
));
1620 aVirDev
->DrawImage(Point(0, nPos
), aImage
);
1621 m_xControl
->set_image(aVirDev
.get());
1626 SvtCalendarBox::SvtCalendarBox(std::unique_ptr
<weld::MenuButton
> pControl
, bool bUseLabel
)
1627 : m_bUseLabel(bUseLabel
)
1628 , m_xControl(std::move(pControl
))
1629 , m_xBuilder(Application::CreateBuilder(m_xControl
.get(), "svt/ui/datewindow.ui"))
1630 , m_xTopLevel(m_xBuilder
->weld_widget("date_popup_window"))
1631 , m_xCalendar(m_xBuilder
->weld_calendar("date"))
1633 m_xControl
->set_popover(m_xTopLevel
.get());
1634 m_xCalendar
->connect_selected(LINK(this, SvtCalendarBox
, SelectHdl
));
1635 m_xCalendar
->connect_activated(LINK(this, SvtCalendarBox
, ActivateHdl
));
1638 void SvtCalendarBox::set_date(const Date
& rDate
)
1640 m_xCalendar
->set_date(rDate
);
1641 set_label_from_date();
1644 void SvtCalendarBox::set_label_from_date()
1648 const LocaleDataWrapper
& rLocaleData
= Application::GetSettings().GetLocaleDataWrapper();
1649 m_xControl
->set_label(rLocaleData
.getDate(m_xCalendar
->get_date()));
1652 IMPL_LINK_NOARG(SvtCalendarBox
, SelectHdl
, weld::Calendar
&, void)
1654 set_label_from_date();
1655 m_aSelectHdl
.Call(*this);
1658 IMPL_LINK_NOARG(SvtCalendarBox
, ActivateHdl
, weld::Calendar
&, void)
1660 if (m_xControl
->get_active())
1661 m_xControl
->set_active(false);
1662 m_aActivatedHdl
.Call(*this);
1665 SvtCalendarBox::~SvtCalendarBox()
1669 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */