Change-Id: I939160ae72fecbe3d4a60ce755730bd4c38497fb Reviewed-on: https://gerrit.libreoffice.org/8182 Reviewed-by: Caolán McNamara <caolanm@redhat.com> Tested-by: Caolán McNamara <caolanm@redhat.com>
2018 lines
56 KiB
C++
2018 lines
56 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 <config_folders.h>
|
|
|
|
#include <tools/stream.hxx>
|
|
#include <vcl/builder.hxx>
|
|
#include <vcl/svapp.hxx>
|
|
#include <vcl/field.hxx>
|
|
#include <vcl/helper.hxx>
|
|
#include <vcl/settings.hxx>
|
|
#include <sal/macros.h>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <comphelper/string.hxx>
|
|
#include <unotools/charclass.hxx>
|
|
|
|
#include <svtools/sampletext.hxx>
|
|
#include <svtools/svtresid.hxx>
|
|
#include <svtools/svtools.hrc>
|
|
#include <svtools/ctrlbox.hxx>
|
|
#include <svtools/ctrltool.hxx>
|
|
#include <svtools/borderhelper.hxx>
|
|
|
|
#include <vcl/i18nhelp.hxx>
|
|
#include <vcl/fontcapabilities.hxx>
|
|
#include <basegfx/polygon/b2dpolygon.hxx>
|
|
#include <basegfx/polygon/b2dpolygontools.hxx>
|
|
|
|
#include <com/sun/star/table/BorderLineStyle.hpp>
|
|
|
|
#include <rtl/bootstrap.hxx>
|
|
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
#include <cstdio>
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#define IMGOUTERTEXTSPACE 5
|
|
#define EXTRAFONTSIZE 5
|
|
#define GAPTOEXTRAPREVIEW 10
|
|
#define MAXPREVIEWWIDTH 120
|
|
#define MINGAPWIDTH 2
|
|
|
|
#define FONTNAMEBOXMRUENTRIESFILE "/user/config/fontnameboxmruentries"
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
// ========================================================================
|
|
// ColorListBox
|
|
// ========================================================================
|
|
|
|
|
|
// - ImplColorListData -
|
|
|
|
|
|
class ImplColorListData
|
|
{
|
|
public:
|
|
Color aColor;
|
|
sal_Bool bColor;
|
|
|
|
ImplColorListData() : aColor( COL_BLACK ) { bColor = sal_False; }
|
|
ImplColorListData( const Color& rColor ) : aColor( rColor ) { bColor = sal_True; }
|
|
};
|
|
|
|
|
|
|
|
void ColorListBox::ImplInit()
|
|
{
|
|
pColorList = new ImpColorList();
|
|
|
|
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
|
|
aImageSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
|
|
EnableUserDraw( true );
|
|
SetUserItemSize( aImageSize );
|
|
}
|
|
|
|
|
|
|
|
void ColorListBox::ImplDestroyColorEntries()
|
|
{
|
|
for ( size_t n = pColorList->size(); n; )
|
|
delete (*pColorList)[ --n ];
|
|
pColorList->clear();
|
|
}
|
|
|
|
|
|
|
|
ColorListBox::ColorListBox( Window* pParent, WinBits nWinStyle ) :
|
|
ListBox( pParent, nWinStyle )
|
|
{
|
|
ImplInit();
|
|
SetEdgeBlending(true);
|
|
}
|
|
|
|
|
|
|
|
ColorListBox::ColorListBox( Window* pParent, const ResId& rResId ) :
|
|
ListBox( pParent, rResId )
|
|
{
|
|
ImplInit();
|
|
SetEdgeBlending(true);
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeColorListBox(Window *pParent, VclBuilder::stringmap &rMap)
|
|
{
|
|
bool bDropdown = VclBuilder::extractDropdown(rMap);
|
|
WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
|
|
if (bDropdown)
|
|
nWinBits |= WB_DROPDOWN;
|
|
ColorListBox *pListBox = new ColorListBox(pParent, nWinBits);
|
|
if (bDropdown)
|
|
pListBox->EnableAutoSize(true);
|
|
return pListBox;
|
|
}
|
|
|
|
|
|
|
|
ColorListBox::~ColorListBox()
|
|
{
|
|
ImplDestroyColorEntries();
|
|
delete pColorList;
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 ColorListBox::InsertEntry( const OUString& rStr, sal_uInt16 nPos )
|
|
{
|
|
nPos = ListBox::InsertEntry( rStr, nPos );
|
|
if ( nPos != LISTBOX_ERROR )
|
|
{
|
|
ImplColorListData* pData = new ImplColorListData;
|
|
if ( nPos < pColorList->size() )
|
|
{
|
|
ImpColorList::iterator it = pColorList->begin();
|
|
::std::advance( it, nPos );
|
|
pColorList->insert( it, pData );
|
|
}
|
|
else
|
|
{
|
|
pColorList->push_back( pData );
|
|
nPos = pColorList->size() - 1;
|
|
}
|
|
}
|
|
return nPos;
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 ColorListBox::InsertEntry( const Color& rColor, const OUString& rStr,
|
|
sal_uInt16 nPos )
|
|
{
|
|
nPos = ListBox::InsertEntry( rStr, nPos );
|
|
if ( nPos != LISTBOX_ERROR )
|
|
{
|
|
ImplColorListData* pData = new ImplColorListData( rColor );
|
|
if ( nPos < pColorList->size() )
|
|
{
|
|
ImpColorList::iterator it = pColorList->begin();
|
|
::std::advance( it, nPos );
|
|
pColorList->insert( it, pData );
|
|
}
|
|
else
|
|
{
|
|
pColorList->push_back( pData );
|
|
nPos = pColorList->size() - 1;
|
|
}
|
|
}
|
|
return nPos;
|
|
}
|
|
|
|
|
|
|
|
void ColorListBox::InsertAutomaticEntryColor(const Color &rColor)
|
|
{
|
|
// insert the "Automatic"-entry always on the first position
|
|
InsertEntry( rColor, SVT_RESSTR(STR_SVT_AUTOMATIC_COLOR), 0 );
|
|
}
|
|
|
|
|
|
|
|
void ColorListBox::RemoveEntry( sal_uInt16 nPos )
|
|
{
|
|
ListBox::RemoveEntry( nPos );
|
|
if ( nPos < pColorList->size() )
|
|
{
|
|
ImpColorList::iterator it = pColorList->begin();
|
|
::std::advance( it, nPos );
|
|
delete *it;
|
|
pColorList->erase( it );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ColorListBox::Clear()
|
|
{
|
|
ImplDestroyColorEntries();
|
|
ListBox::Clear();
|
|
}
|
|
|
|
|
|
|
|
void ColorListBox::CopyEntries( const ColorListBox& rBox )
|
|
{
|
|
// Liste leeren
|
|
ImplDestroyColorEntries();
|
|
|
|
// Daten kopieren
|
|
size_t nCount = rBox.pColorList->size();
|
|
for ( size_t n = 0; n < nCount; n++ )
|
|
{
|
|
ImplColorListData* pData = (*rBox.pColorList)[ n ];
|
|
sal_uInt16 nPos = InsertEntry( rBox.GetEntry( n ), LISTBOX_APPEND );
|
|
if ( nPos != LISTBOX_ERROR )
|
|
{
|
|
if ( nPos < pColorList->size() )
|
|
{
|
|
ImpColorList::iterator it = pColorList->begin();
|
|
::std::advance( it, nPos );
|
|
pColorList->insert( it, new ImplColorListData( *pData ) );
|
|
}
|
|
else
|
|
{
|
|
pColorList->push_back( new ImplColorListData( *pData ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 ColorListBox::GetEntryPos( const Color& rColor ) const
|
|
{
|
|
for( sal_uInt16 n = (sal_uInt16) pColorList->size(); n; )
|
|
{
|
|
ImplColorListData* pData = (*pColorList)[ --n ];
|
|
if ( pData->bColor && ( pData->aColor == rColor ) )
|
|
return n;
|
|
}
|
|
return LISTBOX_ENTRY_NOTFOUND;
|
|
}
|
|
|
|
|
|
|
|
Color ColorListBox::GetEntryColor( sal_uInt16 nPos ) const
|
|
{
|
|
Color aColor;
|
|
ImplColorListData* pData = ( nPos < pColorList->size() ) ? (*pColorList)[ nPos ] : NULL;
|
|
if ( pData && pData->bColor )
|
|
aColor = pData->aColor;
|
|
return aColor;
|
|
}
|
|
|
|
|
|
|
|
void ColorListBox::UserDraw( const UserDrawEvent& rUDEvt )
|
|
{
|
|
size_t nPos = rUDEvt.GetItemId();
|
|
ImplColorListData* pData = ( nPos < pColorList->size() ) ? (*pColorList)[ nPos ] : NULL;
|
|
if ( pData )
|
|
{
|
|
if ( pData->bColor )
|
|
{
|
|
Point aPos( rUDEvt.GetRect().TopLeft() );
|
|
|
|
aPos.X() += 2;
|
|
aPos.Y() += ( rUDEvt.GetRect().GetHeight() - aImageSize.Height() ) / 2;
|
|
|
|
const Rectangle aRect(aPos, aImageSize);
|
|
|
|
rUDEvt.GetDevice()->Push();
|
|
rUDEvt.GetDevice()->SetFillColor( pData->aColor );
|
|
rUDEvt.GetDevice()->SetLineColor( rUDEvt.GetDevice()->GetTextColor() );
|
|
rUDEvt.GetDevice()->DrawRect(aRect);
|
|
rUDEvt.GetDevice()->Pop();
|
|
|
|
const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
|
|
const sal_uInt16 nEdgeBlendingPercent(GetEdgeBlending() ? rStyleSettings.GetEdgeBlending() : 0);
|
|
|
|
if(nEdgeBlendingPercent)
|
|
{
|
|
const Color& rTopLeft(rStyleSettings.GetEdgeBlendingTopLeftColor());
|
|
const Color& rBottomRight(rStyleSettings.GetEdgeBlendingBottomRightColor());
|
|
const sal_uInt8 nAlpha((nEdgeBlendingPercent * 255) / 100);
|
|
const BitmapEx aBlendFrame(createBlendFrame(aRect.GetSize(), nAlpha, rTopLeft, rBottomRight));
|
|
|
|
if(!aBlendFrame.IsEmpty())
|
|
{
|
|
rUDEvt.GetDevice()->DrawBitmapEx(aRect.TopLeft(), aBlendFrame);
|
|
}
|
|
}
|
|
|
|
ListBox::DrawEntry( rUDEvt, false, true, false );
|
|
}
|
|
else
|
|
ListBox::DrawEntry( rUDEvt, false, true, true );
|
|
}
|
|
else
|
|
ListBox::DrawEntry( rUDEvt, true, true, false );
|
|
}
|
|
|
|
// =======================================================================
|
|
// LineListBox
|
|
// =======================================================================
|
|
|
|
BorderWidthImpl::BorderWidthImpl( sal_uInt16 nFlags, double nRate1, double nRate2, double nRateGap ):
|
|
m_nFlags( nFlags ),
|
|
m_nRate1( nRate1 ),
|
|
m_nRate2( nRate2 ),
|
|
m_nRateGap( nRateGap )
|
|
{
|
|
}
|
|
|
|
BorderWidthImpl& BorderWidthImpl::operator= ( const BorderWidthImpl& r )
|
|
{
|
|
m_nFlags = r.m_nFlags;
|
|
m_nRate1 = r.m_nRate1;
|
|
m_nRate2 = r.m_nRate2;
|
|
m_nRateGap = r.m_nRateGap;
|
|
return *this;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
|
|
long BorderWidthImpl::GetLine1( long nWidth ) const
|
|
{
|
|
long result = static_cast<long>(m_nRate1);
|
|
if ( ( m_nFlags & CHANGE_LINE1 ) > 0 )
|
|
{
|
|
long const nConstant2 = (m_nFlags & CHANGE_LINE2) ? 0 : m_nRate2;
|
|
long const nConstantD = (m_nFlags & CHANGE_DIST ) ? 0 : m_nRateGap;
|
|
result = std::max<long>(0,
|
|
static_cast<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;
|
|
}
|
|
|
|
long BorderWidthImpl::GetLine2( long nWidth ) const
|
|
{
|
|
long result = static_cast<long>(m_nRate2);
|
|
if ( ( m_nFlags & CHANGE_LINE2 ) > 0 )
|
|
{
|
|
long const nConstant1 = (m_nFlags & CHANGE_LINE1) ? 0 : m_nRate1;
|
|
long const nConstantD = (m_nFlags & CHANGE_DIST ) ? 0 : m_nRateGap;
|
|
result = std::max<long>(0,
|
|
static_cast<long>((m_nRate2 * nWidth) + 0.5)
|
|
- (nConstant1 + nConstantD));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
long BorderWidthImpl::GetGap( long nWidth ) const
|
|
{
|
|
long result = static_cast<long>(m_nRateGap);
|
|
if ( ( m_nFlags & CHANGE_DIST ) > 0 )
|
|
{
|
|
long const nConstant1 = (m_nFlags & CHANGE_LINE1) ? 0 : m_nRate1;
|
|
long const nConstant2 = (m_nFlags & CHANGE_LINE2) ? 0 : m_nRate2;
|
|
result = std::max<long>(0,
|
|
static_cast<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( long nTested, double nRate, bool nChanging )
|
|
{
|
|
double nWidth = -1.0;
|
|
if ( nChanging )
|
|
nWidth = double( nTested ) / nRate;
|
|
else
|
|
{
|
|
if ( double( nTested ) == nRate )
|
|
nWidth = nRate;
|
|
}
|
|
|
|
return nWidth;
|
|
}
|
|
|
|
long BorderWidthImpl::GuessWidth( long nLine1, long nLine2, long nGap )
|
|
{
|
|
std::vector< double > aToCompare;
|
|
bool bInvalid = false;
|
|
|
|
bool bLine1Change = ( m_nFlags & CHANGE_LINE1 ) > 0;
|
|
double nWidth1 = lcl_getGuessedWidth( nLine1, m_nRate1, bLine1Change );
|
|
if ( bLine1Change )
|
|
aToCompare.push_back( nWidth1 );
|
|
else if ( !bLine1Change && nWidth1 < 0 )
|
|
bInvalid = true;
|
|
|
|
bool bLine2Change = ( m_nFlags & CHANGE_LINE2 ) > 0;
|
|
double nWidth2 = lcl_getGuessedWidth( nLine2, m_nRate2, bLine2Change );
|
|
if ( bLine2Change )
|
|
aToCompare.push_back( nWidth2 );
|
|
else if ( !bLine2Change && nWidth2 < 0 )
|
|
bInvalid = true;
|
|
|
|
bool bGapChange = ( m_nFlags & CHANGE_DIST ) > 0;
|
|
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();
|
|
std::vector< double >::iterator pIt = aToCompare.begin();
|
|
while ( pIt != aToCompare.end() && !bInvalid )
|
|
{
|
|
bInvalid = ( nWidth != *pIt );
|
|
++pIt;
|
|
}
|
|
nWidth = (bInvalid) ? 0.0 : nLine1 + nLine2 + nGap;
|
|
}
|
|
|
|
return nWidth;
|
|
}
|
|
|
|
/** Utility class storing the border line width, style and colors. The widths
|
|
are defined in Twips.
|
|
*/
|
|
class ImpLineListData
|
|
{
|
|
private:
|
|
BorderWidthImpl m_aWidthImpl;
|
|
|
|
Color ( *m_pColor1Fn )( Color );
|
|
Color ( *m_pColor2Fn )( Color );
|
|
Color ( *m_pColorDistFn )( Color, Color );
|
|
|
|
long m_nMinWidth;
|
|
sal_uInt16 m_nStyle;
|
|
|
|
public:
|
|
ImpLineListData( BorderWidthImpl aWidthImpl, sal_uInt16 nStyle,
|
|
long nMinWidth=0, Color ( *pColor1Fn ) ( Color ) = &sameColor,
|
|
Color ( *pColor2Fn ) ( Color ) = &sameColor, Color ( *pColorDistFn ) ( Color, Color ) = &sameDistColor );
|
|
|
|
/** Returns the computed width of the line 1 in twips. */
|
|
long GetLine1ForWidth( long nWidth ) { return m_aWidthImpl.GetLine1( nWidth ); }
|
|
|
|
/** Returns the computed width of the line 2 in twips. */
|
|
long GetLine2ForWidth( long nWidth ) { return m_aWidthImpl.GetLine2( nWidth ); }
|
|
|
|
/** Returns the computed width of the gap in twips. */
|
|
long GetDistForWidth( long nWidth ) { return m_aWidthImpl.GetGap( nWidth ); }
|
|
|
|
Color GetColorLine1( const Color& aMain );
|
|
Color GetColorLine2( const Color& aMain );
|
|
Color GetColorDist( const Color& aMain, const Color& rDefault );
|
|
|
|
/** Returns the minimum width in twips */
|
|
long GetMinWidth( );
|
|
sal_uInt16 GetStyle( );
|
|
};
|
|
|
|
ImpLineListData::ImpLineListData( BorderWidthImpl aWidthImpl,
|
|
sal_uInt16 nStyle, long nMinWidth, Color ( *pColor1Fn )( Color ),
|
|
Color ( *pColor2Fn )( Color ), Color ( *pColorDistFn )( Color, Color ) ) :
|
|
m_aWidthImpl( aWidthImpl ),
|
|
m_pColor1Fn( pColor1Fn ),
|
|
m_pColor2Fn( pColor2Fn ),
|
|
m_pColorDistFn( pColorDistFn ),
|
|
m_nMinWidth( nMinWidth ),
|
|
m_nStyle( nStyle )
|
|
{
|
|
}
|
|
|
|
long ImpLineListData::GetMinWidth( )
|
|
{
|
|
return m_nMinWidth;
|
|
}
|
|
|
|
Color ImpLineListData::GetColorLine1( const Color& rMain )
|
|
{
|
|
return ( *m_pColor1Fn )( rMain );
|
|
}
|
|
|
|
Color ImpLineListData::GetColorLine2( const Color& rMain )
|
|
{
|
|
return ( *m_pColor2Fn )( rMain );
|
|
}
|
|
|
|
Color ImpLineListData::GetColorDist( const Color& rMain, const Color& rDefault )
|
|
{
|
|
return ( *m_pColorDistFn )( rMain, rDefault );
|
|
}
|
|
|
|
sal_uInt16 LineListBox::GetSelectEntryStyle( sal_uInt16 nSelIndex ) const
|
|
{
|
|
sal_uInt16 nStyle = table::BorderLineStyle::SOLID;
|
|
sal_uInt16 nPos = GetSelectEntryPos( nSelIndex );
|
|
if ( nPos != LISTBOX_ENTRY_NOTFOUND )
|
|
{
|
|
if (!m_sNone.isEmpty())
|
|
nPos--;
|
|
nStyle = GetEntryStyle( nPos );
|
|
}
|
|
|
|
return nStyle;
|
|
}
|
|
|
|
sal_uInt16 ImpLineListData::GetStyle( )
|
|
{
|
|
return m_nStyle;
|
|
}
|
|
|
|
|
|
|
|
void lclDrawPolygon( OutputDevice& rDev, const basegfx::B2DPolygon& rPolygon, long nWidth, sal_uInt16 nDashing )
|
|
{
|
|
sal_uInt16 nOldAA = rDev.GetAntialiasing();
|
|
rDev.SetAntialiasing( nOldAA & ~ANTIALIASING_ENABLE_B2DDRAW );
|
|
|
|
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() == MAP_PIXEL && nWidth == nPix)
|
|
nWidth = 0;
|
|
|
|
for ( sal_uInt32 i = 0; i < aPolygons.count( ); i++ )
|
|
{
|
|
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.
|
|
*/
|
|
std::vector<double> GetDashing( sal_uInt16 nDashing )
|
|
{
|
|
std::vector<double> aPattern;
|
|
switch (nDashing)
|
|
{
|
|
case table::BorderLineStyle::DOTTED:
|
|
aPattern.push_back( 1.0 ); // line
|
|
aPattern.push_back( 2.0 ); // blank
|
|
break;
|
|
case table::BorderLineStyle::DASHED:
|
|
aPattern.push_back( 16.0 ); // line
|
|
aPattern.push_back( 5.0 ); // blank
|
|
break;
|
|
case table::BorderLineStyle::FINE_DASHED:
|
|
aPattern.push_back( 6.0 ); // line
|
|
aPattern.push_back( 2.0 ); // blank
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
|
|
return aPattern;
|
|
}
|
|
|
|
namespace {
|
|
|
|
class ApplyScale : std::unary_function<double, void>
|
|
{
|
|
double mfScale;
|
|
public:
|
|
ApplyScale( double fScale ) : mfScale(fScale) {}
|
|
void operator() ( double& rVal )
|
|
{
|
|
rVal *= mfScale;
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
std::vector<double> GetLineDashing( sal_uInt16 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, sal_uInt16 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::tools::applyLineDashing(rPolygon, aPattern, &aPolygons);
|
|
|
|
return aPolygons;
|
|
}
|
|
|
|
void DrawLine( OutputDevice& rDev, const Point& rP1, const Point& rP2,
|
|
sal_uInt32 nWidth, sal_uInt16 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, sal_uInt16 nDashing )
|
|
{
|
|
basegfx::B2DPolygon aPolygon;
|
|
aPolygon.append( rP1 );
|
|
aPolygon.append( rP2 );
|
|
lclDrawPolygon( rDev, aPolygon, nWidth, nDashing );
|
|
}
|
|
|
|
}
|
|
|
|
void LineListBox::ImpGetLine( long nLine1, long nLine2, long nDistance,
|
|
Color aColor1, Color aColor2, Color aColorDist,
|
|
sal_uInt16 nStyle, Bitmap& rBmp )
|
|
{
|
|
//TODO, rather than including the " " text to force
|
|
//the line height, better would be do drop
|
|
//this calculation and draw a bitmap of height
|
|
//equal to normal text line and center the
|
|
//line within that
|
|
long nMinWidth = GetTextWidth(OUString("----------"));
|
|
Size aSize = CalcSubEditSize();
|
|
aSize.Width() = std::max(nMinWidth, aSize.Width());
|
|
aSize.Width() -= aTxtSize.Width();
|
|
aSize.Width() -= 6;
|
|
aSize.Height() = aTxtSize.Height();
|
|
|
|
// SourceUnit nach Twips
|
|
if ( eSourceUnit == FUNIT_POINT )
|
|
{
|
|
nLine1 /= 5;
|
|
nLine2 /= 5;
|
|
nDistance /= 5;
|
|
}
|
|
|
|
// Linien malen
|
|
aSize = aVirDev.PixelToLogic( aSize );
|
|
long nPix = aVirDev.PixelToLogic( Size( 0, 1 ) ).Height();
|
|
sal_uInt32 n1 = nLine1;
|
|
sal_uInt32 n2 = nLine2;
|
|
long nDist = nDistance;
|
|
n1 += nPix-1;
|
|
n1 -= n1%nPix;
|
|
if ( n2 )
|
|
{
|
|
nDist += nPix-1;
|
|
nDist -= nDist%nPix;
|
|
n2 += nPix-1;
|
|
n2 -= n2%nPix;
|
|
}
|
|
long nVirHeight = n1+nDist+n2;
|
|
if ( nVirHeight > aSize.Height() )
|
|
aSize.Height() = nVirHeight;
|
|
// negative width should not be drawn
|
|
if ( aSize.Width() > 0 )
|
|
{
|
|
Size aVirSize = aVirDev.LogicToPixel( aSize );
|
|
if ( aVirDev.GetOutputSizePixel() != aVirSize )
|
|
aVirDev.SetOutputSizePixel( aVirSize );
|
|
aVirDev.SetFillColor( aColorDist );
|
|
aVirDev.DrawRect( 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, table::BorderLineStyle::SOLID );
|
|
}
|
|
rBmp = aVirDev.GetBitmap( Point(), Size( aSize.Width(), n1+nDist+n2 ) );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void LineListBox::ImplInit()
|
|
{
|
|
aTxtSize.Width() = GetTextWidth( OUString( " " ) );
|
|
aTxtSize.Height() = GetTextHeight();
|
|
pLineList = new ImpLineList();
|
|
eUnit = FUNIT_POINT;
|
|
eSourceUnit = FUNIT_POINT;
|
|
|
|
aVirDev.SetLineColor();
|
|
aVirDev.SetMapMode( MapMode( MAP_TWIP ) );
|
|
|
|
UpdatePaintLineColor();
|
|
}
|
|
|
|
|
|
|
|
LineListBox::LineListBox( Window* pParent, WinBits nWinStyle ) :
|
|
ListBox( pParent, nWinStyle ),
|
|
m_nWidth( 5 ),
|
|
m_sNone( ),
|
|
aColor( COL_BLACK ),
|
|
maPaintCol( COL_BLACK )
|
|
{
|
|
ImplInit();
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeLineListBox(Window *pParent, VclBuilder::stringmap &rMap)
|
|
{
|
|
bool bDropdown = VclBuilder::extractDropdown(rMap);
|
|
WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
|
|
if (bDropdown)
|
|
nWinBits |= WB_DROPDOWN;
|
|
LineListBox *pListBox = new LineListBox(pParent, nWinBits);
|
|
if (bDropdown)
|
|
pListBox->EnableAutoSize(true);
|
|
return pListBox;
|
|
}
|
|
|
|
|
|
|
|
LineListBox::~LineListBox()
|
|
{
|
|
for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
|
|
if ( (*pLineList)[ i ] ) {
|
|
delete (*pLineList)[ i ];
|
|
}
|
|
}
|
|
pLineList->clear();
|
|
delete pLineList;
|
|
}
|
|
|
|
sal_uInt16 LineListBox::GetStylePos( sal_uInt16 nListPos, long nWidth )
|
|
{
|
|
sal_uInt16 nPos = LISTBOX_ENTRY_NOTFOUND;
|
|
if (!m_sNone.isEmpty())
|
|
nListPos--;
|
|
|
|
sal_uInt16 i = 0;
|
|
sal_uInt16 n = 0;
|
|
sal_uInt16 nCount = pLineList->size();
|
|
while ( nPos == LISTBOX_ENTRY_NOTFOUND && i < nCount )
|
|
{
|
|
ImpLineListData* pData = (*pLineList)[ i ];
|
|
if ( pData && pData->GetMinWidth() <= nWidth )
|
|
{
|
|
if ( nListPos == n )
|
|
nPos = i;
|
|
n++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return nPos;
|
|
}
|
|
|
|
|
|
void LineListBox::SelectEntry( sal_uInt16 nStyle, sal_Bool bSelect )
|
|
{
|
|
sal_uInt16 nPos = GetEntryPos( nStyle );
|
|
if ( nPos != LISTBOX_ENTRY_NOTFOUND )
|
|
ListBox::SelectEntryPos( nPos, bSelect );
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 LineListBox::InsertEntry( const OUString& rStr, sal_uInt16 nPos )
|
|
{
|
|
nPos = ListBox::InsertEntry( rStr, nPos );
|
|
if ( nPos != LISTBOX_ERROR ) {
|
|
if ( nPos < pLineList->size() ) {
|
|
ImpLineList::iterator it = pLineList->begin();
|
|
::std::advance( it, nPos );
|
|
pLineList->insert( it, reinterpret_cast<ImpLineListData *>(NULL) );
|
|
} else {
|
|
pLineList->push_back( NULL );
|
|
}
|
|
}
|
|
return nPos;
|
|
}
|
|
|
|
|
|
|
|
void LineListBox::InsertEntry(
|
|
BorderWidthImpl aWidthImpl, sal_uInt16 nStyle, long nMinWidth,
|
|
ColorFunc pColor1Fn, ColorFunc pColor2Fn, ColorDistFunc pColorDistFn )
|
|
{
|
|
ImpLineListData* pData = new ImpLineListData(
|
|
aWidthImpl, nStyle, nMinWidth, pColor1Fn, pColor2Fn, pColorDistFn);
|
|
pLineList->push_back( pData );
|
|
}
|
|
|
|
|
|
|
|
void LineListBox::RemoveEntry( sal_uInt16 nPos )
|
|
{
|
|
ListBox::RemoveEntry( nPos );
|
|
|
|
if ( nPos < pLineList->size() ) {
|
|
ImpLineList::iterator it = pLineList->begin();
|
|
::std::advance( it, nPos );
|
|
if ( *it ) delete *it;
|
|
pLineList->erase( it );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void LineListBox::Clear()
|
|
{
|
|
for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
|
|
if ( (*pLineList)[ i ] ) {
|
|
delete (*pLineList)[ i ];
|
|
}
|
|
}
|
|
pLineList->clear();
|
|
|
|
ListBox::Clear();
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 LineListBox::GetEntryPos( sal_uInt16 nStyle ) const
|
|
{
|
|
for ( size_t i = 0, n = pLineList->size(); i < n; ++i ) {
|
|
ImpLineListData* pData = (*pLineList)[ i ];
|
|
if ( pData )
|
|
{
|
|
if ( GetEntryStyle( i ) == nStyle )
|
|
{
|
|
size_t nPos = i;
|
|
if (!m_sNone.isEmpty())
|
|
nPos ++;
|
|
return (sal_uInt16)nPos;
|
|
}
|
|
}
|
|
}
|
|
return LISTBOX_ENTRY_NOTFOUND;
|
|
}
|
|
|
|
|
|
|
|
sal_uInt16 LineListBox::GetEntryStyle( sal_uInt16 nPos ) const
|
|
{
|
|
ImpLineListData* pData = (nPos < pLineList->size()) ? (*pLineList)[ nPos ] : NULL;
|
|
return ( pData ) ? pData->GetStyle() : table::BorderLineStyle::NONE;
|
|
}
|
|
|
|
|
|
|
|
sal_Bool LineListBox::UpdatePaintLineColor( void )
|
|
{
|
|
const StyleSettings& rSettings = GetSettings().GetStyleSettings();
|
|
Color aNewCol( rSettings.GetWindowColor().IsDark()? rSettings.GetLabelTextColor() : aColor );
|
|
|
|
sal_Bool bRet = aNewCol != maPaintCol;
|
|
|
|
if( bRet )
|
|
maPaintCol = aNewCol;
|
|
|
|
return bRet;
|
|
}
|
|
|
|
void LineListBox::UpdateEntries( long nOldWidth )
|
|
{
|
|
SetUpdateMode( false );
|
|
|
|
UpdatePaintLineColor( );
|
|
|
|
sal_uInt16 nSelEntry = GetSelectEntryPos();
|
|
sal_uInt16 nTypePos = GetStylePos( nSelEntry, nOldWidth );
|
|
|
|
// Remove the old entries
|
|
while ( GetEntryCount( ) > 0 )
|
|
ListBox::RemoveEntry( 0 );
|
|
|
|
// Add the new entries based on the defined width
|
|
if (!m_sNone.isEmpty())
|
|
ListBox::InsertEntry( m_sNone, LISTBOX_APPEND );
|
|
|
|
sal_uInt16 n = 0;
|
|
sal_uInt16 nCount = pLineList->size( );
|
|
while ( n < nCount )
|
|
{
|
|
ImpLineListData* pData = (*pLineList)[ n ];
|
|
if ( pData && pData->GetMinWidth() <= m_nWidth )
|
|
{
|
|
Bitmap aBmp;
|
|
ImpGetLine( pData->GetLine1ForWidth( m_nWidth ),
|
|
pData->GetLine2ForWidth( m_nWidth ),
|
|
pData->GetDistForWidth( m_nWidth ),
|
|
GetColorLine1( GetEntryCount( ) ),
|
|
GetColorLine2( GetEntryCount( ) ),
|
|
GetColorDist( GetEntryCount( ) ),
|
|
pData->GetStyle(), aBmp );
|
|
ListBox::InsertEntry(OUString(" "), Image(aBmp), LISTBOX_APPEND);
|
|
if ( n == nTypePos )
|
|
SelectEntryPos( GetEntryCount() - 1 );
|
|
}
|
|
else if ( n == nTypePos )
|
|
SetNoSelection();
|
|
n++;
|
|
}
|
|
|
|
SetUpdateMode( true );
|
|
Invalidate();
|
|
}
|
|
|
|
|
|
|
|
Color LineListBox::GetColorLine1( sal_uInt16 nPos )
|
|
{
|
|
Color rResult = GetPaintColor( );
|
|
|
|
sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
|
|
ImpLineListData* pData = (*pLineList)[ nStyle ];
|
|
if ( pData )
|
|
rResult = pData->GetColorLine1( GetColor( ) );
|
|
|
|
return rResult;
|
|
}
|
|
|
|
Color LineListBox::GetColorLine2( sal_uInt16 nPos )
|
|
{
|
|
Color rResult = GetPaintColor( );
|
|
|
|
sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
|
|
ImpLineListData* pData = (*pLineList)[ nStyle ];
|
|
if ( pData )
|
|
rResult = pData->GetColorLine2( GetColor( ) );
|
|
|
|
return rResult;
|
|
}
|
|
|
|
Color LineListBox::GetColorDist( sal_uInt16 nPos )
|
|
{
|
|
Color rResult = GetSettings().GetStyleSettings().GetFieldColor();
|
|
|
|
sal_uInt16 nStyle = GetStylePos( nPos, m_nWidth );
|
|
ImpLineListData* pData = (*pLineList)[ nStyle ];
|
|
if ( pData )
|
|
rResult = pData->GetColorDist( GetColor( ), rResult );
|
|
|
|
return rResult;
|
|
}
|
|
|
|
|
|
|
|
void LineListBox::DataChanged( const DataChangedEvent& rDCEvt )
|
|
{
|
|
ListBox::DataChanged( rDCEvt );
|
|
|
|
if( ( rDCEvt.GetType() == DATACHANGED_SETTINGS ) && ( rDCEvt.GetFlags() & SETTINGS_STYLE ) )
|
|
UpdateEntries( m_nWidth );
|
|
}
|
|
|
|
|
|
// ===================================================================
|
|
// FontNameBox
|
|
// ===================================================================
|
|
|
|
FontNameBox::FontNameBox( Window* pParent, WinBits nWinStyle ) :
|
|
ComboBox( pParent, nWinStyle )
|
|
{
|
|
mpFontList = NULL;
|
|
mbWYSIWYG = sal_False;
|
|
InitFontMRUEntriesFile();
|
|
}
|
|
|
|
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeFontNameBox(Window *pParent, VclBuilder::stringmap &rMap)
|
|
{
|
|
bool bDropdown = VclBuilder::extractDropdown(rMap);
|
|
WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
|
|
if (bDropdown)
|
|
nWinBits |= WB_DROPDOWN;
|
|
FontNameBox *pListBox = new FontNameBox(pParent, nWinBits);
|
|
if (bDropdown)
|
|
pListBox->EnableAutoSize(true);
|
|
return pListBox;
|
|
}
|
|
|
|
|
|
|
|
FontNameBox::~FontNameBox()
|
|
{
|
|
SaveMRUEntries (maFontMRUEntriesFile);
|
|
ImplDestroyFontList();
|
|
}
|
|
|
|
|
|
|
|
void FontNameBox::SaveMRUEntries( const OUString& aFontMRUEntriesFile, sal_Unicode cSep ) const
|
|
{
|
|
OString aEntries(OUStringToOString(GetMRUEntries(cSep),
|
|
RTL_TEXTENCODING_UTF8));
|
|
|
|
if (aEntries.isEmpty() || aFontMRUEntriesFile.isEmpty())
|
|
return;
|
|
|
|
SvFileStream aStream;
|
|
aStream.Open( aFontMRUEntriesFile, STREAM_WRITE | STREAM_TRUNC );
|
|
if( ! (aStream.IsOpen() && aStream.IsWritable()) )
|
|
{
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
fprintf( stderr, "FontNameBox::SaveMRUEntries: opening mru entries file %s failed\n", OUStringToOString(aFontMRUEntriesFile, RTL_TEXTENCODING_UTF8 ).getStr() );
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
aStream.SetLineDelimiter( LINEEND_LF );
|
|
aStream.WriteLine( aEntries );
|
|
aStream.WriteLine( OString() );
|
|
}
|
|
|
|
|
|
|
|
void FontNameBox::LoadMRUEntries( const OUString& aFontMRUEntriesFile, sal_Unicode cSep )
|
|
{
|
|
if( aFontMRUEntriesFile.isEmpty() )
|
|
return;
|
|
|
|
SvFileStream aStream( aFontMRUEntriesFile, STREAM_READ );
|
|
if( ! aStream.IsOpen() )
|
|
{
|
|
#if OSL_DEBUG_LEVEL > 1
|
|
fprintf( stderr, "FontNameBox::LoadMRUEntries: opening mru entries file %s failed\n", OUStringToOString(aFontMRUEntriesFile, RTL_TEXTENCODING_UTF8).getStr() );
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
OString aLine;
|
|
aStream.ReadLine( aLine );
|
|
OUString aEntries = OStringToOUString(aLine,
|
|
RTL_TEXTENCODING_UTF8);
|
|
SetMRUEntries( aEntries, cSep );
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
{
|
|
delete mpFontList;
|
|
}
|
|
|
|
|
|
|
|
void FontNameBox::Fill( const FontList* pList )
|
|
{
|
|
// store old text and clear box
|
|
OUString aOldText = GetText();
|
|
OUString rEntries = GetMRUEntries();
|
|
bool bLoadFromFile = rEntries.isEmpty();
|
|
Clear();
|
|
|
|
ImplDestroyFontList();
|
|
mpFontList = new ImplFontList;
|
|
|
|
// insert fonts
|
|
sal_uInt16 nFontCount = pList->GetFontNameCount();
|
|
for ( sal_uInt16 i = 0; i < nFontCount; i++ )
|
|
{
|
|
const FontInfo& rFontInfo = pList->GetFontName( i );
|
|
sal_uLong nIndex = InsertEntry( rFontInfo.GetName() );
|
|
if ( nIndex != LISTBOX_ERROR )
|
|
{
|
|
if ( nIndex < mpFontList->size() ) {
|
|
ImplFontList::iterator it = mpFontList->begin();
|
|
::std::advance( it, nIndex );
|
|
mpFontList->insert( it, rFontInfo );
|
|
} else {
|
|
mpFontList->push_back( rFontInfo );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( bLoadFromFile )
|
|
LoadMRUEntries (maFontMRUEntriesFile);
|
|
else
|
|
SetMRUEntries( rEntries );
|
|
|
|
ImplCalcUserItemSize();
|
|
|
|
// restore text
|
|
if (!aOldText.isEmpty())
|
|
SetText( aOldText );
|
|
}
|
|
|
|
|
|
|
|
void FontNameBox::EnableWYSIWYG( sal_Bool bEnable )
|
|
{
|
|
if ( bEnable != mbWYSIWYG )
|
|
{
|
|
mbWYSIWYG = bEnable;
|
|
EnableUserDraw( mbWYSIWYG );
|
|
ImplCalcUserItemSize();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void FontNameBox::ImplCalcUserItemSize()
|
|
{
|
|
Size aUserItemSz;
|
|
if ( mbWYSIWYG && mpFontList )
|
|
{
|
|
aUserItemSz = Size(MAXPREVIEWWIDTH, GetTextHeight() );
|
|
aUserItemSz.Height() *= 16;
|
|
aUserItemSz.Height() /= 10;
|
|
}
|
|
SetUserItemSize( aUserItemSz );
|
|
}
|
|
|
|
namespace
|
|
{
|
|
long shrinkFontToFit(OUString &rSampleText, long nH, Font &rFont, OutputDevice &rDevice, Rectangle &rTextRect)
|
|
{
|
|
long nWidth = 0;
|
|
|
|
Size aSize( rFont.GetSize() );
|
|
|
|
//Make sure it fits in the available height
|
|
while (aSize.Height() > 0)
|
|
{
|
|
if (!rDevice.GetTextBoundRect(rTextRect, rSampleText, 0, 0))
|
|
break;
|
|
if (rTextRect.GetHeight() <= nH)
|
|
{
|
|
nWidth = rTextRect.GetWidth();
|
|
break;
|
|
}
|
|
|
|
aSize.Height() -= EXTRAFONTSIZE;
|
|
rFont.SetSize(aSize);
|
|
rDevice.SetFont(rFont);
|
|
}
|
|
|
|
return nWidth;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void FontNameBox::UserDraw( const UserDrawEvent& rUDEvt )
|
|
{
|
|
assert( mpFontList );
|
|
|
|
FontInfo& rInfo = (*mpFontList)[ rUDEvt.GetItemId() ];
|
|
Point aTopLeft = rUDEvt.GetRect().TopLeft();
|
|
long nX = aTopLeft.X();
|
|
long nH = rUDEvt.GetRect().GetHeight();
|
|
|
|
if ( mbWYSIWYG )
|
|
{
|
|
nX += IMGOUTERTEXTSPACE;
|
|
|
|
const bool bSymbolFont = isSymbolFont(rInfo);
|
|
|
|
Color aTextColor = rUDEvt.GetDevice()->GetTextColor();
|
|
Font aOldFont( rUDEvt.GetDevice()->GetFont() );
|
|
Size aSize( aOldFont.GetSize() );
|
|
aSize.Height() += EXTRAFONTSIZE;
|
|
Font aFont( rInfo );
|
|
aFont.SetSize( aSize );
|
|
rUDEvt.GetDevice()->SetFont( aFont );
|
|
rUDEvt.GetDevice()->SetTextColor( aTextColor );
|
|
|
|
bool bUsingCorrectFont = true;
|
|
Rectangle aTextRect;
|
|
|
|
// Preview the font name
|
|
OUString sFontName = rInfo.GetName();
|
|
|
|
//If it shouldn't or can't draw its own name because it doesn't have the glyphs
|
|
if (!canRenderNameOfSelectedFont(*rUDEvt.GetDevice()))
|
|
bUsingCorrectFont = false;
|
|
else
|
|
{
|
|
//Make sure it fits in the available height, shrinking the font if necessary
|
|
bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, *rUDEvt.GetDevice(), aTextRect) != 0;
|
|
}
|
|
|
|
if (!bUsingCorrectFont)
|
|
{
|
|
rUDEvt.GetDevice()->SetFont(aOldFont);
|
|
rUDEvt.GetDevice()->GetTextBoundRect(aTextRect, sFontName, 0, 0);
|
|
}
|
|
|
|
long nTextHeight = aTextRect.GetHeight();
|
|
long nDesiredGap = (nH-nTextHeight)/2;
|
|
long nVertAdjust = nDesiredGap - aTextRect.Top();
|
|
Point aPos( nX, aTopLeft.Y() + nVertAdjust );
|
|
rUDEvt.GetDevice()->DrawText( aPos, sFontName );
|
|
long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW;
|
|
|
|
if (!bUsingCorrectFont)
|
|
rUDEvt.GetDevice()->SetFont( aFont );
|
|
|
|
OUString sSampleText;
|
|
|
|
if (!bSymbolFont)
|
|
{
|
|
const bool bNameBeginsWithLatinText = rInfo.GetName()[0] <= 'z';
|
|
|
|
if (bNameBeginsWithLatinText || !bUsingCorrectFont)
|
|
sSampleText = makeShortRepresentativeTextForSelectedFont(*rUDEvt.GetDevice());
|
|
}
|
|
|
|
//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 (size_t i = 0; i < SAL_N_ELEMENTS(aScripts); ++i)
|
|
{
|
|
OUString sText = makeShortRepresentativeTextForScript(aScripts[i]);
|
|
if (!sText.isEmpty())
|
|
{
|
|
bool bHasSampleTextGlyphs = (-1 == rUDEvt.GetDevice()->HasGlyphs(aFont, sText));
|
|
if (bHasSampleTextGlyphs)
|
|
{
|
|
sSampleText = sText;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static const UScriptCode aMinimalScripts[] =
|
|
{
|
|
USCRIPT_HEBREW, //e.g. biblical hebrew
|
|
USCRIPT_GREEK
|
|
};
|
|
|
|
for (size_t i = 0; i < SAL_N_ELEMENTS(aMinimalScripts); ++i)
|
|
{
|
|
OUString sText = makeShortMinimalTextForScript(aMinimalScripts[i]);
|
|
if (!sText.isEmpty())
|
|
{
|
|
bool bHasSampleTextGlyphs = (-1 == rUDEvt.GetDevice()->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(*rUDEvt.GetDevice());
|
|
|
|
if (!sSampleText.isEmpty())
|
|
{
|
|
const Size &rItemSize = rUDEvt.GetDevice()->GetOutputSize();
|
|
//leave a little border at the edge
|
|
long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE;
|
|
if (nSpace >= 0)
|
|
{
|
|
//Make sure it fits in the available height, and get how wide that would be
|
|
long nWidth = shrinkFontToFit(sSampleText, nH, aFont, *rUDEvt.GetDevice(), aTextRect);
|
|
//Chop letters off until it fits in the available width
|
|
while (nWidth > nSpace || nWidth > MAXPREVIEWWIDTH)
|
|
{
|
|
sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
|
|
nWidth = rUDEvt.GetDevice()->GetTextBoundRect(aTextRect, sSampleText, 0, 0) ?
|
|
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, aTopLeft.Y() + nVertAdjust);
|
|
rUDEvt.GetDevice()->DrawText( aPos, sSampleText );
|
|
}
|
|
}
|
|
}
|
|
|
|
rUDEvt.GetDevice()->SetFont( aOldFont );
|
|
DrawEntry( rUDEvt, false, false); // draw separator
|
|
}
|
|
else
|
|
{
|
|
DrawEntry( rUDEvt, true, true );
|
|
}
|
|
}
|
|
|
|
// ===================================================================
|
|
// FontStyleBox
|
|
// ===================================================================
|
|
|
|
FontStyleBox::FontStyleBox( Window* pParent, const ResId& rResId ) :
|
|
ComboBox( pParent, rResId )
|
|
{
|
|
aLastStyle = GetText();
|
|
}
|
|
|
|
FontStyleBox::FontStyleBox(Window* pParent, WinBits nBits)
|
|
: ComboBox(pParent, nBits)
|
|
{
|
|
aLastStyle = GetText();
|
|
|
|
//Use the standard texts to get an optimal size and stick to that size.
|
|
//That should stop the character dialog dancing around.
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_LIGHT));
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_LIGHT_ITALIC));
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_NORMAL));
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_NORMAL_ITALIC));
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BOLD));
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BOLD_ITALIC));
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BLACK));
|
|
InsertEntry(SVT_RESSTR(STR_SVT_STYLE_BLACK_ITALIC));
|
|
aOptimalSize = GetOptimalSize();
|
|
Clear();
|
|
}
|
|
|
|
Size FontStyleBox::GetOptimalSize() const
|
|
{
|
|
if (aOptimalSize.Width() || aOptimalSize.Height())
|
|
return aOptimalSize;
|
|
return ComboBox::GetOptimalSize();
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeFontStyleBox(Window *pParent, VclBuilder::stringmap &rMap)
|
|
{
|
|
bool bDropdown = VclBuilder::extractDropdown(rMap);
|
|
WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
|
|
if (bDropdown)
|
|
nWinBits |= WB_DROPDOWN;
|
|
FontStyleBox *pListBox = new FontStyleBox(pParent, nWinBits);
|
|
if (bDropdown)
|
|
pListBox->EnableAutoSize(true);
|
|
return pListBox;
|
|
}
|
|
|
|
FontStyleBox::~FontStyleBox()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void FontStyleBox::Select()
|
|
{
|
|
// keep text over fill operation
|
|
aLastStyle = GetText();
|
|
ComboBox::Select();
|
|
}
|
|
|
|
|
|
|
|
void FontStyleBox::LoseFocus()
|
|
{
|
|
// keep text over fill operation
|
|
aLastStyle = GetText();
|
|
ComboBox::LoseFocus();
|
|
}
|
|
|
|
|
|
|
|
void FontStyleBox::Modify()
|
|
{
|
|
CharClass aChrCls( ::comphelper::getProcessComponentContext(),
|
|
GetSettings().GetLanguageTag() );
|
|
OUString aStr = GetText();
|
|
sal_uInt16 nEntryCount = GetEntryCount();
|
|
|
|
if ( GetEntryPos( aStr ) == COMBOBOX_ENTRY_NOTFOUND )
|
|
{
|
|
aStr = aChrCls.uppercase(aStr);
|
|
for ( sal_uInt16 i = 0; i < nEntryCount; i++ )
|
|
{
|
|
OUString aEntryText = aChrCls.uppercase(GetEntry(i));
|
|
|
|
if ( aStr == aEntryText )
|
|
{
|
|
SetText( GetEntry( i ) );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ComboBox::Modify();
|
|
}
|
|
|
|
|
|
|
|
void FontStyleBox::Fill( const OUString& rName, const FontList* pList )
|
|
{
|
|
// note: this method must call ComboBox::SetText(),
|
|
// else aLastStyle will overwritten
|
|
// store prior selection position and clear box
|
|
OUString aOldText = GetText();
|
|
sal_uInt16 nPos = GetEntryPos( aOldText );
|
|
Clear();
|
|
|
|
// does a font with this name already exist?
|
|
sal_Handle hFontInfo = pList->GetFirstFontInfo( rName );
|
|
if ( hFontInfo )
|
|
{
|
|
OUString aStyleText;
|
|
FontWeight eLastWeight = WEIGHT_DONTKNOW;
|
|
FontItalic eLastItalic = ITALIC_NONE;
|
|
FontWidth eLastWidth = WIDTH_DONTKNOW;
|
|
sal_Bool bNormal = sal_False;
|
|
sal_Bool bItalic = sal_False;
|
|
sal_Bool bBold = sal_False;
|
|
sal_Bool bBoldItalic = sal_False;
|
|
sal_Bool bInsert = sal_False;
|
|
FontInfo aInfo;
|
|
while ( hFontInfo )
|
|
{
|
|
aInfo = pList->GetFontInfo( hFontInfo );
|
|
|
|
FontWeight eWeight = aInfo.GetWeight();
|
|
FontItalic eItalic = aInfo.GetItalic();
|
|
FontWidth eWidth = aInfo.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 )
|
|
InsertEntry( aStyleText );
|
|
|
|
if ( eWeight <= WEIGHT_NORMAL )
|
|
{
|
|
if ( eItalic != ITALIC_NONE )
|
|
bItalic = sal_True;
|
|
else
|
|
bNormal = sal_True;
|
|
}
|
|
else
|
|
{
|
|
if ( eItalic != ITALIC_NONE )
|
|
bBoldItalic = sal_True;
|
|
else
|
|
bBold = sal_True;
|
|
}
|
|
|
|
// For wrong StyleNames we replace this with the correct once
|
|
aStyleText = pList->GetStyleName( aInfo );
|
|
bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
|
|
if ( !bInsert )
|
|
{
|
|
aStyleText = pList->GetStyleName( eWeight, eItalic );
|
|
bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
|
|
}
|
|
|
|
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( aInfo );
|
|
if (rAttrStyleText == aTempStyleText)
|
|
aStyleText = rAttrStyleText;
|
|
bInsert = GetEntryPos( aStyleText ) == LISTBOX_ENTRY_NOTFOUND;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bItalic && (aStyleText == pList->GetItalicStr()) )
|
|
bItalic = sal_True;
|
|
else if ( !bBold && (aStyleText == pList->GetBoldStr()) )
|
|
bBold = sal_True;
|
|
else if ( !bBoldItalic && (aStyleText == pList->GetBoldItalicStr()) )
|
|
bBoldItalic = sal_True;
|
|
|
|
hFontInfo = pList->GetNextFontInfo( hFontInfo );
|
|
}
|
|
|
|
if ( bInsert )
|
|
InsertEntry( aStyleText );
|
|
|
|
// certain style as copy
|
|
if ( bNormal )
|
|
{
|
|
if ( !bItalic )
|
|
InsertEntry( pList->GetItalicStr() );
|
|
if ( !bBold )
|
|
InsertEntry( pList->GetBoldStr() );
|
|
}
|
|
if ( !bBoldItalic )
|
|
{
|
|
if ( bNormal || bItalic || bBold )
|
|
InsertEntry( pList->GetBoldItalicStr() );
|
|
}
|
|
if (!aOldText.isEmpty())
|
|
{
|
|
if ( GetEntryPos( aLastStyle ) != LISTBOX_ENTRY_NOTFOUND )
|
|
ComboBox::SetText( aLastStyle );
|
|
else
|
|
{
|
|
if ( nPos >= GetEntryCount() )
|
|
ComboBox::SetText( GetEntry( 0 ) );
|
|
else
|
|
ComboBox::SetText( GetEntry( nPos ) );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// insert standard styles if no font
|
|
InsertEntry( pList->GetNormalStr() );
|
|
InsertEntry( pList->GetItalicStr() );
|
|
InsertEntry( pList->GetBoldStr() );
|
|
InsertEntry( pList->GetBoldItalicStr() );
|
|
if (!aOldText.isEmpty())
|
|
{
|
|
if ( nPos > GetEntryCount() )
|
|
ComboBox::SetText( GetEntry( 0 ) );
|
|
else
|
|
ComboBox::SetText( GetEntry( nPos ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===================================================================
|
|
// FontSizeBox
|
|
// ===================================================================
|
|
|
|
FontSizeBox::FontSizeBox( Window* pParent, WinBits nWinSize ) :
|
|
MetricBox( pParent, nWinSize )
|
|
{
|
|
ImplInit();
|
|
}
|
|
|
|
extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeFontSizeBox(Window *pParent, VclBuilder::stringmap &rMap)
|
|
{
|
|
bool bDropdown = VclBuilder::extractDropdown(rMap);
|
|
WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP;
|
|
if (bDropdown)
|
|
nWinBits |= WB_DROPDOWN;
|
|
FontSizeBox* pListBox = new FontSizeBox(pParent, nWinBits);
|
|
if (bDropdown)
|
|
pListBox->EnableAutoSize(true);
|
|
return pListBox;
|
|
}
|
|
|
|
|
|
|
|
FontSizeBox::~FontSizeBox()
|
|
{
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::ImplInit()
|
|
{
|
|
EnableAutocomplete( false );
|
|
|
|
bRelativeMode = sal_False;
|
|
bPtRelative = sal_False;
|
|
bRelative = sal_False;
|
|
bStdSize = sal_False;
|
|
pFontList = NULL;
|
|
|
|
SetShowTrailingZeros( false );
|
|
SetDecimalDigits( 1 );
|
|
SetMin( 20 );
|
|
SetMax( 9999 );
|
|
SetProminentEntryType( PROMINENT_MIDDLE );
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::Reformat()
|
|
{
|
|
FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
|
|
if ( !bRelativeMode || !aFontSizeNames.IsEmpty() )
|
|
{
|
|
long nNewValue = aFontSizeNames.Name2Size( GetText() );
|
|
if ( nNewValue)
|
|
{
|
|
mnLastValue = nNewValue;
|
|
return;
|
|
}
|
|
}
|
|
|
|
MetricBox::Reformat();
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::Modify()
|
|
{
|
|
MetricBox::Modify();
|
|
|
|
if ( bRelativeMode )
|
|
{
|
|
OUString aStr = comphelper::string::stripStart(GetText(), ' ');
|
|
|
|
sal_Bool bNewMode = bRelative;
|
|
sal_Bool bOldPtRelMode = bPtRelative;
|
|
|
|
if ( bRelative )
|
|
{
|
|
bPtRelative = sal_False;
|
|
const sal_Unicode* pStr = aStr.getStr();
|
|
while ( *pStr )
|
|
{
|
|
if ( ((*pStr < '0') || (*pStr > '9')) && (*pStr != '%') )
|
|
{
|
|
if ( ('-' == *pStr || '+' == *pStr) && !bPtRelative )
|
|
bPtRelative = sal_True;
|
|
else if ( bPtRelative && 'p' == *pStr && 't' == *++pStr )
|
|
;
|
|
else
|
|
{
|
|
bNewMode = sal_False;
|
|
break;
|
|
}
|
|
}
|
|
pStr++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( -1 != aStr.indexOf('%') )
|
|
{
|
|
bNewMode = sal_True;
|
|
bPtRelative = sal_False;
|
|
}
|
|
|
|
if ( '-' == aStr[0] || '+' == aStr[0] )
|
|
{
|
|
bNewMode = sal_True;
|
|
bPtRelative = sal_True;
|
|
}
|
|
}
|
|
|
|
if ( bNewMode != bRelative || bPtRelative != bOldPtRelMode )
|
|
SetRelative( bNewMode );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::Fill( const FontInfo* pInfo, 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 sal_IntPtr* pTempAry;
|
|
const sal_IntPtr* pAry = 0;
|
|
|
|
if( pInfo )
|
|
{
|
|
aFontInfo = *pInfo;
|
|
pAry = pList->GetSizeAry( *pInfo );
|
|
}
|
|
else
|
|
{
|
|
pAry = pList->GetStdSizeAry();
|
|
}
|
|
|
|
// first insert font size names (for simplified/traditional chinese)
|
|
FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
|
|
if ( pAry == pList->GetStdSizeAry() )
|
|
{
|
|
// for standard sizes we don't need to bother
|
|
if ( bStdSize && GetEntryCount() && aFontSizeNames.IsEmpty() )
|
|
return;
|
|
bStdSize = sal_True;
|
|
}
|
|
else
|
|
bStdSize = sal_False;
|
|
|
|
Selection aSelection = GetSelection();
|
|
OUString aStr = GetText();
|
|
|
|
Clear();
|
|
sal_uInt16 nPos = 0;
|
|
|
|
if ( !aFontSizeNames.IsEmpty() )
|
|
{
|
|
if ( pAry == pList->GetStdSizeAry() )
|
|
{
|
|
// for scalable fonts all font size names
|
|
sal_uLong nCount = aFontSizeNames.Count();
|
|
for( sal_uLong i = 0; i < nCount; i++ )
|
|
{
|
|
OUString aSizeName = aFontSizeNames.GetIndexName( i );
|
|
sal_IntPtr nSize = aFontSizeNames.GetIndexSize( i );
|
|
ComboBox::InsertEntry( aSizeName, nPos );
|
|
ComboBox::SetEntryData( nPos, (void*)(-nSize) ); // mark as special
|
|
nPos++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// for fixed size fonts only selectable font size names
|
|
pTempAry = pAry;
|
|
while ( *pTempAry )
|
|
{
|
|
OUString aSizeName = aFontSizeNames.Size2Name( *pTempAry );
|
|
if ( !aSizeName.isEmpty() )
|
|
{
|
|
ComboBox::InsertEntry( aSizeName, nPos );
|
|
ComboBox::SetEntryData( nPos, (void*)(-(*pTempAry)) ); // mark as special
|
|
nPos++;
|
|
}
|
|
pTempAry++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// then insert numerical font size values
|
|
pTempAry = pAry;
|
|
while ( *pTempAry )
|
|
{
|
|
InsertValue( *pTempAry, FUNIT_NONE, nPos );
|
|
ComboBox::SetEntryData( nPos, (void*)(*pTempAry) );
|
|
nPos++;
|
|
pTempAry++;
|
|
}
|
|
|
|
SetText( aStr );
|
|
SetSelection( aSelection );
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::EnableRelativeMode( sal_uInt16 nMin, sal_uInt16 nMax, sal_uInt16 nStep )
|
|
{
|
|
bRelativeMode = sal_True;
|
|
nRelMin = nMin;
|
|
nRelMax = nMax;
|
|
nRelStep = nStep;
|
|
SetUnit( FUNIT_POINT );
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::EnablePtRelativeMode( short nMin, short nMax, short nStep )
|
|
{
|
|
bRelativeMode = sal_True;
|
|
nPtRelMin = nMin;
|
|
nPtRelMax = nMax;
|
|
nPtRelStep = nStep;
|
|
SetUnit( FUNIT_POINT );
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::SetRelative( sal_Bool bNewRelative )
|
|
{
|
|
if ( bRelativeMode )
|
|
{
|
|
Selection aSelection = GetSelection();
|
|
OUString aStr = comphelper::string::stripStart(GetText(), ' ');
|
|
|
|
if ( bNewRelative )
|
|
{
|
|
bRelative = sal_True;
|
|
bStdSize = sal_False;
|
|
|
|
if ( bPtRelative )
|
|
{
|
|
SetDecimalDigits( 1 );
|
|
SetMin( nPtRelMin );
|
|
SetMax( nPtRelMax );
|
|
SetUnit( FUNIT_POINT );
|
|
|
|
Clear();
|
|
|
|
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 );
|
|
SetMin( nRelMin );
|
|
SetMax( nRelMax );
|
|
SetUnit( FUNIT_PERCENT );
|
|
|
|
Clear();
|
|
sal_uInt16 i = nRelMin;
|
|
while ( i <= nRelMax )
|
|
{
|
|
InsertValue( i );
|
|
i = i + nRelStep;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bRelative = bPtRelative = sal_False;
|
|
SetDecimalDigits( 1 );
|
|
SetMin( 20 );
|
|
SetMax( 9999 );
|
|
SetUnit( FUNIT_POINT );
|
|
if ( pFontList )
|
|
Fill( &aFontInfo, pFontList );
|
|
}
|
|
|
|
SetText( aStr );
|
|
SetSelection( aSelection );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
OUString FontSizeBox::CreateFieldText( sal_Int64 nValue ) const
|
|
{
|
|
OUString sRet( MetricBox::CreateFieldText( nValue ) );
|
|
if ( bRelativeMode && bPtRelative && (0 <= nValue) && !sRet.isEmpty() )
|
|
sRet = "+" + sRet;
|
|
return sRet;
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::SetValue( sal_Int64 nNewValue, FieldUnit eInUnit )
|
|
{
|
|
if ( !bRelative )
|
|
{
|
|
sal_Int64 nTempValue = MetricField::ConvertValue( nNewValue, GetBaseValue(), GetDecimalDigits(), eInUnit, GetUnit() );
|
|
FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
|
|
// conversion loses precision; however font sizes should
|
|
// never have a problem with that
|
|
OUString aName = aFontSizeNames.Size2Name( static_cast<long>(nTempValue) );
|
|
if ( !aName.isEmpty() && (GetEntryPos( aName ) != LISTBOX_ENTRY_NOTFOUND) )
|
|
{
|
|
mnLastValue = nTempValue;
|
|
SetText( aName );
|
|
mnFieldValue = mnLastValue;
|
|
SetEmptyFieldValueData( false );
|
|
return;
|
|
}
|
|
}
|
|
|
|
MetricBox::SetValue( nNewValue, eInUnit );
|
|
}
|
|
|
|
|
|
|
|
void FontSizeBox::SetValue( sal_Int64 nNewValue )
|
|
{
|
|
SetValue( nNewValue, FUNIT_NONE );
|
|
}
|
|
|
|
|
|
|
|
sal_Int64 FontSizeBox::GetValue( sal_uInt16 nPos, FieldUnit eOutUnit ) const
|
|
{
|
|
if ( !bRelative )
|
|
{
|
|
sal_Int64 nComboVal = static_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(ComboBox::GetEntryData( nPos )));
|
|
if ( nComboVal < 0 ) // marked as special?
|
|
{
|
|
return MetricField::ConvertValue( -nComboVal, mnBaseValue, GetDecimalDigits(),
|
|
meUnit, eOutUnit );
|
|
}
|
|
}
|
|
|
|
// do normal font size processing
|
|
sal_Int64 nRetValue = MetricBox::GetValue( nPos, eOutUnit );
|
|
return nRetValue;
|
|
}
|
|
|
|
|
|
|
|
sal_Int64 FontSizeBox::GetValue( FieldUnit eOutUnit ) const
|
|
{
|
|
if ( !bRelative )
|
|
{
|
|
FontSizeNames aFontSizeNames( GetSettings().GetUILanguageTag().getLanguageType() );
|
|
sal_Int64 nValue = aFontSizeNames.Name2Size( GetText() );
|
|
if ( nValue)
|
|
return MetricField::ConvertValue( nValue, GetBaseValue(), GetDecimalDigits(), GetUnit(), eOutUnit );
|
|
}
|
|
|
|
return MetricBox::GetValue( eOutUnit );
|
|
}
|
|
|
|
|
|
|
|
sal_Int64 FontSizeBox::GetValue() const
|
|
{
|
|
// implementation not inline, because it is a virtual function
|
|
return GetValue( FUNIT_NONE );
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|