/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // include --------------------------------------------------------------- #include #include #include #include // class SvxBorderLine -------------------------------------------------- namespace { Color lcl_compute3DColor( Color aMain, int nLight, int nMedium, int nDark ) { basegfx::BColor color = aMain.getBColor( ); basegfx::BColor hsl = basegfx::tools::rgb2hsl( color ); int nCoef = 0; if ( hsl.getZ( ) >= 0.5 ) nCoef = nLight; else if ( 0.5 > hsl.getZ() && hsl.getZ() >= 0.25 ) nCoef = nMedium; else nCoef = nDark; double L = hsl.getZ() * 255.0 + nCoef; hsl.setZ( L / 255.0 ); color = basegfx::tools::hsl2rgb( hsl ); return Color( color ); } } // Anonymous namespace namespace editeng { Color SvxBorderLine::darkColor( Color aMain ) { return aMain; } Color SvxBorderLine::lightColor( Color aMain ) { // Divide Luminance by 2 basegfx::BColor color = aMain.getBColor( ); basegfx::BColor hsl = basegfx::tools::rgb2hsl( color ); hsl.setZ( hsl.getZ() * 0.5 ); color = basegfx::tools::hsl2rgb( hsl ); return Color( color ); } Color SvxBorderLine::threeDLightColor( Color aMain ) { // These values have been defined in an empirical way return lcl_compute3DColor( aMain, 3, 40, 83 ); } Color SvxBorderLine::threeDDarkColor( Color aMain ) { // These values have been defined in an empirical way return lcl_compute3DColor( aMain, -85, -43, -1 ); } Color SvxBorderLine::threeDMediumColor( Color aMain ) { // These values have been defined in an empirical way return lcl_compute3DColor( aMain, -42, -0, 42 ); } SvxBorderLine::SvxBorderLine( const Color *pCol, long nWidth, SvxBorderStyle nStyle, bool bUseLeftTop, Color (*pColorOutFn)( Color ), Color (*pColorInFn)( Color ), Color (*pColorGapFn)( Color ) ) : m_nWidth( nWidth ) , m_bMirrorWidths( false ) , m_aWidthImpl( SvxBorderLine::getWidthImpl( nStyle ) ) , m_nMult( 1 ) , m_nDiv( 1 ) , m_nStyle( nStyle ) , m_bUseLeftTop( bUseLeftTop ) , m_pColorOutFn( pColorOutFn ) , m_pColorInFn( pColorInFn ) , m_pColorGapFn( pColorGapFn ) { if ( pCol ) aColor = *pCol; } /** Get the BorderWithImpl object corresponding to the given #nStyle, all the units handled by the resulting object are Twips and the BorderWidthImpl::GetLine1() corresponds to the Outer Line. */ BorderWidthImpl SvxBorderLine::getWidthImpl( SvxBorderStyle nStyle ) { BorderWidthImpl aImpl; switch ( nStyle ) { // No line: no width case NO_STYLE: aImpl = BorderWidthImpl( 0, 0.0 ); break; // Single lines case SOLID: case DOTTED: case DASHED: aImpl = BorderWidthImpl( CHANGE_LINE1, 1.0 ); break; // Double lines case DOUBLE: aImpl = BorderWidthImpl( CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST, 1.0, 1.0, 1.0 ); break; case THINTHICK_SMALLGAP: aImpl = BorderWidthImpl( CHANGE_LINE1, 1.0, 15.0, 15.0 ); break; case THINTHICK_MEDIUMGAP: aImpl = BorderWidthImpl( CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST, 1.0, 0.5, 0.5 ); break; case THINTHICK_LARGEGAP: aImpl = BorderWidthImpl( CHANGE_DIST, 30.0, 15.0, 1.0 ); break; case THICKTHIN_SMALLGAP: aImpl = BorderWidthImpl( CHANGE_LINE2, 15.0, 1.0, 15.0 ); break; case THICKTHIN_MEDIUMGAP: aImpl = BorderWidthImpl( CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST, 0.5, 1.0, 0.5 ); break; case THICKTHIN_LARGEGAP: aImpl = BorderWidthImpl( CHANGE_DIST, 15.0, 30.0, 1.0 ); break; // Engraved / Embossed /* * Word compat: the lines widths are exactly following this rule, shouldbe: * 0.75pt up to 3pt and then 3pt */ case EMBOSSED: case ENGRAVED: aImpl = BorderWidthImpl( CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST, 0.5, 0.5, 1.0 ); break; // Inset / Outset /* * Word compat: the gap width should be measured relatively to the biggest width for the * row or column. */ case OUTSET: aImpl = BorderWidthImpl( CHANGE_LINE2 | CHANGE_DIST, 15.0, 1.0, 1.0 ); break; case INSET: aImpl = BorderWidthImpl( CHANGE_LINE1 | CHANGE_DIST, 1.0, 15.0, 1.0 ); break; } return aImpl; } // ----------------------------------------------------------------------- SvxBorderLine::SvxBorderLine( const SvxBorderLine& r ) { *this = r; } // ----------------------------------------------------------------------- SvxBorderLine& SvxBorderLine::operator=( const SvxBorderLine& r ) { aColor = r.aColor; m_nWidth = r.m_nWidth; m_aWidthImpl = r.m_aWidthImpl; m_bMirrorWidths = r.m_bMirrorWidths; m_nMult = r.m_nMult; m_nDiv = r.m_nDiv; m_nStyle = r.m_nStyle; m_bUseLeftTop = r.m_bUseLeftTop; m_pColorOutFn = r.m_pColorOutFn; m_pColorInFn = r.m_pColorInFn; m_pColorGapFn = r.m_pColorGapFn; return *this; } // ----------------------------------------------------------------------- void SvxBorderLine::ScaleMetrics( long nMult, long nDiv ) { m_nMult = nMult; m_nDiv = nDiv; } void SvxBorderLine::GuessLinesWidths( SvxBorderStyle nStyle, sal_uInt16 nOut, sal_uInt16 nIn, sal_uInt16 nDist ) { if ( nStyle == NO_STYLE ) { nStyle = SOLID; if ( nOut > 0 && nIn > 0 ) nStyle = DOUBLE; } if ( nStyle == DOUBLE ) { static SvxBorderStyle aDoubleStyles[] = { DOUBLE, THINTHICK_SMALLGAP, THINTHICK_MEDIUMGAP, THINTHICK_LARGEGAP, THICKTHIN_SMALLGAP, THICKTHIN_MEDIUMGAP, THICKTHIN_LARGEGAP }; size_t const len = SAL_N_ELEMENTS(aDoubleStyles); long nWidth = 0; SvxBorderStyle nTestStyle(NO_STYLE); for (size_t i = 0; i < len && nWidth == 0; ++i) { nTestStyle = aDoubleStyles[i]; BorderWidthImpl aWidthImpl = getWidthImpl( nTestStyle ); nWidth = aWidthImpl.GuessWidth( nOut, nIn, nDist ); } // If anything matched, then set it if ( nWidth > 0 ) { nStyle = nTestStyle; SetStyle( nStyle ); m_nWidth = nWidth; } else { // fdo#38542: not a known double, default to something custom... SetStyle( nStyle ); m_nWidth = nOut + nIn + nDist; if (nOut + nIn + nDist) { m_aWidthImpl = BorderWidthImpl( CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST, static_cast(nOut ) / static_cast(m_nWidth), static_cast(nIn ) / static_cast(m_nWidth), static_cast(nDist) / static_cast(m_nWidth)); } } } else { SetStyle( nStyle ); if (nOut == 0 && nIn > 0) { // If only inner width is given swap inner and outer widths for // single line styles, otherwise GuessWidth() marks this as invalid // and returns a 0 width. switch (nStyle) { case SOLID: case DOTTED: case DASHED: ::std::swap( nOut, nIn); break; default: ; // nothing } } m_nWidth = m_aWidthImpl.GuessWidth( nOut, nIn, nDist ); } } sal_uInt16 SvxBorderLine::GetOutWidth() const { sal_uInt16 nOut = (sal_uInt16)Scale( m_aWidthImpl.GetLine1( m_nWidth ), m_nMult, m_nDiv ); if ( m_bMirrorWidths ) nOut = (sal_uInt16)Scale( m_aWidthImpl.GetLine2( m_nWidth ), m_nMult, m_nDiv ); return nOut; } sal_uInt16 SvxBorderLine::GetInWidth() const { sal_uInt16 nIn = (sal_uInt16)Scale( m_aWidthImpl.GetLine2( m_nWidth ), m_nMult, m_nDiv ); if ( m_bMirrorWidths ) nIn = (sal_uInt16)Scale( m_aWidthImpl.GetLine1( m_nWidth ), m_nMult, m_nDiv ); return nIn; } sal_uInt16 SvxBorderLine::GetDistance() const { return (sal_uInt16)Scale( m_aWidthImpl.GetGap( m_nWidth ), m_nMult, m_nDiv ); } // ----------------------------------------------------------------------- sal_Bool SvxBorderLine::operator==( const SvxBorderLine& rCmp ) const { return ( ( aColor == rCmp.aColor ) && ( m_nWidth == rCmp.m_nWidth ) && ( m_bMirrorWidths == rCmp.m_bMirrorWidths ) && ( m_aWidthImpl == rCmp.m_aWidthImpl ) && ( m_nStyle == rCmp.GetStyle() ) && ( m_bUseLeftTop == rCmp.m_bUseLeftTop ) && ( m_pColorOutFn == rCmp.m_pColorOutFn ) && ( m_pColorInFn == rCmp.m_pColorInFn ) && ( m_pColorGapFn == rCmp.m_pColorGapFn ) ); } void SvxBorderLine::SetStyle( SvxBorderStyle nNew ) { m_nStyle = nNew; m_aWidthImpl = getWidthImpl( m_nStyle ); switch ( nNew ) { case EMBOSSED: m_pColorOutFn = threeDLightColor; m_pColorInFn = threeDDarkColor; m_pColorGapFn = threeDMediumColor; m_bUseLeftTop = true; break; case ENGRAVED: m_pColorOutFn = threeDDarkColor; m_pColorInFn = threeDLightColor; m_pColorGapFn = threeDMediumColor; m_bUseLeftTop = true; break; case OUTSET: m_pColorOutFn = lightColor; m_pColorInFn = darkColor; m_bUseLeftTop = true; m_pColorGapFn = NULL; break; case INSET: m_pColorOutFn = darkColor; m_pColorInFn = lightColor; m_bUseLeftTop = true; m_pColorGapFn = NULL; break; default: m_pColorOutFn = darkColor; m_pColorInFn = darkColor; m_bUseLeftTop = false; m_pColorGapFn = NULL; break; } } Color SvxBorderLine::GetColorOut( bool bLeftOrTop ) const { Color aResult = aColor; if ( m_aWidthImpl.IsDouble() && m_pColorOutFn != NULL ) { if ( !bLeftOrTop && m_bUseLeftTop ) aResult = (*m_pColorInFn)( aColor ); else aResult = (*m_pColorOutFn)( aColor ); } return aResult; } Color SvxBorderLine::GetColorIn( bool bLeftOrTop ) const { Color aResult = aColor; if ( m_aWidthImpl.IsDouble() && m_pColorInFn != NULL ) { if ( !bLeftOrTop && m_bUseLeftTop ) aResult = (*m_pColorOutFn)( aColor ); else aResult = (*m_pColorInFn)( aColor ); } return aResult; } Color SvxBorderLine::GetColorGap( ) const { Color aResult = aColor; if ( m_aWidthImpl.IsDouble() && m_pColorGapFn != NULL ) { aResult = (*m_pColorGapFn)( aColor ); } return aResult; } // ----------------------------------------------------------------------- XubString SvxBorderLine::GetValueString( SfxMapUnit eSrcUnit, SfxMapUnit eDestUnit, const IntlWrapper* pIntl, sal_Bool bMetricStr) const { static const sal_uInt16 aStyleIds[] = { RID_SOLID, RID_DOTTED, RID_DASHED, RID_DOUBLE, RID_THINTHICK_SMALLGAP, RID_THINTHICK_MEDIUMGAP, RID_THINTHICK_LARGEGAP, RID_THICKTHIN_SMALLGAP, RID_THICKTHIN_MEDIUMGAP, RID_THICKTHIN_LARGEGAP, RID_EMBOSSED, RID_ENGRAVED, RID_OUTSET, RID_INSET }; sal_uInt16 nResId = aStyleIds[m_nStyle]; String aStr; aStr += sal_Unicode('('); aStr += ::GetColorString( aColor ); aStr += cpDelim; if ( nResId ) aStr += EE_RESSTR(nResId); else { String sMetric = EE_RESSTR(GetMetricId( eDestUnit )); aStr += GetMetricText( (long)GetInWidth(), eSrcUnit, eDestUnit, pIntl ); if ( bMetricStr ) aStr += sMetric; aStr += cpDelim; aStr += GetMetricText( (long)GetOutWidth(), eSrcUnit, eDestUnit, pIntl ); if ( bMetricStr ) aStr += sMetric; aStr += cpDelim; aStr += GetMetricText( (long)GetDistance(), eSrcUnit, eDestUnit, pIntl ); if ( bMetricStr ) aStr += sMetric; } aStr += sal_Unicode(')'); return aStr; } bool SvxBorderLine::HasPriority( const SvxBorderLine& rOtherLine ) const { const sal_uInt16 nThisSize = GetOutWidth() + GetDistance() + GetInWidth(); const sal_uInt16 nOtherSize = rOtherLine.GetOutWidth() + rOtherLine.GetDistance() + rOtherLine.GetInWidth(); if ( nThisSize > nOtherSize ) { return true; } else if ( nThisSize < nOtherSize ) { return false; } else if ( rOtherLine.GetInWidth() && !GetInWidth() ) { return true; } return false; } } // namespace editeng /* vim:set shiftwidth=4 softtabstop=4 expandtab: */