1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <basegfx/color/bcolor.hxx>
21 #include <basegfx/color/bcolortools.hxx>
23 #include <editeng/borderline.hxx>
24 #include <editeng/itemtype.hxx>
27 using namespace ::com::sun::star::table::BorderLineStyle
;
29 // class SvxBorderLine --------------------------------------------------
33 Color
lcl_compute3DColor( Color aMain
, int nLight
, int nMedium
, int nDark
)
35 basegfx::BColor color
= aMain
.getBColor( );
36 basegfx::BColor hsl
= basegfx::tools::rgb2hsl( color
);
39 if ( hsl
.getZ( ) >= 0.5 )
41 else if ( 0.5 > hsl
.getZ() && hsl
.getZ() >= 0.25 )
46 double L
= hsl
.getZ() * 255.0 + nCoef
;
47 hsl
.setZ( L
/ 255.0 );
48 color
= basegfx::tools::hsl2rgb( hsl
);
50 return Color( color
);
52 } // Anonymous namespace
56 Color
SvxBorderLine::darkColor( Color aMain
)
61 Color
SvxBorderLine::lightColor( Color aMain
)
64 // Divide Luminance by 2
65 basegfx::BColor color
= aMain
.getBColor( );
66 basegfx::BColor hsl
= basegfx::tools::rgb2hsl( color
);
67 hsl
.setZ( hsl
.getZ() * 0.5 );
68 color
= basegfx::tools::hsl2rgb( hsl
);
70 return Color( color
);
74 Color
SvxBorderLine::threeDLightColor( Color aMain
)
76 // These values have been defined in an empirical way
77 return lcl_compute3DColor( aMain
, 3, 40, 83 );
80 Color
SvxBorderLine::threeDDarkColor( Color aMain
)
82 // These values have been defined in an empirical way
83 return lcl_compute3DColor( aMain
, -85, -43, -1 );
86 Color
SvxBorderLine::threeDMediumColor( Color aMain
)
88 // These values have been defined in an empirical way
89 return lcl_compute3DColor( aMain
, -42, -0, 42 );
92 SvxBorderLine::SvxBorderLine( const Color
*pCol
, long nWidth
,
93 SvxBorderStyle nStyle
, bool bUseLeftTop
,
94 Color (*pColorOutFn
)( Color
), Color (*pColorInFn
)( Color
),
95 Color (*pColorGapFn
)( Color
) )
97 , m_bMirrorWidths( false )
98 , m_aWidthImpl( SvxBorderLine::getWidthImpl( nStyle
) )
102 , m_bUseLeftTop( bUseLeftTop
)
103 , m_pColorOutFn( pColorOutFn
)
104 , m_pColorInFn( pColorInFn
)
105 , m_pColorGapFn( pColorGapFn
)
113 ConvertBorderStyleFromWord(int const nWordLineStyle
)
115 switch (nWordLineStyle
)
117 // First the single lines
119 case 2: // thick line
121 // and the unsupported special cases which we map to a single line
132 // then the shading beams which we represent by a double line
135 // then the double lines, for which we have good matches
137 case 10: // Don't have triple so use double
138 case 21: // Don't have double wave: use double instead
141 return THINTHICK_SMALLGAP
;
143 case 13: // Don't have thin thick thin, so use thick thin
144 return THICKTHIN_SMALLGAP
;
146 return THINTHICK_MEDIUMGAP
;
148 case 16: // Don't have thin thick thin, so use thick thin
149 return THICKTHIN_MEDIUMGAP
;
151 return THINTHICK_LARGEGAP
;
153 case 19: // Don't have thin thick thin, so use thick thin
154 return THICKTHIN_LARGEGAP
;
168 static const double THINTHICK_SMALLGAP_line2
= 15.0;
169 static const double THINTHICK_SMALLGAP_gap
= 15.0;
170 static const double THINTHICK_LARGEGAP_line1
= 30.0;
171 static const double THINTHICK_LARGEGAP_line2
= 15.0;
172 static const double THICKTHIN_SMALLGAP_line1
= 15.0;
173 static const double THICKTHIN_SMALLGAP_gap
= 15.0;
174 static const double THICKTHIN_LARGEGAP_line1
= 15.0;
175 static const double THICKTHIN_LARGEGAP_line2
= 30.0;
176 static const double OUTSET_line1
= 15.0;
177 static const double INSET_line2
= 15.0;
180 ConvertBorderWidthFromWord(SvxBorderStyle
const eStyle
, double const fWidth
,
181 int const nWordLineStyle
)
187 switch (nWordLineStyle
)
190 return (fWidth
* 2.0); // thick
191 case 5: // fdo#55526: map 0 hairline width to > 0
192 return (fWidth
> 1.0) ? fWidth
: 1.0;
202 // Display a minimum effective border width of 1pt
204 return (fWidth
> 0 && fWidth
< 20) ? 20 : fWidth
;
210 case THINTHICK_MEDIUMGAP
:
211 case THICKTHIN_MEDIUMGAP
:
216 case THINTHICK_SMALLGAP
:
217 return fWidth
+ THINTHICK_SMALLGAP_line2
+ THINTHICK_SMALLGAP_gap
;
219 case THINTHICK_LARGEGAP
:
220 return fWidth
+ THINTHICK_LARGEGAP_line1
+ THINTHICK_LARGEGAP_line2
;
222 case THICKTHIN_SMALLGAP
:
223 return fWidth
+ THICKTHIN_SMALLGAP_line1
+ THICKTHIN_SMALLGAP_gap
;
225 case THICKTHIN_LARGEGAP
:
226 return fWidth
+ THICKTHIN_LARGEGAP_line1
+ THICKTHIN_LARGEGAP_line2
;
229 return (fWidth
* 2.0) + OUTSET_line1
;
232 return (fWidth
* 2.0) + INSET_line2
;
235 assert(false); // should only be called for known border style
241 ConvertBorderWidthToWord(SvxBorderStyle
const eStyle
, double const fWidth
)
256 case THINTHICK_MEDIUMGAP
:
257 case THICKTHIN_MEDIUMGAP
:
262 case THINTHICK_SMALLGAP
:
263 return fWidth
- THINTHICK_SMALLGAP_line2
- THINTHICK_SMALLGAP_gap
;
265 case THINTHICK_LARGEGAP
:
266 return fWidth
- THINTHICK_LARGEGAP_line1
- THINTHICK_LARGEGAP_line2
;
268 case THICKTHIN_SMALLGAP
:
269 return fWidth
- THICKTHIN_SMALLGAP_line1
- THICKTHIN_SMALLGAP_gap
;
271 case THICKTHIN_LARGEGAP
:
272 return fWidth
- THICKTHIN_LARGEGAP_line1
- THICKTHIN_LARGEGAP_line2
;
275 return (fWidth
- OUTSET_line1
) / 2.0;
278 return (fWidth
- INSET_line2
) / 2.0;
281 assert(false); // should only be called for known border style
286 /** Get the BorderWithImpl object corresponding to the given #nStyle, all the
287 units handled by the resulting object are Twips and the
288 BorderWidthImpl::GetLine1() corresponds to the Outer Line.
290 BorderWidthImpl
SvxBorderLine::getWidthImpl( SvxBorderStyle nStyle
)
292 BorderWidthImpl aImpl
;
298 aImpl
= BorderWidthImpl( 0, 0.0 );
306 aImpl
= BorderWidthImpl( CHANGE_LINE1
, 1.0 );
312 aImpl
= BorderWidthImpl(
313 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
314 // fdo#46112 fdo#38542 fdo#43249:
315 // non-constant witdths must sum to 1
316 1.0/3.0, 1.0/3.0, 1.0/3.0 );
320 aImpl
= BorderWidthImpl(CHANGE_DIST
, 10.0, 10.0, 1.0);
323 case THINTHICK_SMALLGAP
:
324 aImpl
= BorderWidthImpl( CHANGE_LINE1
, 1.0,
325 THINTHICK_SMALLGAP_line2
, THINTHICK_SMALLGAP_gap
);
328 case THINTHICK_MEDIUMGAP
:
329 aImpl
= BorderWidthImpl(
330 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
334 case THINTHICK_LARGEGAP
:
335 aImpl
= BorderWidthImpl( CHANGE_DIST
,
336 THINTHICK_LARGEGAP_line1
, THINTHICK_LARGEGAP_line2
, 1.0 );
339 case THICKTHIN_SMALLGAP
:
340 aImpl
= BorderWidthImpl( CHANGE_LINE2
, THICKTHIN_SMALLGAP_line1
,
341 1.0, THICKTHIN_SMALLGAP_gap
);
344 case THICKTHIN_MEDIUMGAP
:
345 aImpl
= BorderWidthImpl(
346 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
350 case THICKTHIN_LARGEGAP
:
351 aImpl
= BorderWidthImpl( CHANGE_DIST
, THICKTHIN_LARGEGAP_line1
,
352 THICKTHIN_LARGEGAP_line2
, 1.0 );
355 // Engraved / Embossed
357 * Word compat: the lines widths are exactly following this rule, shouldbe:
358 * 0.75pt up to 3pt and then 3pt
363 aImpl
= BorderWidthImpl(
364 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
370 * Word compat: the gap width should be measured relatively to the biggest width for the
374 aImpl
= BorderWidthImpl(
375 CHANGE_LINE2
| CHANGE_DIST
,
376 OUTSET_line1
, 0.5, 0.5 );
380 aImpl
= BorderWidthImpl(
381 CHANGE_LINE1
| CHANGE_DIST
,
382 0.5, INSET_line2
, 0.5 );
389 // -----------------------------------------------------------------------
391 SvxBorderLine::SvxBorderLine( const SvxBorderLine
& r
)
396 // -----------------------------------------------------------------------
398 SvxBorderLine
& SvxBorderLine::operator=( const SvxBorderLine
& r
)
401 m_nWidth
= r
.m_nWidth
;
402 m_aWidthImpl
= r
.m_aWidthImpl
;
403 m_bMirrorWidths
= r
.m_bMirrorWidths
;
406 m_nStyle
= r
.m_nStyle
;
407 m_bUseLeftTop
= r
.m_bUseLeftTop
;
408 m_pColorOutFn
= r
.m_pColorOutFn
;
409 m_pColorInFn
= r
.m_pColorInFn
;
410 m_pColorGapFn
= r
.m_pColorGapFn
;
414 // -----------------------------------------------------------------------
416 void SvxBorderLine::ScaleMetrics( long nMult
, long nDiv
)
422 void SvxBorderLine::GuessLinesWidths( SvxBorderStyle nStyle
, sal_uInt16 nOut
, sal_uInt16 nIn
, sal_uInt16 nDist
)
427 if ( nOut
> 0 && nIn
> 0 )
431 if ( nStyle
== DOUBLE
)
433 static SvxBorderStyle aDoubleStyles
[] =
445 size_t const len
= SAL_N_ELEMENTS(aDoubleStyles
);
447 SvxBorderStyle
nTestStyle(NONE
);
448 for (size_t i
= 0; i
< len
&& nWidth
== 0; ++i
)
450 nTestStyle
= aDoubleStyles
[i
];
451 BorderWidthImpl aWidthImpl
= getWidthImpl( nTestStyle
);
452 nWidth
= aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
455 // If anything matched, then set it
459 SetBorderLineStyle(nStyle
);
464 // fdo#38542: not a known double, default to something custom...
465 SetBorderLineStyle(nStyle
);
466 m_nWidth
= nOut
+ nIn
+ nDist
;
467 if (nOut
+ nIn
+ nDist
)
469 m_aWidthImpl
= BorderWidthImpl(
470 CHANGE_LINE1
| CHANGE_LINE2
| CHANGE_DIST
,
471 static_cast<double>(nOut
) / static_cast<double>(m_nWidth
),
472 static_cast<double>(nIn
) / static_cast<double>(m_nWidth
),
473 static_cast<double>(nDist
) / static_cast<double>(m_nWidth
));
479 SetBorderLineStyle(nStyle
);
480 if (nOut
== 0 && nIn
> 0)
482 // If only inner width is given swap inner and outer widths for
483 // single line styles, otherwise GuessWidth() marks this as invalid
484 // and returns a 0 width.
491 ::std::swap( nOut
, nIn
);
497 m_nWidth
= m_aWidthImpl
.GuessWidth( nOut
, nIn
, nDist
);
501 sal_uInt16
SvxBorderLine::GetOutWidth() const
503 sal_uInt16 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
504 if ( m_bMirrorWidths
)
505 nOut
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
509 sal_uInt16
SvxBorderLine::GetInWidth() const
511 sal_uInt16 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine2( m_nWidth
), m_nMult
, m_nDiv
);
512 if ( m_bMirrorWidths
)
513 nIn
= (sal_uInt16
)Scale( m_aWidthImpl
.GetLine1( m_nWidth
), m_nMult
, m_nDiv
);
517 sal_uInt16
SvxBorderLine::GetDistance() const
519 return (sal_uInt16
)Scale( m_aWidthImpl
.GetGap( m_nWidth
), m_nMult
, m_nDiv
);
522 // -----------------------------------------------------------------------
524 sal_Bool
SvxBorderLine::operator==( const SvxBorderLine
& rCmp
) const
526 return ( ( aColor
== rCmp
.aColor
) &&
527 ( m_nWidth
== rCmp
.m_nWidth
) &&
528 ( m_bMirrorWidths
== rCmp
.m_bMirrorWidths
) &&
529 ( m_aWidthImpl
== rCmp
.m_aWidthImpl
) &&
530 ( m_nStyle
== rCmp
.GetBorderLineStyle()) &&
531 ( m_bUseLeftTop
== rCmp
.m_bUseLeftTop
) &&
532 ( m_pColorOutFn
== rCmp
.m_pColorOutFn
) &&
533 ( m_pColorInFn
== rCmp
.m_pColorInFn
) &&
534 ( m_pColorGapFn
== rCmp
.m_pColorGapFn
) );
537 void SvxBorderLine::SetBorderLineStyle( SvxBorderStyle nNew
)
540 m_aWidthImpl
= getWidthImpl( m_nStyle
);
545 m_pColorOutFn
= threeDLightColor
;
546 m_pColorInFn
= threeDDarkColor
;
547 m_pColorGapFn
= threeDMediumColor
;
548 m_bUseLeftTop
= true;
551 m_pColorOutFn
= threeDDarkColor
;
552 m_pColorInFn
= threeDLightColor
;
553 m_pColorGapFn
= threeDMediumColor
;
554 m_bUseLeftTop
= true;
557 m_pColorOutFn
= lightColor
;
558 m_pColorInFn
= darkColor
;
559 m_bUseLeftTop
= true;
560 m_pColorGapFn
= NULL
;
563 m_pColorOutFn
= darkColor
;
564 m_pColorInFn
= lightColor
;
565 m_bUseLeftTop
= true;
566 m_pColorGapFn
= NULL
;
569 m_pColorOutFn
= darkColor
;
570 m_pColorInFn
= darkColor
;
571 m_bUseLeftTop
= false;
572 m_pColorGapFn
= NULL
;
577 Color
SvxBorderLine::GetColorOut( bool bLeftOrTop
) const
579 Color aResult
= aColor
;
581 if ( m_aWidthImpl
.IsDouble() && m_pColorOutFn
!= NULL
)
583 if ( !bLeftOrTop
&& m_bUseLeftTop
)
584 aResult
= (*m_pColorInFn
)( aColor
);
586 aResult
= (*m_pColorOutFn
)( aColor
);
592 Color
SvxBorderLine::GetColorIn( bool bLeftOrTop
) const
594 Color aResult
= aColor
;
596 if ( m_aWidthImpl
.IsDouble() && m_pColorInFn
!= NULL
)
598 if ( !bLeftOrTop
&& m_bUseLeftTop
)
599 aResult
= (*m_pColorOutFn
)( aColor
);
601 aResult
= (*m_pColorInFn
)( aColor
);
607 Color
SvxBorderLine::GetColorGap( ) const
609 Color aResult
= aColor
;
611 if ( m_aWidthImpl
.IsDouble() && m_pColorGapFn
!= NULL
)
613 aResult
= (*m_pColorGapFn
)( aColor
);
619 // -----------------------------------------------------------------------
621 XubString
SvxBorderLine::GetValueString( SfxMapUnit eSrcUnit
,
622 SfxMapUnit eDestUnit
,
623 const IntlWrapper
* pIntl
,
624 sal_Bool bMetricStr
) const
626 static const sal_uInt16 aStyleIds
[] =
632 RID_THINTHICK_SMALLGAP
,
633 RID_THINTHICK_MEDIUMGAP
,
634 RID_THINTHICK_LARGEGAP
,
635 RID_THICKTHIN_SMALLGAP
,
636 RID_THICKTHIN_MEDIUMGAP
,
637 RID_THICKTHIN_LARGEGAP
,
643 sal_uInt16 nResId
= aStyleIds
[m_nStyle
];
645 aStr
+= sal_Unicode('(');
646 aStr
+= ::GetColorString( aColor
);
650 aStr
+= EE_RESSTR(nResId
);
653 String sMetric
= EE_RESSTR(GetMetricId( eDestUnit
));
654 aStr
+= GetMetricText( (long)GetInWidth(), eSrcUnit
, eDestUnit
, pIntl
);
658 aStr
+= GetMetricText( (long)GetOutWidth(), eSrcUnit
, eDestUnit
, pIntl
);
662 aStr
+= GetMetricText( (long)GetDistance(), eSrcUnit
, eDestUnit
, pIntl
);
666 aStr
+= sal_Unicode(')');
670 bool SvxBorderLine::HasPriority( const SvxBorderLine
& rOtherLine
) const
672 const sal_uInt16 nThisSize
= GetOutWidth() + GetDistance() + GetInWidth();
673 const sal_uInt16 nOtherSize
= rOtherLine
.GetOutWidth() + rOtherLine
.GetDistance() + rOtherLine
.GetInWidth();
675 if ( nThisSize
> nOtherSize
)
679 else if ( nThisSize
< nOtherSize
)
683 else if ( rOtherLine
.GetInWidth() && !GetInWidth() )
691 bool operator!=( const SvxBorderLine
& rLeft
, const SvxBorderLine
& rRight
)
693 return !(rLeft
== rRight
);
696 } // namespace editeng
698 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */