30d3a57439
a) announce Preview when a 'selected' font preview is requested b) move EndPreview to when the dropdown popups down, rather than listen to ESC Change-Id: I68916769150c23c0ec18aae084cdf3cafb7352a4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160609 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
1685 lines
53 KiB
C++
1685 lines
53 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <sal/config.h>
|
|
#include <config_folders.h>
|
|
|
|
#include <comphelper/lok.hxx>
|
|
#include <i18nutil/unicode.hxx>
|
|
#include <officecfg/Office/Common.hxx>
|
|
#include <tools/stream.hxx>
|
|
#include <vcl/customweld.hxx>
|
|
#include <vcl/event.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/fieldvalues.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <vcl/image.hxx>
|
|
#include <vcl/virdev.hxx>
|
|
#include <vcl/weldutils.hxx>
|
|
#include <rtl/math.hxx>
|
|
#include <sal/macros.h>
|
|
#include <sal/log.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <unotools/localedatawrapper.hxx>
|
|
#include <unotools/syslocale.hxx>
|
|
|
|
#include <svtools/borderline.hxx>
|
|
#include <svtools/sampletext.hxx>
|
|
#include <svtools/svtresid.hxx>
|
|
#include <svtools/strings.hrc>
|
|
#include <svtools/ctrlbox.hxx>
|
|
#include <svtools/ctrltool.hxx>
|
|
#include <svtools/borderhelper.hxx>
|
|
#include <svtools/valueset.hxx>
|
|
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
#include <editeng/borderline.hxx>
|
|
|
|
#include <rtl/bootstrap.hxx>
|
|
|
|
#include <borderline.hrc>
|
|
|
|
#include <stdio.h>
|
|
|
|
#define IMGOUTERTEXTSPACE 5
|
|
#define EXTRAFONTSIZE 5
|
|
#define GAPTOEXTRAPREVIEW 10
|
|
#define MINGAPWIDTH 2
|
|
|
|
constexpr OUStringLiteral FONTNAMEBOXMRUENTRIESFILE = u"/user/config/fontnameboxmruentries";
|
|
|
|
|
|
BorderWidthImpl::BorderWidthImpl( BorderWidthImplFlags nFlags, double nRate1, double nRate2, double nRateGap ):
|
|
m_nFlags( nFlags ),
|
|
m_nRate1( nRate1 ),
|
|
m_nRate2( nRate2 ),
|
|
m_nRateGap( nRateGap )
|
|
{
|
|
}
|
|
|
|
bool BorderWidthImpl::operator== ( const BorderWidthImpl& r ) const
|
|
{
|
|
return ( m_nFlags == r.m_nFlags ) &&
|
|
( m_nRate1 == r.m_nRate1 ) &&
|
|
( m_nRate2 == r.m_nRate2 ) &&
|
|
( m_nRateGap == r.m_nRateGap );
|
|
}
|
|
|
|
tools::Long BorderWidthImpl::GetLine1( tools::Long nWidth ) const
|
|
{
|
|
tools::Long result = static_cast<tools::Long>(m_nRate1);
|
|
if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 )
|
|
{
|
|
tools::Long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
|
|
tools::Long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
|
|
result = std::max<tools::Long>(0,
|
|
static_cast<tools::Long>((m_nRate1 * nWidth) + 0.5)
|
|
- (nConstant2 + nConstantD));
|
|
if (result == 0 && m_nRate1 > 0.0 && nWidth > 0)
|
|
{ // fdo#51777: hack to essentially treat 1 twip DOUBLE border
|
|
result = 1; // as 1 twip SINGLE border
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
tools::Long BorderWidthImpl::GetLine2( tools::Long nWidth ) const
|
|
{
|
|
tools::Long result = static_cast<tools::Long>(m_nRate2);
|
|
if ( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2)
|
|
{
|
|
tools::Long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
|
|
tools::Long const nConstantD = (m_nFlags & BorderWidthImplFlags::CHANGE_DIST ) ? 0 : m_nRateGap;
|
|
result = std::max<tools::Long>(0,
|
|
static_cast<tools::Long>((m_nRate2 * nWidth) + 0.5)
|
|
- (nConstant1 + nConstantD));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
tools::Long BorderWidthImpl::GetGap( tools::Long nWidth ) const
|
|
{
|
|
tools::Long result = static_cast<tools::Long>(m_nRateGap);
|
|
if ( m_nFlags & BorderWidthImplFlags::CHANGE_DIST )
|
|
{
|
|
tools::Long const nConstant1 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE1) ? 0 : m_nRate1;
|
|
tools::Long const nConstant2 = (m_nFlags & BorderWidthImplFlags::CHANGE_LINE2) ? 0 : m_nRate2;
|
|
result = std::max<tools::Long>(0,
|
|
static_cast<tools::Long>((m_nRateGap * nWidth) + 0.5)
|
|
- (nConstant1 + nConstant2));
|
|
}
|
|
|
|
// Avoid having too small distances (less than 0.1pt)
|
|
if ( result < MINGAPWIDTH && m_nRate1 > 0 && m_nRate2 > 0 )
|
|
result = MINGAPWIDTH;
|
|
|
|
return result;
|
|
}
|
|
|
|
static double lcl_getGuessedWidth( tools::Long nTested, double nRate, bool bChanging )
|
|
{
|
|
double nWidth = -1.0;
|
|
if ( bChanging )
|
|
nWidth = double( nTested ) / nRate;
|
|
else
|
|
{
|
|
if ( rtl::math::approxEqual(double( nTested ), nRate) )
|
|
nWidth = nRate;
|
|
}
|
|
|
|
return nWidth;
|
|
}
|
|
|
|
tools::Long BorderWidthImpl::GuessWidth( tools::Long nLine1, tools::Long nLine2, tools::Long nGap )
|
|
{
|
|
std::vector< double > aToCompare;
|
|
bool bInvalid = false;
|
|
|
|
bool bLine1Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE1 );
|
|
double nWidth1 = lcl_getGuessedWidth( nLine1, m_nRate1, bLine1Change );
|
|
if ( bLine1Change )
|
|
aToCompare.push_back( nWidth1 );
|
|
else if (nWidth1 < 0)
|
|
bInvalid = true;
|
|
|
|
bool bLine2Change = bool( m_nFlags & BorderWidthImplFlags::CHANGE_LINE2 );
|
|
double nWidth2 = lcl_getGuessedWidth( nLine2, m_nRate2, bLine2Change );
|
|
if ( bLine2Change )
|
|
aToCompare.push_back( nWidth2 );
|
|
else if (nWidth2 < 0)
|
|
bInvalid = true;
|
|
|
|
bool bGapChange = bool( m_nFlags & BorderWidthImplFlags::CHANGE_DIST );
|
|
double nWidthGap = lcl_getGuessedWidth( nGap, m_nRateGap, bGapChange );
|
|
if ( bGapChange && nGap >= MINGAPWIDTH )
|
|
aToCompare.push_back( nWidthGap );
|
|
else if ( !bGapChange && nWidthGap < 0 )
|
|
bInvalid = true;
|
|
|
|
// non-constant line width factors must sum to 1
|
|
assert((((bLine1Change) ? m_nRate1 : 0) +
|
|
((bLine2Change) ? m_nRate2 : 0) +
|
|
((bGapChange) ? m_nRateGap : 0)) - 1.0 < 0.00001 );
|
|
|
|
double nWidth = 0.0;
|
|
if ( (!bInvalid) && (!aToCompare.empty()) )
|
|
{
|
|
nWidth = *aToCompare.begin();
|
|
for (auto const& elem : aToCompare)
|
|
{
|
|
bInvalid = ( nWidth != elem );
|
|
if (bInvalid)
|
|
break;
|
|
}
|
|
nWidth = bInvalid ? 0.0 : nLine1 + nLine2 + nGap;
|
|
}
|
|
|
|
return nWidth;
|
|
}
|
|
|
|
static void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, tools::Long nWidth, SvxBorderLineStyle nDashing )
|
|
{
|
|
AntialiasingFlags nOldAA = rDev.GetAntialiasing();
|
|
rDev.SetAntialiasing( nOldAA & ~AntialiasingFlags::Enable );
|
|
|
|
tools::Long nPix = rDev.PixelToLogic(Size(1, 1)).Width();
|
|
basegfx::B2DPolyPolygon aPolygons = svtools::ApplyLineDashing(rPolygon, nDashing, nPix);
|
|
|
|
// Handle problems of width 1px in Pixel mode: 0.5px gives a 1px line
|
|
if (rDev.GetMapMode().GetMapUnit() == MapUnit::MapPixel && nWidth == nPix)
|
|
nWidth = 0;
|
|
|
|
for ( sal_uInt32 i = 0; i < aPolygons.count( ); i++ )
|
|
{
|
|
const basegfx::B2DPolygon& aDash = aPolygons.getB2DPolygon( i );
|
|
basegfx::B2DPoint aStart = aDash.getB2DPoint( 0 );
|
|
basegfx::B2DPoint aEnd = aDash.getB2DPoint( aDash.count() - 1 );
|
|
|
|
basegfx::B2DVector aVector( aEnd - aStart );
|
|
aVector.normalize( );
|
|
const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
|
|
|
|
const basegfx::B2DVector aWidthOffset( double( nWidth ) / 2 * aPerpendicular);
|
|
basegfx::B2DPolygon aDashPolygon;
|
|
aDashPolygon.append( aStart + aWidthOffset );
|
|
aDashPolygon.append( aEnd + aWidthOffset );
|
|
aDashPolygon.append( aEnd - aWidthOffset );
|
|
aDashPolygon.append( aStart - aWidthOffset );
|
|
aDashPolygon.setClosed( true );
|
|
|
|
rDev.DrawPolygon( aDashPolygon );
|
|
}
|
|
|
|
rDev.SetAntialiasing( nOldAA );
|
|
}
|
|
|
|
namespace svtools {
|
|
|
|
/**
|
|
* Dashing array must start with a line width and end with a blank width.
|
|
*/
|
|
static std::vector<double> GetDashing( SvxBorderLineStyle nDashing )
|
|
{
|
|
std::vector<double> aPattern;
|
|
switch (nDashing)
|
|
{
|
|
case SvxBorderLineStyle::DOTTED:
|
|
aPattern.push_back( 1.0 ); // line
|
|
aPattern.push_back( 2.0 ); // blank
|
|
break;
|
|
case SvxBorderLineStyle::DASHED:
|
|
aPattern.push_back( 16.0 ); // line
|
|
aPattern.push_back( 5.0 ); // blank
|
|
break;
|
|
case SvxBorderLineStyle::FINE_DASHED:
|
|
aPattern.push_back( 6.0 ); // line
|
|
aPattern.push_back( 2.0 ); // blank
|
|
break;
|
|
case SvxBorderLineStyle::DASH_DOT:
|
|
aPattern.push_back( 16.0 ); // line
|
|
aPattern.push_back( 5.0 ); // blank
|
|
aPattern.push_back( 5.0 ); // line
|
|
aPattern.push_back( 5.0 ); // blank
|
|
break;
|
|
case SvxBorderLineStyle::DASH_DOT_DOT:
|
|
aPattern.push_back( 16.0 ); // line
|
|
aPattern.push_back( 5.0 ); // blank
|
|
aPattern.push_back( 5.0 ); // line
|
|
aPattern.push_back( 5.0 ); // blank
|
|
aPattern.push_back( 5.0 ); // line
|
|
aPattern.push_back( 5.0 ); // blank
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
|
|
return aPattern;
|
|
}
|
|
|
|
namespace {
|
|
|
|
class ApplyScale
|
|
{
|
|
double mfScale;
|
|
public:
|
|
explicit ApplyScale( double fScale ) : mfScale(fScale) {}
|
|
void operator() ( double& rVal )
|
|
{
|
|
rVal *= mfScale;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
std::vector<double> GetLineDashing( SvxBorderLineStyle nDashing, double fScale )
|
|
{
|
|
std::vector<double> aPattern = GetDashing(nDashing);
|
|
std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
|
|
return aPattern;
|
|
}
|
|
|
|
basegfx::B2DPolyPolygon ApplyLineDashing( const basegfx::B2DPolygon& rPolygon, SvxBorderLineStyle nDashing, double fScale )
|
|
{
|
|
std::vector<double> aPattern = GetDashing(nDashing);
|
|
std::for_each(aPattern.begin(), aPattern.end(), ApplyScale(fScale));
|
|
|
|
basegfx::B2DPolyPolygon aPolygons;
|
|
|
|
if (aPattern.empty())
|
|
aPolygons.append(rPolygon);
|
|
else
|
|
basegfx::utils::applyLineDashing(rPolygon, aPattern, &aPolygons);
|
|
|
|
return aPolygons;
|
|
}
|
|
|
|
void DrawLine( OutputDevice& rDev, const Point& rP1, const Point& rP2,
|
|
sal_uInt32 nWidth, SvxBorderLineStyle nDashing )
|
|
{
|
|
DrawLine( rDev, basegfx::B2DPoint( rP1.X(), rP1.Y() ),
|
|
basegfx::B2DPoint( rP2.X(), rP2.Y( ) ), nWidth, nDashing );
|
|
}
|
|
|
|
void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rP1, const basegfx::B2DPoint& rP2,
|
|
sal_uInt32 nWidth, SvxBorderLineStyle nDashing )
|
|
{
|
|
basegfx::B2DPolygon aPolygon;
|
|
aPolygon.append( rP1 );
|
|
aPolygon.append( rP2 );
|
|
lclDrawPolygon( rDev, aPolygon, nWidth, nDashing );
|
|
}
|
|
|
|
}
|
|
|
|
static Size gUserItemSz;
|
|
static int gFontNameBoxes;
|
|
static size_t gPreviewsPerDevice;
|
|
static std::vector<VclPtr<VirtualDevice>> gFontPreviewVirDevs;
|
|
static std::vector<OUString> gRenderedFontNames;
|
|
static int gHighestDPI = 0;
|
|
|
|
namespace
|
|
{
|
|
std::vector<VclPtr<VirtualDevice>>& getFontPreviewVirDevs()
|
|
{
|
|
return gFontPreviewVirDevs;
|
|
}
|
|
|
|
void clearFontPreviewVirDevs()
|
|
{
|
|
for (auto &rDev : gFontPreviewVirDevs)
|
|
rDev.disposeAndClear();
|
|
gFontPreviewVirDevs.clear();
|
|
}
|
|
|
|
std::vector<OUString>& getRenderedFontNames()
|
|
{
|
|
return gRenderedFontNames;
|
|
}
|
|
|
|
void clearRenderedFontNames()
|
|
{
|
|
gRenderedFontNames.clear();
|
|
}
|
|
|
|
void calcCustomItemSize(const weld::ComboBox& rComboBox)
|
|
{
|
|
gUserItemSz = Size(rComboBox.get_approximate_digit_width() * 52, rComboBox.get_text_height());
|
|
gUserItemSz.setHeight(gUserItemSz.Height() * 16);
|
|
gUserItemSz.setHeight(gUserItemSz.Height() / 10);
|
|
|
|
size_t nMaxDeviceHeight = SAL_MAX_INT16 / 16; // see limitXCreatePixmap and be generous wrt up to x16 hidpi
|
|
assert(gUserItemSz.Height() != 0);
|
|
gPreviewsPerDevice = gUserItemSz.Height() == 0 ? 16 : nMaxDeviceHeight / gUserItemSz.Height();
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
gPreviewsPerDevice = 1;
|
|
}
|
|
}
|
|
|
|
IMPL_LINK(FontNameBox, SettingsChangedHdl, VclSimpleEvent&, rEvent, void)
|
|
{
|
|
if (rEvent.GetId() != VclEventId::ApplicationDataChanged)
|
|
return;
|
|
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
return;
|
|
|
|
DataChangedEvent* pData = static_cast<DataChangedEvent*>(static_cast<VclWindowEvent&>(rEvent).GetData());
|
|
if (pData->GetType() == DataChangedEventType::SETTINGS)
|
|
{
|
|
clearFontPreviewVirDevs();
|
|
clearRenderedFontNames();
|
|
calcCustomItemSize(*m_xComboBox);
|
|
if (mbWYSIWYG && mpFontList && !mpFontList->empty())
|
|
{
|
|
mnPreviewProgress = 0;
|
|
maUpdateIdle.Start();
|
|
}
|
|
}
|
|
}
|
|
|
|
FontNameBox::FontNameBox(std::unique_ptr<weld::ComboBox> p)
|
|
: m_xComboBox(std::move(p))
|
|
, mnPreviewProgress(0)
|
|
, mbWYSIWYG(false)
|
|
, maUpdateIdle("FontNameBox Preview Update")
|
|
{
|
|
++gFontNameBoxes;
|
|
InitFontMRUEntriesFile();
|
|
|
|
maUpdateIdle.SetPriority(TaskPriority::LOWEST);
|
|
maUpdateIdle.SetInvokeHandler(LINK(this, FontNameBox, UpdateHdl));
|
|
|
|
Application::AddEventListener(LINK(this, FontNameBox, SettingsChangedHdl));
|
|
}
|
|
|
|
FontNameBox::~FontNameBox()
|
|
{
|
|
Application::RemoveEventListener(LINK(this, FontNameBox, SettingsChangedHdl));
|
|
|
|
if (mpFontList)
|
|
{
|
|
SaveMRUEntries (maFontMRUEntriesFile);
|
|
ImplDestroyFontList();
|
|
}
|
|
--gFontNameBoxes;
|
|
if (!gFontNameBoxes)
|
|
{
|
|
clearFontPreviewVirDevs();
|
|
clearRenderedFontNames();
|
|
}
|
|
}
|
|
|
|
void FontNameBox::SaveMRUEntries(const OUString& aFontMRUEntriesFile) const
|
|
{
|
|
OString aEntries(OUStringToOString(m_xComboBox->get_mru_entries(),
|
|
RTL_TEXTENCODING_UTF8));
|
|
|
|
if (aEntries.isEmpty() || aFontMRUEntriesFile.isEmpty())
|
|
return;
|
|
|
|
SvFileStream aStream;
|
|
aStream.Open( aFontMRUEntriesFile, StreamMode::WRITE | StreamMode::TRUNC );
|
|
if( ! (aStream.IsOpen() && aStream.IsWritable()) )
|
|
{
|
|
SAL_INFO("svtools.control", "FontNameBox::SaveMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed");
|
|
return;
|
|
}
|
|
|
|
aStream.SetLineDelimiter( LINEEND_LF );
|
|
aStream.WriteLine( aEntries );
|
|
aStream.WriteLine( "" );
|
|
}
|
|
|
|
void FontNameBox::LoadMRUEntries( const OUString& aFontMRUEntriesFile )
|
|
{
|
|
if (aFontMRUEntriesFile.isEmpty())
|
|
return;
|
|
|
|
if (!officecfg::Office::Common::Font::View::ShowFontBoxWYSIWYG::get())
|
|
return;
|
|
|
|
SvFileStream aStream( aFontMRUEntriesFile, StreamMode::READ );
|
|
if( ! aStream.IsOpen() )
|
|
{
|
|
SAL_INFO("svtools.control", "FontNameBox::LoadMRUEntries: opening mru entries file " << aFontMRUEntriesFile << " failed");
|
|
return;
|
|
}
|
|
|
|
OString aLine;
|
|
aStream.ReadLine( aLine );
|
|
OUString aEntries = OStringToOUString(aLine,
|
|
RTL_TEXTENCODING_UTF8);
|
|
m_xComboBox->set_mru_entries(aEntries);
|
|
}
|
|
|
|
void FontNameBox::InitFontMRUEntriesFile()
|
|
{
|
|
OUString sUserConfigDir("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE( "bootstrap") "::UserInstallation}");
|
|
rtl::Bootstrap::expandMacros(sUserConfigDir);
|
|
|
|
maFontMRUEntriesFile = sUserConfigDir;
|
|
if( !maFontMRUEntriesFile.isEmpty() )
|
|
{
|
|
maFontMRUEntriesFile += FONTNAMEBOXMRUENTRIESFILE;
|
|
}
|
|
}
|
|
|
|
void FontNameBox::ImplDestroyFontList()
|
|
{
|
|
mpFontList.reset();
|
|
mnPreviewProgress = 0;
|
|
maUpdateIdle.Stop();
|
|
}
|
|
|
|
void FontNameBox::Fill( const FontList* pList )
|
|
{
|
|
// store old text and clear box
|
|
OUString aOldText = m_xComboBox->get_active_text();
|
|
OUString rEntries = m_xComboBox->get_mru_entries();
|
|
bool bLoadFromFile = rEntries.isEmpty();
|
|
m_xComboBox->freeze();
|
|
m_xComboBox->clear();
|
|
|
|
ImplDestroyFontList();
|
|
mpFontList.reset(new ImplFontList);
|
|
|
|
// insert fonts
|
|
size_t nFontCount = pList->GetFontNameCount();
|
|
for (size_t i = 0; i < nFontCount; ++i)
|
|
{
|
|
const FontMetric& rFontMetric = pList->GetFontName(i);
|
|
m_xComboBox->append(OUString::number(i), rFontMetric.GetFamilyName());
|
|
mpFontList->push_back(rFontMetric);
|
|
}
|
|
|
|
if (bLoadFromFile)
|
|
LoadMRUEntries(maFontMRUEntriesFile);
|
|
else
|
|
m_xComboBox->set_mru_entries(rEntries);
|
|
|
|
m_xComboBox->thaw();
|
|
|
|
if (mbWYSIWYG && nFontCount)
|
|
{
|
|
assert(mnPreviewProgress == 0 && "ImplDestroyFontList wasn't called");
|
|
maUpdateIdle.Start();
|
|
}
|
|
|
|
// restore text
|
|
if (!aOldText.isEmpty())
|
|
set_active_or_entry_text(aOldText);
|
|
}
|
|
|
|
static bool IsRunningUnitTest() { return getenv("LO_TESTNAME") != nullptr; }
|
|
|
|
void FontNameBox::EnableWYSIWYG(bool bEnable)
|
|
{
|
|
if (IsRunningUnitTest())
|
|
return;
|
|
if (mbWYSIWYG == bEnable)
|
|
return;
|
|
mbWYSIWYG = bEnable;
|
|
|
|
if (mbWYSIWYG)
|
|
{
|
|
calcCustomItemSize(*m_xComboBox);
|
|
m_xComboBox->connect_custom_get_size(LINK(this, FontNameBox, CustomGetSizeHdl));
|
|
m_xComboBox->connect_custom_render(LINK(this, FontNameBox, CustomRenderHdl));
|
|
}
|
|
else
|
|
{
|
|
m_xComboBox->connect_custom_get_size(Link<OutputDevice&, Size>());
|
|
m_xComboBox->connect_custom_render(Link<weld::ComboBox::render_args, void>());
|
|
}
|
|
m_xComboBox->set_custom_renderer(mbWYSIWYG);
|
|
}
|
|
|
|
IMPL_LINK(FontNameBox, CustomGetSizeHdl, OutputDevice&, rDevice, Size)
|
|
{
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
calcCustomItemSize(*m_xComboBox);
|
|
gUserItemSz.setWidth(1.0 * rDevice.GetDPIX() / 96.0 * gUserItemSz.getWidth());
|
|
gUserItemSz.setHeight(1.0 * rDevice.GetDPIY() / 96.0 * gUserItemSz.getHeight());
|
|
}
|
|
return mbWYSIWYG ? gUserItemSz : Size();
|
|
}
|
|
|
|
namespace
|
|
{
|
|
tools::Long shrinkFontToFit(OUString const &rSampleText, tools::Long nH, vcl::Font &rFont, OutputDevice &rDevice, tools::Rectangle &rTextRect)
|
|
{
|
|
tools::Long nWidth = 0;
|
|
|
|
Size aSize( rFont.GetFontSize() );
|
|
|
|
//Make sure it fits in the available height
|
|
while (aSize.Height() > 0)
|
|
{
|
|
if (!rDevice.GetTextBoundRect(rTextRect, rSampleText))
|
|
break;
|
|
if (rTextRect.GetHeight() <= nH)
|
|
{
|
|
nWidth = rTextRect.GetWidth();
|
|
break;
|
|
}
|
|
|
|
aSize.AdjustHeight( -(EXTRAFONTSIZE) );
|
|
rFont.SetFontSize(aSize);
|
|
rDevice.SetFont(rFont);
|
|
}
|
|
|
|
return nWidth;
|
|
}
|
|
}
|
|
|
|
IMPL_LINK_NOARG(FontNameBox, UpdateHdl, Timer*, void)
|
|
{
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
return;
|
|
|
|
CachePreview(mnPreviewProgress++, nullptr);
|
|
// tdf#132536 limit to ~25 pre-rendered for now. The font caches look
|
|
// b0rked, the massive charmaps are ~never swapped out, and don't count
|
|
// towards the size of a font in the font cache.
|
|
if (mnPreviewProgress < std::min<size_t>(25, mpFontList->size()))
|
|
maUpdateIdle.Start();
|
|
}
|
|
|
|
static void DrawPreview(const FontMetric& rFontMetric, const Point& rTopLeft, OutputDevice& rDevice, bool bSelected)
|
|
{
|
|
rDevice.Push(vcl::PushFlags::TEXTCOLOR);
|
|
|
|
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
|
|
if (bSelected)
|
|
rDevice.SetTextColor(rStyleSettings.GetHighlightTextColor());
|
|
else
|
|
rDevice.SetTextColor(rStyleSettings.GetDialogTextColor());
|
|
|
|
tools::Long nX = rTopLeft.X();
|
|
tools::Long nH = gUserItemSz.Height();
|
|
|
|
nX += IMGOUTERTEXTSPACE;
|
|
|
|
const bool bSymbolFont = isSymbolFont(rFontMetric);
|
|
|
|
vcl::Font aOldFont(rDevice.GetFont());
|
|
Size aSize( aOldFont.GetFontSize() );
|
|
aSize.AdjustHeight(EXTRAFONTSIZE );
|
|
vcl::Font aFont( rFontMetric );
|
|
aFont.SetFontSize( aSize );
|
|
rDevice.SetFont(aFont);
|
|
|
|
bool bUsingCorrectFont = true;
|
|
tools::Rectangle aTextRect;
|
|
|
|
// Preview the font name
|
|
const OUString& sFontName = rFontMetric.GetFamilyName();
|
|
|
|
//If it shouldn't or can't draw its own name because it doesn't have the glyphs
|
|
if (!canRenderNameOfSelectedFont(rDevice))
|
|
bUsingCorrectFont = false;
|
|
else
|
|
{
|
|
//Make sure it fits in the available height, shrinking the font if necessary
|
|
bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, rDevice, aTextRect) != 0;
|
|
}
|
|
|
|
if (!bUsingCorrectFont)
|
|
{
|
|
rDevice.SetFont(aOldFont);
|
|
rDevice.GetTextBoundRect(aTextRect, sFontName);
|
|
}
|
|
|
|
tools::Long nTextHeight = aTextRect.GetHeight();
|
|
tools::Long nDesiredGap = (nH-nTextHeight)/2;
|
|
tools::Long nVertAdjust = nDesiredGap - aTextRect.Top();
|
|
Point aPos( nX, rTopLeft.Y() + nVertAdjust );
|
|
rDevice.DrawText(aPos, sFontName);
|
|
tools::Long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW;
|
|
|
|
if (!bUsingCorrectFont)
|
|
rDevice.SetFont(aFont);
|
|
|
|
OUString sSampleText;
|
|
|
|
if (!bSymbolFont)
|
|
{
|
|
const bool bNameBeginsWithLatinText = rFontMetric.GetFamilyName()[0] <= 'z';
|
|
|
|
if (bNameBeginsWithLatinText || !bUsingCorrectFont)
|
|
sSampleText = makeShortRepresentativeTextForSelectedFont(rDevice);
|
|
}
|
|
|
|
//If we're not a symbol font, but could neither render our own name and
|
|
//we can't determine what script it would like to render, then try a
|
|
//few well known scripts
|
|
if (sSampleText.isEmpty() && !bUsingCorrectFont)
|
|
{
|
|
static const UScriptCode aScripts[] =
|
|
{
|
|
USCRIPT_ARABIC,
|
|
USCRIPT_HEBREW,
|
|
|
|
USCRIPT_BENGALI,
|
|
USCRIPT_GURMUKHI,
|
|
USCRIPT_GUJARATI,
|
|
USCRIPT_ORIYA,
|
|
USCRIPT_TAMIL,
|
|
USCRIPT_TELUGU,
|
|
USCRIPT_KANNADA,
|
|
USCRIPT_MALAYALAM,
|
|
USCRIPT_SINHALA,
|
|
USCRIPT_DEVANAGARI,
|
|
|
|
USCRIPT_THAI,
|
|
USCRIPT_LAO,
|
|
USCRIPT_GEORGIAN,
|
|
USCRIPT_TIBETAN,
|
|
USCRIPT_SYRIAC,
|
|
USCRIPT_MYANMAR,
|
|
USCRIPT_ETHIOPIC,
|
|
USCRIPT_KHMER,
|
|
USCRIPT_MONGOLIAN,
|
|
|
|
USCRIPT_KOREAN,
|
|
USCRIPT_JAPANESE,
|
|
USCRIPT_HAN,
|
|
USCRIPT_SIMPLIFIED_HAN,
|
|
USCRIPT_TRADITIONAL_HAN,
|
|
|
|
USCRIPT_GREEK
|
|
};
|
|
|
|
for (const UScriptCode& rScript : aScripts)
|
|
{
|
|
OUString sText = makeShortRepresentativeTextForScript(rScript);
|
|
if (!sText.isEmpty())
|
|
{
|
|
bool bHasSampleTextGlyphs = (-1 == rDevice.HasGlyphs(aFont, sText));
|
|
if (bHasSampleTextGlyphs)
|
|
{
|
|
sSampleText = sText;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static const UScriptCode aMinimalScripts[] =
|
|
{
|
|
USCRIPT_HEBREW, //e.g. biblical hebrew
|
|
USCRIPT_GREEK
|
|
};
|
|
|
|
for (const UScriptCode& rMinimalScript : aMinimalScripts)
|
|
{
|
|
OUString sText = makeShortMinimalTextForScript(rMinimalScript);
|
|
if (!sText.isEmpty())
|
|
{
|
|
bool bHasSampleTextGlyphs = (-1 == rDevice.HasGlyphs(aFont, sText));
|
|
if (bHasSampleTextGlyphs)
|
|
{
|
|
sSampleText = sText;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//If we're a symbol font, or for some reason the font still couldn't
|
|
//render something representative of what it would like to render then
|
|
//make up some semi-random text that it *can* display
|
|
if (bSymbolFont || (!bUsingCorrectFont && sSampleText.isEmpty()))
|
|
sSampleText = makeShortRepresentativeSymbolTextForSelectedFont(rDevice);
|
|
|
|
if (!sSampleText.isEmpty())
|
|
{
|
|
const Size &rItemSize = gUserItemSz;
|
|
|
|
//leave a little border at the edge
|
|
tools::Long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE;
|
|
if (nSpace >= 0)
|
|
{
|
|
//Make sure it fits in the available height, and get how wide that would be
|
|
tools::Long nWidth = shrinkFontToFit(sSampleText, nH, aFont, rDevice, aTextRect);
|
|
//Chop letters off until it fits in the available width
|
|
while (nWidth > nSpace || nWidth > gUserItemSz.Width())
|
|
{
|
|
sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
|
|
nWidth = rDevice.GetTextBoundRect(aTextRect, sSampleText) ?
|
|
aTextRect.GetWidth() : 0;
|
|
}
|
|
|
|
//center the text on the line
|
|
if (!sSampleText.isEmpty() && nWidth)
|
|
{
|
|
nTextHeight = aTextRect.GetHeight();
|
|
nDesiredGap = (nH-nTextHeight)/2;
|
|
nVertAdjust = nDesiredGap - aTextRect.Top();
|
|
aPos = Point(nTextX + nSpace - nWidth, rTopLeft.Y() + nVertAdjust);
|
|
rDevice.DrawText(aPos, sSampleText);
|
|
}
|
|
}
|
|
}
|
|
|
|
rDevice.SetFont(aOldFont);
|
|
rDevice.Pop();
|
|
}
|
|
|
|
OutputDevice& FontNameBox::CachePreview(size_t nIndex, Point* pTopLeft,
|
|
sal_Int32 nDPIX, sal_Int32 nDPIY)
|
|
{
|
|
SolarMutexGuard aGuard;
|
|
const FontMetric& rFontMetric = (*mpFontList)[nIndex];
|
|
const OUString& rFontName = rFontMetric.GetFamilyName();
|
|
|
|
if (comphelper::LibreOfficeKit::isActive())
|
|
{
|
|
// we want to cache only best quality previews
|
|
if (gHighestDPI < nDPIX || gHighestDPI < nDPIY)
|
|
{
|
|
clearRenderedFontNames();
|
|
clearFontPreviewVirDevs();
|
|
gHighestDPI = std::max(nDPIX, nDPIY);
|
|
}
|
|
else if (gHighestDPI > nDPIX || gHighestDPI > nDPIY)
|
|
{
|
|
nDPIX = gHighestDPI;
|
|
nDPIY = gHighestDPI;
|
|
}
|
|
}
|
|
|
|
size_t nPreviewIndex;
|
|
auto& rFontNames = getRenderedFontNames();
|
|
auto& rVirtualDevs = getFontPreviewVirDevs();
|
|
auto xFind = std::find(rFontNames.begin(), rFontNames.end(), rFontName);
|
|
bool bPreviewAvailable = xFind != rFontNames.end();
|
|
if (!bPreviewAvailable)
|
|
{
|
|
nPreviewIndex = rFontNames.size();
|
|
rFontNames.push_back(rFontName);
|
|
}
|
|
else
|
|
nPreviewIndex = std::distance(rFontNames.begin(), xFind);
|
|
|
|
size_t nPage = nPreviewIndex / gPreviewsPerDevice;
|
|
size_t nIndexInPage = nPreviewIndex - (nPage * gPreviewsPerDevice);
|
|
|
|
Point aTopLeft(0, gUserItemSz.Height() * nIndexInPage);
|
|
|
|
if (!bPreviewAvailable)
|
|
{
|
|
if (nPage >= rVirtualDevs.size())
|
|
{
|
|
bool bIsLOK = comphelper::LibreOfficeKit::isActive();
|
|
if (bIsLOK) // allow transparent background in LOK case
|
|
rVirtualDevs.emplace_back(VclPtr<VirtualDevice>::Create(DeviceFormat::WITH_ALPHA));
|
|
else
|
|
rVirtualDevs.emplace_back(m_xComboBox->create_render_virtual_device());
|
|
|
|
VirtualDevice& rDevice = *rVirtualDevs.back();
|
|
rDevice.SetOutputSizePixel(Size(gUserItemSz.Width(), gUserItemSz.Height() * gPreviewsPerDevice));
|
|
if (bIsLOK)
|
|
{
|
|
rDevice.SetDPIX(nDPIX);
|
|
rDevice.SetDPIY(nDPIY);
|
|
}
|
|
|
|
weld::SetPointFont(rDevice, m_xComboBox->get_font(), bIsLOK);
|
|
assert(rVirtualDevs.size() == nPage + 1);
|
|
}
|
|
|
|
DrawPreview(rFontMetric, aTopLeft, *rVirtualDevs.back(), false);
|
|
}
|
|
|
|
if (pTopLeft)
|
|
*pTopLeft = aTopLeft;
|
|
|
|
return *rVirtualDevs[nPage];
|
|
}
|
|
|
|
IMPL_LINK(FontNameBox, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void)
|
|
{
|
|
vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
|
|
const ::tools::Rectangle& rRect = std::get<1>(aPayload);
|
|
bool bSelected = std::get<2>(aPayload);
|
|
const OUString& rId = std::get<3>(aPayload);
|
|
|
|
sal_uInt32 nIndex = rId.toUInt32();
|
|
|
|
Point aDestPoint(rRect.TopLeft());
|
|
auto nMargin = (rRect.GetHeight() - gUserItemSz.Height()) / 2;
|
|
aDestPoint.AdjustY(nMargin);
|
|
|
|
if (bSelected)
|
|
{
|
|
const FontMetric& rFontMetric = (*mpFontList)[nIndex];
|
|
DrawPreview(rFontMetric, aDestPoint, rRenderContext, true);
|
|
m_aLivePreviewHdl.Call(rFontMetric);
|
|
}
|
|
else
|
|
{
|
|
// use cache of unselected entries
|
|
Point aTopLeft;
|
|
OutputDevice& rDevice = CachePreview(nIndex, &aTopLeft,
|
|
rRenderContext.GetDPIX(),
|
|
rRenderContext.GetDPIY());
|
|
|
|
Size aSourceSize = comphelper::LibreOfficeKit::isActive() ? rDevice.GetOutputSizePixel() : gUserItemSz;
|
|
rRenderContext.DrawOutDev(aDestPoint, gUserItemSz,
|
|
aTopLeft, aSourceSize,
|
|
rDevice);
|
|
}
|
|
}
|
|
|
|
void FontNameBox::set_active_or_entry_text(const OUString& rText)
|
|
{
|
|
const int nFound = m_xComboBox->find_text(rText);
|
|
if (nFound != -1)
|
|
m_xComboBox->set_active(nFound);
|
|
m_xComboBox->set_entry_text(rText);
|
|
}
|
|
|
|
FontStyleBox::FontStyleBox(std::unique_ptr<weld::ComboBox> p)
|
|
: m_xComboBox(std::move(p))
|
|
{
|
|
//Use the standard texts to get an optimal size and stick to that size.
|
|
//That should stop the character dialog dancing around.
|
|
auto nMaxLen = m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHT)).Width();
|
|
nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_LIGHT_ITALIC)).Width());
|
|
nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMAL)).Width());
|
|
nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_NORMAL_ITALIC)).Width());
|
|
nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLD)).Width());
|
|
nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BOLD_ITALIC)).Width());
|
|
nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACK)).Width());
|
|
nMaxLen = std::max(nMaxLen, m_xComboBox->get_pixel_size(SvtResId(STR_SVT_STYLE_BLACK_ITALIC)).Width());
|
|
m_xComboBox->set_entry_width_chars(std::ceil(nMaxLen / m_xComboBox->get_approximate_digit_width()));
|
|
}
|
|
|
|
void FontStyleBox::Fill( std::u16string_view rName, const FontList* pList )
|
|
{
|
|
OUString aOldText = m_xComboBox->get_active_text();
|
|
int nPos = m_xComboBox->get_active();
|
|
|
|
m_xComboBox->freeze();
|
|
m_xComboBox->clear();
|
|
|
|
// does a font with this name already exist?
|
|
sal_Handle hFontMetric = pList->GetFirstFontMetric( rName );
|
|
if ( hFontMetric )
|
|
{
|
|
OUString aStyleText;
|
|
FontWeight eLastWeight = WEIGHT_DONTKNOW;
|
|
FontItalic eLastItalic = ITALIC_NONE;
|
|
FontWidth eLastWidth = WIDTH_DONTKNOW;
|
|
bool bNormal = false;
|
|
bool bItalic = false;
|
|
bool bBold = false;
|
|
bool bBoldItalic = false;
|
|
bool bInsert = false;
|
|
FontMetric aFontMetric;
|
|
while ( hFontMetric )
|
|
{
|
|
aFontMetric = FontList::GetFontMetric( hFontMetric );
|
|
|
|
FontWeight eWeight = aFontMetric.GetWeight();
|
|
FontItalic eItalic = aFontMetric.GetItalic();
|
|
FontWidth eWidth = aFontMetric.GetWidthType();
|
|
// Only if the attributes are different, we insert the
|
|
// Font to avoid double Entries in different languages
|
|
if ( (eWeight != eLastWeight) || (eItalic != eLastItalic) ||
|
|
(eWidth != eLastWidth) )
|
|
{
|
|
if ( bInsert )
|
|
m_xComboBox->append_text(aStyleText);
|
|
|
|
if ( eWeight <= WEIGHT_NORMAL )
|
|
{
|
|
if ( eItalic != ITALIC_NONE )
|
|
bItalic = true;
|
|
else
|
|
bNormal = true;
|
|
}
|
|
else
|
|
{
|
|
if ( eItalic != ITALIC_NONE )
|
|
bBoldItalic = true;
|
|
else
|
|
bBold = true;
|
|
}
|
|
|
|
// For wrong StyleNames we replace this with the correct once
|
|
aStyleText = pList->GetStyleName( aFontMetric );
|
|
bInsert = m_xComboBox->find_text(aStyleText) == -1;
|
|
if ( !bInsert )
|
|
{
|
|
aStyleText = pList->GetStyleName( eWeight, eItalic );
|
|
bInsert = m_xComboBox->find_text(aStyleText) == -1;
|
|
}
|
|
|
|
eLastWeight = eWeight;
|
|
eLastItalic = eItalic;
|
|
eLastWidth = eWidth;
|
|
}
|
|
else
|
|
{
|
|
if ( bInsert )
|
|
{
|
|
// If we have two names for the same attributes
|
|
// we prefer the translated standard names
|
|
const OUString& rAttrStyleText = pList->GetStyleName( eWeight, eItalic );
|
|
if (rAttrStyleText != aStyleText)
|
|
{
|
|
OUString aTempStyleText = pList->GetStyleName( aFontMetric );
|
|
if (rAttrStyleText == aTempStyleText)
|
|
aStyleText = rAttrStyleText;
|
|
bInsert = m_xComboBox->find_text(aStyleText) == -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bItalic && (aStyleText == pList->GetItalicStr()) )
|
|
bItalic = true;
|
|
else if ( !bBold && (aStyleText == pList->GetBoldStr()) )
|
|
bBold = true;
|
|
else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) )
|
|
bBoldItalic = true;
|
|
|
|
hFontMetric = FontList::GetNextFontMetric( hFontMetric );
|
|
}
|
|
|
|
if ( bInsert )
|
|
m_xComboBox->append_text(aStyleText);
|
|
|
|
// certain style as copy
|
|
if ( bNormal )
|
|
{
|
|
if ( !bItalic )
|
|
m_xComboBox->append_text(pList->GetItalicStr());
|
|
if ( !bBold )
|
|
m_xComboBox->append_text(pList->GetBoldStr());
|
|
}
|
|
if ( !bBoldItalic )
|
|
{
|
|
if ( bNormal || bItalic || bBold )
|
|
m_xComboBox->append_text(pList->GetBoldItalicStr());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// insert standard styles if no font
|
|
m_xComboBox->append_text(pList->GetNormalStr());
|
|
m_xComboBox->append_text(pList->GetItalicStr());
|
|
m_xComboBox->append_text(pList->GetBoldStr());
|
|
m_xComboBox->append_text(pList->GetBoldItalicStr());
|
|
}
|
|
|
|
m_xComboBox->thaw();
|
|
|
|
if (!aOldText.isEmpty())
|
|
{
|
|
int nFound = m_xComboBox->find_text(aOldText);
|
|
if (nFound != -1)
|
|
m_xComboBox->set_active(nFound);
|
|
else
|
|
{
|
|
if (nPos >= m_xComboBox->get_count())
|
|
m_xComboBox->set_active(0);
|
|
else
|
|
m_xComboBox->set_active(nPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
FontSizeBox::FontSizeBox(std::unique_ptr<weld::ComboBox> p)
|
|
: pFontList(nullptr)
|
|
, nSavedValue(0)
|
|
, nMin(20)
|
|
, nMax(9999)
|
|
, eUnit(FieldUnit::POINT)
|
|
, nDecimalDigits(1)
|
|
, nRelMin(0)
|
|
, nRelMax(0)
|
|
, nRelStep(0)
|
|
, nPtRelMin(0)
|
|
, nPtRelMax(0)
|
|
, nPtRelStep(0)
|
|
, bRelativeMode(false)
|
|
, bRelative(false)
|
|
, bPtRelative(false)
|
|
, bStdSize(false)
|
|
, m_xComboBox(std::move(p))
|
|
{
|
|
m_xComboBox->set_entry_width_chars(std::ceil(m_xComboBox->get_pixel_size(format_number(105)).Width() /
|
|
m_xComboBox->get_approximate_digit_width()));
|
|
m_xComboBox->connect_focus_out(LINK(this, FontSizeBox, ReformatHdl));
|
|
m_xComboBox->connect_changed(LINK(this, FontSizeBox, ModifyHdl));
|
|
}
|
|
|
|
void FontSizeBox::set_active_or_entry_text(const OUString& rText)
|
|
{
|
|
const int nFound = m_xComboBox->find_text(rText);
|
|
if (nFound != -1)
|
|
m_xComboBox->set_active(nFound);
|
|
m_xComboBox->set_entry_text(rText);
|
|
}
|
|
|
|
IMPL_LINK(FontSizeBox, ReformatHdl, weld::Widget&, rWidget, void)
|
|
{
|
|
FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
|
|
if (!bRelativeMode || !aFontSizeNames.IsEmpty())
|
|
{
|
|
if (aFontSizeNames.Name2Size(m_xComboBox->get_active_text()) != 0)
|
|
return;
|
|
}
|
|
|
|
set_value(get_value());
|
|
|
|
m_aFocusOutHdl.Call(rWidget);
|
|
}
|
|
|
|
IMPL_LINK(FontSizeBox, ModifyHdl, weld::ComboBox&, rBox, void)
|
|
{
|
|
if (bRelativeMode)
|
|
{
|
|
OUString aStr = comphelper::string::stripStart(rBox.get_active_text(), ' ');
|
|
|
|
bool bNewMode = bRelative;
|
|
bool bOldPtRelMode = bPtRelative;
|
|
|
|
if ( bRelative )
|
|
{
|
|
bPtRelative = false;
|
|
const sal_Unicode* pStr = aStr.getStr();
|
|
while ( *pStr )
|
|
{
|
|
if ( ((*pStr < '0') || (*pStr > '9')) && (*pStr != '%') && !unicode::isSpace(*pStr) )
|
|
{
|
|
if ( ('-' == *pStr || '+' == *pStr) && !bPtRelative )
|
|
bPtRelative = true;
|
|
else if ( bPtRelative && 'p' == *pStr && 't' == *++pStr )
|
|
;
|
|
else
|
|
{
|
|
bNewMode = false;
|
|
break;
|
|
}
|
|
}
|
|
pStr++;
|
|
}
|
|
}
|
|
else if (!aStr.isEmpty())
|
|
{
|
|
if ( -1 != aStr.indexOf('%') )
|
|
{
|
|
bNewMode = true;
|
|
bPtRelative = false;
|
|
}
|
|
|
|
if ( '-' == aStr[0] || '+' == aStr[0] )
|
|
{
|
|
bNewMode = true;
|
|
bPtRelative = true;
|
|
}
|
|
}
|
|
|
|
if ( bNewMode != bRelative || bPtRelative != bOldPtRelMode )
|
|
SetRelative( bNewMode );
|
|
}
|
|
m_aChangeHdl.Call(rBox);
|
|
}
|
|
|
|
void FontSizeBox::Fill( const FontList* pList )
|
|
{
|
|
// remember for relative mode
|
|
pFontList = pList;
|
|
|
|
// no font sizes need to be set for relative mode
|
|
if ( bRelative )
|
|
return;
|
|
|
|
// query font sizes
|
|
const int* pTempAry;
|
|
const int* pAry = nullptr;
|
|
|
|
pAry = FontList::GetStdSizeAry();
|
|
|
|
// first insert font size names (for simplified/traditional chinese)
|
|
FontSizeNames aFontSizeNames( Application::GetSettings().GetUILanguageTag().getLanguageType() );
|
|
if ( pAry == FontList::GetStdSizeAry() )
|
|
{
|
|
// for standard sizes we don't need to bother
|
|
if (bStdSize && m_xComboBox->get_count() && aFontSizeNames.IsEmpty())
|
|
return;
|
|
bStdSize = true;
|
|
}
|
|
else
|
|
bStdSize = false;
|
|
|
|
int nSelectionStart, nSelectionEnd;
|
|
m_xComboBox->get_entry_selection_bounds(nSelectionStart, nSelectionEnd);
|
|
OUString aStr = m_xComboBox->get_active_text();
|
|
|
|
m_xComboBox->freeze();
|
|
m_xComboBox->clear();
|
|
int nPos = 0;
|
|
|
|
if ( !aFontSizeNames.IsEmpty() )
|
|
{
|
|
if ( pAry == FontList::GetStdSizeAry() )
|
|
{
|
|
// for scalable fonts all font size names
|
|
sal_uInt32 nCount = aFontSizeNames.Count();
|
|
for( sal_uInt32 i = 0; i < nCount; i++ )
|
|
{
|
|
OUString aSizeName = aFontSizeNames.GetIndexName( i );
|
|
int nSize = aFontSizeNames.GetIndexSize( i );
|
|
OUString sId(OUString::number(-nSize)); // mark as special
|
|
m_xComboBox->insert(nPos, aSizeName, &sId, nullptr, nullptr);
|
|
nPos++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// for fixed size fonts only selectable font size names
|
|
pTempAry = pAry;
|
|
while ( *pTempAry )
|
|
{
|
|
OUString aSizeName = aFontSizeNames.Size2Name( *pTempAry );
|
|
if ( !aSizeName.isEmpty() )
|
|
{
|
|
OUString sId(OUString::number(-(*pTempAry))); // mark as special
|
|
m_xComboBox->insert(nPos, aSizeName, &sId, nullptr, nullptr);
|
|
nPos++;
|
|
}
|
|
pTempAry++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// then insert numerical font size values
|
|
pTempAry = pAry;
|
|
while (*pTempAry)
|
|
{
|
|
InsertValue(*pTempAry);
|
|
++pTempAry;
|
|
}
|
|
|
|
m_xComboBox->thaw();
|
|
set_active_or_entry_text(aStr);
|
|
m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
|
|
}
|
|
|
|
void FontSizeBox::EnableRelativeMode( sal_uInt16 nNewMin, sal_uInt16 nNewMax, sal_uInt16 nStep )
|
|
{
|
|
bRelativeMode = true;
|
|
nRelMin = nNewMin;
|
|
nRelMax = nNewMax;
|
|
nRelStep = nStep;
|
|
SetUnit(FieldUnit::POINT);
|
|
}
|
|
|
|
void FontSizeBox::EnablePtRelativeMode( short nNewMin, short nNewMax, short nStep )
|
|
{
|
|
bRelativeMode = true;
|
|
nPtRelMin = nNewMin;
|
|
nPtRelMax = nNewMax;
|
|
nPtRelStep = nStep;
|
|
SetUnit(FieldUnit::POINT);
|
|
}
|
|
|
|
void FontSizeBox::InsertValue(int i)
|
|
{
|
|
OUString sNumber(OUString::number(i));
|
|
m_xComboBox->append(sNumber, format_number(i));
|
|
}
|
|
|
|
void FontSizeBox::SetRelative( bool bNewRelative )
|
|
{
|
|
if ( !bRelativeMode )
|
|
return;
|
|
|
|
int nSelectionStart, nSelectionEnd;
|
|
m_xComboBox->get_entry_selection_bounds(nSelectionStart, nSelectionEnd);
|
|
OUString aStr = comphelper::string::stripStart(m_xComboBox->get_active_text(), ' ');
|
|
|
|
if (bNewRelative)
|
|
{
|
|
bRelative = true;
|
|
bStdSize = false;
|
|
|
|
m_xComboBox->clear();
|
|
|
|
if (bPtRelative)
|
|
{
|
|
SetDecimalDigits( 1 );
|
|
SetRange(nPtRelMin, nPtRelMax);
|
|
SetUnit(FieldUnit::POINT);
|
|
|
|
short i = nPtRelMin, n = 0;
|
|
// JP 30.06.98: more than 100 values are not useful
|
|
while ( i <= nPtRelMax && n++ < 100 )
|
|
{
|
|
InsertValue( i );
|
|
i = i + nPtRelStep;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetDecimalDigits(0);
|
|
SetRange(nRelMin, nRelMax);
|
|
SetUnit(FieldUnit::PERCENT);
|
|
|
|
sal_uInt16 i = nRelMin;
|
|
while ( i <= nRelMax )
|
|
{
|
|
InsertValue( i );
|
|
i = i + nRelStep;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pFontList)
|
|
m_xComboBox->clear();
|
|
bRelative = bPtRelative = false;
|
|
SetDecimalDigits(1);
|
|
SetRange(20, 9999);
|
|
SetUnit(FieldUnit::POINT);
|
|
if ( pFontList)
|
|
Fill( pFontList );
|
|
}
|
|
|
|
set_active_or_entry_text(aStr);
|
|
m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
|
|
}
|
|
|
|
OUString FontSizeBox::format_number(int nValue) const
|
|
{
|
|
OUString sRet;
|
|
|
|
//pawn percent off to icu to decide whether percent is separated from its number for this locale
|
|
if (eUnit == FieldUnit::PERCENT)
|
|
{
|
|
double fValue = nValue;
|
|
fValue /= weld::SpinButton::Power10(nDecimalDigits);
|
|
sRet = unicode::formatPercent(fValue, Application::GetSettings().GetUILanguageTag());
|
|
}
|
|
else
|
|
{
|
|
const SvtSysLocale aSysLocale;
|
|
const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
|
|
sRet = rLocaleData.getNum(nValue, nDecimalDigits, true, false);
|
|
if (eUnit != FieldUnit::NONE && eUnit != FieldUnit::DEGREE)
|
|
sRet += " ";
|
|
assert(eUnit != FieldUnit::PERCENT);
|
|
sRet += weld::MetricSpinButton::MetricToString(eUnit);
|
|
}
|
|
|
|
if (bRelativeMode && bPtRelative && (0 <= nValue) && !sRet.isEmpty())
|
|
sRet = "+" + sRet;
|
|
|
|
return sRet;
|
|
}
|
|
|
|
void FontSizeBox::SetValue(int nNewValue, FieldUnit eInUnit)
|
|
{
|
|
auto nTempValue = vcl::ConvertValue(nNewValue, 0, GetDecimalDigits(), eInUnit, GetUnit());
|
|
if (nTempValue < nMin)
|
|
nTempValue = nMin;
|
|
else if (nTempValue > nMax)
|
|
nTempValue = nMax;
|
|
if (!bRelative)
|
|
{
|
|
FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
|
|
// conversion loses precision; however font sizes should
|
|
// never have a problem with that
|
|
OUString aName = aFontSizeNames.Size2Name(nTempValue);
|
|
if (!aName.isEmpty() && m_xComboBox->find_text(aName) != -1)
|
|
{
|
|
m_xComboBox->set_active_text(aName);
|
|
return;
|
|
}
|
|
}
|
|
OUString aResult = format_number(nTempValue);
|
|
set_active_or_entry_text(aResult);
|
|
}
|
|
|
|
void FontSizeBox::set_value(int nNewValue)
|
|
{
|
|
SetValue(nNewValue, eUnit);
|
|
}
|
|
|
|
int FontSizeBox::get_value() const
|
|
{
|
|
OUString aStr = m_xComboBox->get_active_text();
|
|
if (!bRelative)
|
|
{
|
|
FontSizeNames aFontSizeNames(Application::GetSettings().GetUILanguageTag().getLanguageType());
|
|
auto nValue = aFontSizeNames.Name2Size(aStr);
|
|
if (nValue)
|
|
return vcl::ConvertValue(nValue, 0, GetDecimalDigits(), GetUnit(), GetUnit());
|
|
}
|
|
|
|
const SvtSysLocale aSysLocale;
|
|
const LocaleDataWrapper& rLocaleData = aSysLocale.GetLocaleData();
|
|
double fResult(0.0);
|
|
(void)vcl::TextToValue(aStr, fResult, 0, GetDecimalDigits(), rLocaleData, GetUnit());
|
|
if (!aStr.isEmpty())
|
|
{
|
|
if (fResult < nMin)
|
|
fResult = nMin;
|
|
else if (fResult > nMax)
|
|
fResult = nMax;
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
SvxBorderLineStyle SvtLineListBox::GetSelectEntryStyle() const
|
|
{
|
|
if (m_xLineSet->IsNoSelection())
|
|
return SvxBorderLineStyle::NONE;
|
|
auto nId = m_xLineSet->GetSelectedItemId();
|
|
return static_cast<SvxBorderLineStyle>(nId - 1);
|
|
}
|
|
|
|
namespace
|
|
{
|
|
Size getPreviewSize(const weld::Widget& rControl)
|
|
{
|
|
return Size(rControl.get_approximate_digit_width() * 15, rControl.get_text_height());
|
|
}
|
|
}
|
|
|
|
void SvtLineListBox::ImpGetLine( tools::Long nLine1, tools::Long nLine2, tools::Long nDistance,
|
|
Color aColor1, Color aColor2, Color aColorDist,
|
|
SvxBorderLineStyle nStyle, BitmapEx& rBmp )
|
|
{
|
|
Size aSize(getPreviewSize(*m_xControl));
|
|
|
|
// SourceUnit to Twips
|
|
if ( eSourceUnit == FieldUnit::POINT )
|
|
{
|
|
nLine1 /= 5;
|
|
nLine2 /= 5;
|
|
nDistance /= 5;
|
|
}
|
|
|
|
// Paint the lines
|
|
aSize = aVirDev->PixelToLogic( aSize );
|
|
tools::Long nPix = aVirDev->PixelToLogic( Size( 0, 1 ) ).Height();
|
|
sal_uInt32 n1 = nLine1;
|
|
sal_uInt32 n2 = nLine2;
|
|
tools::Long nDist = nDistance;
|
|
n1 += nPix-1;
|
|
n1 -= n1%nPix;
|
|
if ( n2 )
|
|
{
|
|
nDist += nPix-1;
|
|
nDist -= nDist%nPix;
|
|
n2 += nPix-1;
|
|
n2 -= n2%nPix;
|
|
}
|
|
tools::Long nVirHeight = n1+nDist+n2;
|
|
if ( nVirHeight > aSize.Height() )
|
|
aSize.setHeight( nVirHeight );
|
|
// negative width should not be drawn
|
|
if ( aSize.Width() <= 0 )
|
|
return;
|
|
|
|
Size aVirSize = aVirDev->LogicToPixel( aSize );
|
|
if ( aVirDev->GetOutputSizePixel() != aVirSize )
|
|
aVirDev->SetOutputSizePixel( aVirSize );
|
|
aVirDev->SetFillColor( aColorDist );
|
|
aVirDev->DrawRect( tools::Rectangle( Point(), aSize ) );
|
|
|
|
aVirDev->SetFillColor( aColor1 );
|
|
|
|
double y1 = double( n1 ) / 2;
|
|
svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y1 ), basegfx::B2DPoint( aSize.Width( ), y1 ), n1, nStyle );
|
|
|
|
if ( n2 )
|
|
{
|
|
double y2 = n1 + nDist + double( n2 ) / 2;
|
|
aVirDev->SetFillColor( aColor2 );
|
|
svtools::DrawLine( *aVirDev, basegfx::B2DPoint( 0, y2 ), basegfx::B2DPoint( aSize.Width(), y2 ), n2, SvxBorderLineStyle::SOLID );
|
|
}
|
|
rBmp = aVirDev->GetBitmapEx( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
|
|
}
|
|
|
|
SvtLineListBox::SvtLineListBox(std::unique_ptr<weld::MenuButton> pControl)
|
|
: WeldToolbarPopup(css::uno::Reference<css::frame::XFrame>(), pControl.get(), "svt/ui/linewindow.ui", "line_popup_window")
|
|
, m_xControl(std::move(pControl))
|
|
, m_xNoneButton(m_xBuilder->weld_button("none_line_button"))
|
|
, m_xLineSet(new ValueSet(nullptr))
|
|
, m_xLineSetWin(new weld::CustomWeld(*m_xBuilder, "lineset", *m_xLineSet))
|
|
, m_nWidth( 5 )
|
|
, aVirDev(VclPtr<VirtualDevice>::Create())
|
|
, aColor(COL_BLACK)
|
|
{
|
|
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
|
|
m_xLineSet->SetStyle(WinBits(WB_FLATVALUESET | WB_NO_DIRECTSELECT | WB_TABSTOP));
|
|
m_xLineSet->SetItemHeight(rStyleSettings.GetListBoxPreviewDefaultPixelSize().Height() + 1);
|
|
m_xLineSet->SetColCount(1);
|
|
m_xLineSet->SetSelectHdl(LINK(this, SvtLineListBox, ValueSelectHdl));
|
|
|
|
m_xNoneButton->connect_clicked(LINK(this, SvtLineListBox, NoneHdl));
|
|
|
|
m_xControl->set_popover(m_xTopLevel.get());
|
|
m_xControl->connect_toggled(LINK(this, SvtLineListBox, ToggleHdl));
|
|
m_xControl->connect_style_updated(LINK(this, SvtLineListBox, StyleUpdatedHdl));
|
|
|
|
// lock size to these maxes height/width so it doesn't jump around in size
|
|
m_xControl->set_label(GetLineStyleName(SvxBorderLineStyle::NONE));
|
|
Size aNonePrefSize = m_xControl->get_preferred_size();
|
|
m_xControl->set_label("");
|
|
aVirDev->SetOutputSizePixel(getPreviewSize(*m_xControl));
|
|
m_xControl->set_image(aVirDev);
|
|
Size aSolidPrefSize = m_xControl->get_preferred_size();
|
|
m_xControl->set_size_request(std::max(aNonePrefSize.Width(), aSolidPrefSize.Width()),
|
|
std::max(aNonePrefSize.Height(), aSolidPrefSize.Height()));
|
|
|
|
eSourceUnit = FieldUnit::POINT;
|
|
|
|
aVirDev->SetLineColor();
|
|
aVirDev->SetMapMode(MapMode(MapUnit::MapTwip));
|
|
}
|
|
|
|
void SvtLineListBox::GrabFocus()
|
|
{
|
|
if (GetSelectEntryStyle() == SvxBorderLineStyle::NONE)
|
|
m_xNoneButton->grab_focus();
|
|
else
|
|
m_xLineSet->GrabFocus();
|
|
}
|
|
|
|
IMPL_LINK(SvtLineListBox, ToggleHdl, weld::Toggleable&, rButton, void)
|
|
{
|
|
if (rButton.get_active())
|
|
GrabFocus();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SvtLineListBox, StyleUpdatedHdl, weld::Widget&, void)
|
|
{
|
|
UpdateEntries();
|
|
UpdatePreview();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SvtLineListBox, NoneHdl, weld::Button&, void)
|
|
{
|
|
SelectEntry(SvxBorderLineStyle::NONE);
|
|
ValueSelectHdl(nullptr);
|
|
}
|
|
|
|
SvtLineListBox::~SvtLineListBox()
|
|
{
|
|
}
|
|
|
|
OUString SvtLineListBox::GetLineStyleName(SvxBorderLineStyle eStyle)
|
|
{
|
|
OUString sRet;
|
|
for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE); ++i)
|
|
{
|
|
if (eStyle == RID_SVXSTR_BORDERLINE[i].second)
|
|
{
|
|
sRet = SvtResId(RID_SVXSTR_BORDERLINE[i].first);
|
|
break;
|
|
}
|
|
}
|
|
return sRet;
|
|
}
|
|
|
|
void SvtLineListBox::SelectEntry(SvxBorderLineStyle nStyle)
|
|
{
|
|
if (nStyle == SvxBorderLineStyle::NONE)
|
|
m_xLineSet->SetNoSelection();
|
|
else
|
|
m_xLineSet->SelectItem(static_cast<sal_Int16>(nStyle) + 1);
|
|
UpdatePreview();
|
|
}
|
|
|
|
void SvtLineListBox::InsertEntry(
|
|
const BorderWidthImpl& rWidthImpl, SvxBorderLineStyle nStyle, tools::Long nMinWidth,
|
|
ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
|
|
{
|
|
m_vLineList.emplace_back(new ImpLineListData(
|
|
rWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn));
|
|
}
|
|
|
|
void SvtLineListBox::UpdateEntries()
|
|
{
|
|
SvxBorderLineStyle eSelected = GetSelectEntryStyle();
|
|
|
|
// Remove the old entries
|
|
m_xLineSet->Clear();
|
|
|
|
const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
|
|
Color aFieldColor = rSettings.GetFieldColor();
|
|
|
|
// Add the new entries based on the defined width
|
|
sal_uInt16 n = 0;
|
|
sal_uInt16 nCount = m_vLineList.size( );
|
|
while ( n < nCount )
|
|
{
|
|
auto& pData = m_vLineList[ n ];
|
|
BitmapEx aBmp;
|
|
ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
|
|
pData->GetLine2ForWidth( m_nWidth ),
|
|
pData->GetDistForWidth( m_nWidth ),
|
|
pData->GetColorLine1(aColor),
|
|
pData->GetColorLine2(aColor),
|
|
pData->GetColorDist(aColor, aFieldColor),
|
|
pData->GetStyle(), aBmp );
|
|
sal_Int16 nItemId = static_cast<sal_Int16>(pData->GetStyle()) + 1;
|
|
m_xLineSet->InsertItem(nItemId, Image(aBmp), GetLineStyleName(pData->GetStyle()));
|
|
if (pData->GetStyle() == eSelected)
|
|
m_xLineSet->SelectItem(nItemId);
|
|
n++;
|
|
}
|
|
|
|
m_xLineSet->SetOptimalSize();
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SvtLineListBox, ValueSelectHdl, ValueSet*, void)
|
|
{
|
|
maSelectHdl.Call(*this);
|
|
UpdatePreview();
|
|
if (m_xControl->get_active())
|
|
m_xControl->set_active(false);
|
|
}
|
|
|
|
void SvtLineListBox::UpdatePreview()
|
|
{
|
|
SvxBorderLineStyle eStyle = GetSelectEntryStyle();
|
|
for (sal_uInt32 i = 0; i < SAL_N_ELEMENTS(RID_SVXSTR_BORDERLINE); ++i)
|
|
{
|
|
if (eStyle == RID_SVXSTR_BORDERLINE[i].second)
|
|
{
|
|
m_xControl->set_label(SvtResId(RID_SVXSTR_BORDERLINE[i].first));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (eStyle == SvxBorderLineStyle::NONE)
|
|
{
|
|
m_xControl->set_image(nullptr);
|
|
m_xControl->set_label(GetLineStyleName(SvxBorderLineStyle::NONE));
|
|
}
|
|
else
|
|
{
|
|
Image aImage(m_xLineSet->GetItemImage(m_xLineSet->GetSelectedItemId()));
|
|
m_xControl->set_label("");
|
|
const auto nPos = (aVirDev->GetOutputSizePixel().Height() - aImage.GetSizePixel().Height()) / 2;
|
|
aVirDev->Push(vcl::PushFlags::MAPMODE);
|
|
aVirDev->SetMapMode(MapMode(MapUnit::MapPixel));
|
|
const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
|
|
aVirDev->SetBackground(rSettings.GetFieldColor());
|
|
aVirDev->Erase();
|
|
aVirDev->DrawImage(Point(0, nPos), aImage);
|
|
m_xControl->set_image(aVirDev.get());
|
|
aVirDev->Pop();
|
|
}
|
|
}
|
|
|
|
SvtCalendarBox::SvtCalendarBox(std::unique_ptr<weld::MenuButton> pControl, bool bUseLabel)
|
|
: m_bUseLabel(bUseLabel)
|
|
, m_xControl(std::move(pControl))
|
|
, m_xBuilder(Application::CreateBuilder(m_xControl.get(), "svt/ui/datewindow.ui"))
|
|
, m_xTopLevel(m_xBuilder->weld_popover("date_popup_window"))
|
|
, m_xCalendar(m_xBuilder->weld_calendar("date_picker"))
|
|
{
|
|
m_xControl->set_popover(m_xTopLevel.get());
|
|
m_xCalendar->connect_selected(LINK(this, SvtCalendarBox, SelectHdl));
|
|
m_xCalendar->connect_activated(LINK(this, SvtCalendarBox, ActivateHdl));
|
|
}
|
|
|
|
void SvtCalendarBox::set_date(const Date& rDate)
|
|
{
|
|
m_xCalendar->set_date(rDate);
|
|
set_label_from_date();
|
|
}
|
|
|
|
void SvtCalendarBox::set_label_from_date()
|
|
{
|
|
if (!m_bUseLabel)
|
|
return;
|
|
const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
|
|
m_xControl->set_label(rLocaleData.getDate(m_xCalendar->get_date()));
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SvtCalendarBox, SelectHdl, weld::Calendar&, void)
|
|
{
|
|
set_label_from_date();
|
|
m_aSelectHdl.Call(*this);
|
|
}
|
|
|
|
IMPL_LINK_NOARG(SvtCalendarBox, ActivateHdl, weld::Calendar&, void)
|
|
{
|
|
if (m_xControl->get_active())
|
|
m_xControl->set_active(false);
|
|
m_aActivatedHdl.Call(*this);
|
|
}
|
|
|
|
SvtCalendarBox::~SvtCalendarBox()
|
|
{
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|