1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
31 // include ---------------------------------------------------------------
32 #include <basegfx/color/bcolor.hxx>
33 #include <basegfx/color/bcolortools.hxx>
35 #include <editeng/borderline.hxx>
36 #include <editeng/itemtype.hxx>
39 using namespace ::com::sun::star::table::BorderLineStyle
;
41 // class SvxBorderLine --------------------------------------------------
45 Color
lcl_compute3DColor( Color aMain
, int nLight
, int nMedium
, int nDark
)
47 basegfx::BColor color
= aMain
.getBColor( );
48 basegfx::BColor hsl
= basegfx::tools::rgb2hsl( color
);
51 if ( hsl
.getZ( ) >= 0.5 )
53 else if ( 0.5 > hsl
.getZ() && hsl
.getZ() >= 0.25 )
58 double L
= hsl
.getZ() * 255.0 + nCoef
;
59 hsl
.setZ( L
/ 255.0 );
60 color
= basegfx::tools::hsl2rgb( hsl
);
62 return Color( color
);
64 } // Anonymous namespace
68 Color
SvxBorderLine::darkColor( Color aMain
)
73 Color
SvxBorderLine::lightColor( Color aMain
)
76 // Divide Luminance by 2
77 basegfx::BColor color
= aMain
.getBColor( );
78 basegfx::BColor hsl
= basegfx::tools::rgb2hsl( color
);
79 hsl
.setZ( hsl
.getZ() * 0.5 );
80 color
= basegfx::tools::hsl2rgb( hsl
);
82 return Color( color
);
86 Color
SvxBorderLine::threeDLightColor( Color aMain
)
88 // These values have been defined in an empirical way
89 return lcl_compute3DColor( aMain
, 3, 40, 83 );
92 Color
SvxBorderLine::threeDDarkColor( Color aMain
)
94 // These values have been defined in an empirical way
95 return lcl_compute3DColor( aMain
, -85, -43, -1 );
98 Color
SvxBorderLine::threeDMediumColor( Color aMain
)
100 // These values have been defined in an empirical way
101 return lcl_compute3DColor( aMain
, -42, -0, 42 );
104 SvxBorderLine::SvxBorderLine( const Color
*pCol
, long nWidth
,
105 SvxBorderStyle nStyle
, bool bUseLeftTop
,
106 Color (*pColorOutFn
)( Color
), Color (*pColorInFn
)( Color
),
107 Color (*pColorGapFn
)( Color
) )
109 , m_bMirrorWidths( false )
110 , m_aWidthImpl( SvxBorderLine::getWidthImpl( nStyle
) )
114 , m_bUseLeftTop( bUseLeftTop
)
115 , m_pColorOutFn( pColorOutFn
)
116 , m_pColorInFn( pColorInFn
)
117 , m_pColorGapFn( pColorGapFn
)
125 ConvertBorderStyleFromWord(int const nWordLineStyle
)
127 switch (nWordLineStyle
)
129 // First the single lines
131 case 2: // thick line
133 // and the unsupported special cases which we map to a single line
148 // then the shading beams which we represent by a double line
152 // then the double lines, for which we have good matches
154 case 10: // Don't have triple so use double
155 case 21: // Don't have double wave: use double instead
159 return THINTHICK_SMALLGAP
;
162 case 13: // Don't have thin thick thin, so use thick thin
163 return THICKTHIN_SMALLGAP
;
166 return THINTHICK_MEDIUMGAP
;
169 case 16: // Don't have thin thick thin, so use thick thin
170 return THICKTHIN_MEDIUMGAP
;
173 return THINTHICK_LARGEGAP
;
176 case 19: // Don't have thin thick thin, so use thick thin
177 return THICKTHIN_LARGEGAP
;
197 static const double THINTHICK_SMALLGAP_line2
= 15.0;
198 static const double THINTHICK_SMALLGAP_gap
= 15.0;
199 static const double THINTHICK_LARGEGAP_line1
= 30.0;
200 static const double THINTHICK_LARGEGAP_line2
= 15.0;
201 static const double THICKTHIN_SMALLGAP_line1
= 15.0;
202 static const double THICKTHIN_SMALLGAP_gap
= 15.0;
203 static const double THICKTHIN_LARGEGAP_line1
= 15.0;
204 static const double THICKTHIN_LARGEGAP_line2
= 30.0;
205 static const double OUTSET_line1
= 15.0;
206 static const double INSET_line2
= 15.0;
209 ConvertBorderWidthFromWord(SvxBorderStyle
const eStyle
, double const fWidth
,
210 int const nWordLineStyle
)
216 switch (nWordLineStyle
)
219 return (fWidth
* 2.0); // thick
221 case 5: // fdo#55526: map 0 hairline width to > 0
222 return (fWidth
> 1.0) ? fWidth
: 1.0;
234 // Display a minimum effective border width of 1pt
236 return (fWidth
> 0 && fWidth
< 20) ? 20 : fWidth
;
244 case THINTHICK_MEDIUMGAP
:
245 case THICKTHIN_MEDIUMGAP
:
251 case THINTHICK_SMALLGAP
:
252 return fWidth
+ THINTHICK_SMALLGAP_line2
+ THINTHICK_SMALLGAP_gap
;
255 case THINTHICK_LARGEGAP
:
256 return fWidth
+ THINTHICK_LARGEGAP_line1
+ THINTHICK_LARGEGAP_line2
;
259 case THICKTHIN_SMALLGAP
:
260 return fWidth
+ THICKTHIN_SMALLGAP_line1
+ THICKTHIN_SMALLGAP_gap
;
263 case THICKTHIN_LARGEGAP
:
264 return fWidth
+ THICKTHIN_LARGEGAP_line1
+ THICKTHIN_LARGEGAP_line2
;
268 return (fWidth
* 2.0) + OUTSET_line1
;
272 return (fWidth
* 2.0) + INSET_line2
;
276 assert(false); // should only be called for known border style
283 ConvertBorderWidthToWord(SvxBorderStyle
const eStyle
, double const fWidth
)
300 case THINTHICK_MEDIUMGAP
:
301 case THICKTHIN_MEDIUMGAP
:
307 case THINTHICK_SMALLGAP
:
308 return fWidth
- THINTHICK_SMALLGAP_line2
- THINTHICK_SMALLGAP_gap
;
311 case THINTHICK_LARGEGAP
:
312 return fWidth
- THINTHICK_LARGEGAP_line1
- THINTHICK_LARGEGAP_line2
;
315 case THICKTHIN_SMALLGAP
:
316 return fWidth
- THICKTHIN_SMALLGAP_line1
- THICKTHIN_SMALLGAP_gap
;
319 case THICKTHIN_LARGEGAP
:
320 return fWidth
- THICKTHIN_LARGEGAP_line1
- THICKTHIN_LARGEGAP_line2
;
324 return (fWidth
- OUTSET_line1
) / 2.0;
328 return (fWidth
- INSET_line2
) / 2.0;
332 assert(false); // should only be called for known border style
338 /** Get the BorderWithImpl object corresponding to the given #nStyle, all the
339 units handled by the resulting object are Twips and the
340 BorderWidthImpl::GetLine1() corresponds to the Outer Line.
342 BorderWidthImpl
SvxBorderLine::getWidthImpl( SvxBorderStyle nStyle
)
344 BorderWidthImpl aImpl
;
350 aImpl
= BorderWidthImpl( 0, 0.0 );
358 aImpl
= BorderWidthImpl( CHANGE_LINE1
, 1.0 );
364 aImpl
= BorderWidthImpl(
365 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
366 // fdo#46112 fdo#38542 fdo#43249:
367 // non-constant witdths must sum to 1
368 1.0/3.0, 1.0/3.0, 1.0/3.0 );
371 case THINTHICK_SMALLGAP
:
372 aImpl
= BorderWidthImpl( CHANGE_LINE1
, 1.0,
373 THINTHICK_SMALLGAP_line2
, THINTHICK_SMALLGAP_gap
);
376 case THINTHICK_MEDIUMGAP
:
377 aImpl
= BorderWidthImpl(
378 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
382 case THINTHICK_LARGEGAP
:
383 aImpl
= BorderWidthImpl( CHANGE_DIST
,
384 THINTHICK_LARGEGAP_line1
, THINTHICK_LARGEGAP_line2
, 1.0 );
387 case THICKTHIN_SMALLGAP
:
388 aImpl
= BorderWidthImpl( CHANGE_LINE2
, THICKTHIN_SMALLGAP_line1
,
389 1.0, THICKTHIN_SMALLGAP_gap
);
392 case THICKTHIN_MEDIUMGAP
:
393 aImpl
= BorderWidthImpl(
394 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
398 case THICKTHIN_LARGEGAP
:
399 aImpl
= BorderWidthImpl( CHANGE_DIST
, THICKTHIN_LARGEGAP_line1
,
400 THICKTHIN_LARGEGAP_line2
, 1.0 );
403 // Engraved / Embossed
405 * Word compat: the lines widths are exactly following this rule, shouldbe:
406 * 0.75pt up to 3pt and then 3pt
411 aImpl
= BorderWidthImpl(
412 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
418 * Word compat: the gap width should be measured relatively to the biggest width for the
422 aImpl
= BorderWidthImpl(
423 CHANGE_LINE2
| CHANGE_DIST
,
424 OUTSET_line1
, 0.5, 0.5 );
428 aImpl
= BorderWidthImpl(
429 CHANGE_LINE1
| CHANGE_DIST
,
430 0.5, INSET_line2
, 0.5 );
437 // -----------------------------------------------------------------------
439 SvxBorderLine::SvxBorderLine( const SvxBorderLine
& r
)
444 // -----------------------------------------------------------------------
446 SvxBorderLine
& SvxBorderLine::operator=( const SvxBorderLine
& r
)
449 m_nWidth
= r
.m_nWidth
;
450 m_aWidthImpl
= r
.m_aWidthImpl
;
451 m_bMirrorWidths
= r
.m_bMirrorWidths
;
454 m_nStyle
= r
.m_nStyle
;
455 m_bUseLeftTop
= r
.m_bUseLeftTop
;
456 m_pColorOutFn
= r
.m_pColorOutFn
;
457 m_pColorInFn
= r
.m_pColorInFn
;
458 m_pColorGapFn
= r
.m_pColorGapFn
;
462 // -----------------------------------------------------------------------
464 void SvxBorderLine::ScaleMetrics( long nMult
, long nDiv
)
470 void SvxBorderLine::GuessLinesWidths( SvxBorderStyle nStyle
, sal_uInt16 nOut
, sal_uInt16 nIn
, sal_uInt16 nDist
)
475 if ( nOut
> 0 && nIn
> 0 )
479 if ( nStyle
== DOUBLE
)
481 static SvxBorderStyle aDoubleStyles
[] =
492 size_t const len
= SAL_N_ELEMENTS(aDoubleStyles
);
494 SvxBorderStyle
nTestStyle(NONE
);
495 for (size_t i
= 0; i
< len
&& nWidth
== 0; ++i
)
497 nTestStyle
= aDoubleStyles
[i
];
498 BorderWidthImpl aWidthImpl
= getWidthImpl( nTestStyle
);
499 nWidth
= aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
502 // If anything matched, then set it
506 SetBorderLineStyle(nStyle
);
511 // fdo#38542: not a known double, default to something custom...
512 SetBorderLineStyle(nStyle
);
513 m_nWidth
= nOut
+ nIn
+ nDist
;
514 if (nOut
+ nIn
+ nDist
)
516 m_aWidthImpl
= BorderWidthImpl(
517 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
518 static_cast<double>(nOut
) / static_cast<double>(m_nWidth
),
519 static_cast<double>(nIn
) / static_cast<double>(m_nWidth
),
520 static_cast<double>(nDist
) / static_cast<double>(m_nWidth
));
526 SetBorderLineStyle(nStyle
);
527 if (nOut
== 0 && nIn
> 0)
529 // If only inner width is given swap inner and outer widths for
530 // single line styles, otherwise GuessWidth() marks this as invalid
531 // and returns a 0 width.
538 ::std::swap( nOut
, nIn
);
544 m_nWidth
= m_aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
548 sal_uInt16
SvxBorderLine::GetOutWidth() const
550 sal_uInt16 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
551 if ( m_bMirrorWidths
)
552 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
556 sal_uInt16
SvxBorderLine::GetInWidth() const
558 sal_uInt16 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
559 if ( m_bMirrorWidths
)
560 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
564 sal_uInt16
SvxBorderLine::GetDistance() const
566 return (sal_uInt16
)Scale( m_aWidthImpl
.GetGap( m_nWidth
), m_nMult
, m_nDiv
);
569 // -----------------------------------------------------------------------
571 sal_Bool
SvxBorderLine::operator==( const SvxBorderLine
& rCmp
) const
573 return ( ( aColor
== rCmp
.aColor
) &&
574 ( m_nWidth
== rCmp
.m_nWidth
) &&
575 ( m_bMirrorWidths
== rCmp
.m_bMirrorWidths
) &&
576 ( m_aWidthImpl
== rCmp
.m_aWidthImpl
) &&
577 ( m_nStyle
== rCmp
.GetBorderLineStyle()) &&
578 ( m_bUseLeftTop
== rCmp
.m_bUseLeftTop
) &&
579 ( m_pColorOutFn
== rCmp
.m_pColorOutFn
) &&
580 ( m_pColorInFn
== rCmp
.m_pColorInFn
) &&
581 ( m_pColorGapFn
== rCmp
.m_pColorGapFn
) );
584 void SvxBorderLine::SetBorderLineStyle( SvxBorderStyle nNew
)
587 m_aWidthImpl
= getWidthImpl( m_nStyle
);
592 m_pColorOutFn
= threeDLightColor
;
593 m_pColorInFn
= threeDDarkColor
;
594 m_pColorGapFn
= threeDMediumColor
;
595 m_bUseLeftTop
= true;
598 m_pColorOutFn
= threeDDarkColor
;
599 m_pColorInFn
= threeDLightColor
;
600 m_pColorGapFn
= threeDMediumColor
;
601 m_bUseLeftTop
= true;
604 m_pColorOutFn
= lightColor
;
605 m_pColorInFn
= darkColor
;
606 m_bUseLeftTop
= true;
607 m_pColorGapFn
= NULL
;
610 m_pColorOutFn
= darkColor
;
611 m_pColorInFn
= lightColor
;
612 m_bUseLeftTop
= true;
613 m_pColorGapFn
= NULL
;
616 m_pColorOutFn
= darkColor
;
617 m_pColorInFn
= darkColor
;
618 m_bUseLeftTop
= false;
619 m_pColorGapFn
= NULL
;
624 Color
SvxBorderLine::GetColorOut( bool bLeftOrTop
) const
626 Color aResult
= aColor
;
628 if ( m_aWidthImpl
.IsDouble() && m_pColorOutFn
!= NULL
)
630 if ( !bLeftOrTop
&& m_bUseLeftTop
)
631 aResult
= (*m_pColorInFn
)( aColor
);
633 aResult
= (*m_pColorOutFn
)( aColor
);
639 Color
SvxBorderLine::GetColorIn( bool bLeftOrTop
) const
641 Color aResult
= aColor
;
643 if ( m_aWidthImpl
.IsDouble() && m_pColorInFn
!= NULL
)
645 if ( !bLeftOrTop
&& m_bUseLeftTop
)
646 aResult
= (*m_pColorOutFn
)( aColor
);
648 aResult
= (*m_pColorInFn
)( aColor
);
654 Color
SvxBorderLine::GetColorGap( ) const
656 Color aResult
= aColor
;
658 if ( m_aWidthImpl
.IsDouble() && m_pColorGapFn
!= NULL
)
660 aResult
= (*m_pColorGapFn
)( aColor
);
666 // -----------------------------------------------------------------------
668 XubString
SvxBorderLine::GetValueString( SfxMapUnit eSrcUnit
,
669 SfxMapUnit eDestUnit
,
670 const IntlWrapper
* pIntl
,
671 sal_Bool bMetricStr
) const
673 static const sal_uInt16 aStyleIds
[] =
679 RID_THINTHICK_SMALLGAP
,
680 RID_THINTHICK_MEDIUMGAP
,
681 RID_THINTHICK_LARGEGAP
,
682 RID_THICKTHIN_SMALLGAP
,
683 RID_THICKTHIN_MEDIUMGAP
,
684 RID_THICKTHIN_LARGEGAP
,
690 sal_uInt16 nResId
= aStyleIds
[m_nStyle
];
692 aStr
+= sal_Unicode('(');
693 aStr
+= ::GetColorString( aColor
);
697 aStr
+= EE_RESSTR(nResId
);
700 String sMetric
= EE_RESSTR(GetMetricId( eDestUnit
));
701 aStr
+= GetMetricText( (long)GetInWidth(), eSrcUnit
, eDestUnit
, pIntl
);
705 aStr
+= GetMetricText( (long)GetOutWidth(), eSrcUnit
, eDestUnit
, pIntl
);
709 aStr
+= GetMetricText( (long)GetDistance(), eSrcUnit
, eDestUnit
, pIntl
);
713 aStr
+= sal_Unicode(')');
717 bool SvxBorderLine::HasPriority( const SvxBorderLine
& rOtherLine
) const
719 const sal_uInt16 nThisSize
= GetOutWidth() + GetDistance() + GetInWidth();
720 const sal_uInt16 nOtherSize
= rOtherLine
.GetOutWidth() + rOtherLine
.GetDistance() + rOtherLine
.GetInWidth();
722 if ( nThisSize
> nOtherSize
)
726 else if ( nThisSize
< nOtherSize
)
730 else if ( rOtherLine
.GetInWidth() && !GetInWidth() )
738 } // namespace editeng
740 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */