Bump for 3.6-28
[LibreOffice.git] / editeng / source / items / borderline.cxx
blob0ce62a7d4c622b296c7b7bf2a0e6de6ca1f47c88
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 --------------------------------------------------
43 namespace {
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 );
50 int nCoef = 0;
51 if ( hsl.getZ( ) >= 0.5 )
52 nCoef = nLight;
53 else if ( 0.5 > hsl.getZ() && hsl.getZ() >= 0.25 )
54 nCoef = nMedium;
55 else
56 nCoef = nDark;
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
66 namespace editeng {
68 Color SvxBorderLine::darkColor( Color aMain )
70 return 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 ) )
108 : m_nWidth( nWidth )
109 , m_bMirrorWidths( false )
110 , m_aWidthImpl( SvxBorderLine::getWidthImpl( nStyle ) )
111 , m_nMult( 1 )
112 , m_nDiv( 1 )
113 , m_nStyle( nStyle )
114 , m_bUseLeftTop( bUseLeftTop )
115 , m_pColorOutFn( pColorOutFn )
116 , m_pColorInFn( pColorInFn )
117 , m_pColorGapFn( pColorGapFn )
119 if ( pCol )
120 aColor = *pCol;
124 SvxBorderStyle
125 ConvertBorderStyleFromWord(int const nWordLineStyle)
127 switch (nWordLineStyle)
129 // First the single lines
130 case 1:
131 case 2: // thick line
132 case 5: // hairline
133 // and the unsupported special cases which we map to a single line
134 case 8:
135 case 9:
136 case 20:
137 return SOLID;
138 break;
139 case 6:
140 return DOTTED;
141 break;
142 case 7:
143 return DASHED;
144 break;
145 case 22:
146 return FINE_DASHED;
147 break;
148 // then the shading beams which we represent by a double line
149 case 23:
150 return DOUBLE;
151 break;
152 // then the double lines, for which we have good matches
153 case 3:
154 case 10: // Don't have triple so use double
155 case 21: // Don't have double wave: use double instead
156 return DOUBLE;
157 break;
158 case 11:
159 return THINTHICK_SMALLGAP;
160 break;
161 case 12:
162 case 13: // Don't have thin thick thin, so use thick thin
163 return THICKTHIN_SMALLGAP;
164 break;
165 case 14:
166 return THINTHICK_MEDIUMGAP;
167 break;
168 case 15:
169 case 16: // Don't have thin thick thin, so use thick thin
170 return THICKTHIN_MEDIUMGAP;
171 break;
172 case 17:
173 return THINTHICK_LARGEGAP;
174 break;
175 case 18:
176 case 19: // Don't have thin thick thin, so use thick thin
177 return THICKTHIN_LARGEGAP;
178 break;
179 case 24:
180 return EMBOSSED;
181 break;
182 case 25:
183 return ENGRAVED;
184 break;
185 case 26:
186 return OUTSET;
187 break;
188 case 27:
189 return INSET;
190 break;
191 default:
192 return NONE;
193 break;
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;
208 double
209 ConvertBorderWidthFromWord(SvxBorderStyle const eStyle, double const fWidth,
210 int const nWordLineStyle)
212 switch (eStyle)
214 // Single lines
215 case SOLID:
216 switch (nWordLineStyle)
218 case 2:
219 return (fWidth * 2.0); // thick
220 break;
221 case 5: // fdo#55526: map 0 hairline width to > 0
222 return (fWidth > 1.0) ? fWidth : 1.0;
223 break;
224 default:
225 return fWidth;
226 break;
228 break;
230 case DOTTED:
231 case DASHED:
232 return fWidth;
234 // Display a minimum effective border width of 1pt
235 case FINE_DASHED:
236 return (fWidth > 0 && fWidth < 20) ? 20 : fWidth;
237 break;
239 // Double lines
240 case DOUBLE:
241 return fWidth * 3.0;
242 break;
244 case THINTHICK_MEDIUMGAP:
245 case THICKTHIN_MEDIUMGAP:
246 case EMBOSSED:
247 case ENGRAVED:
248 return fWidth * 2.0;
249 break;
251 case THINTHICK_SMALLGAP:
252 return fWidth + THINTHICK_SMALLGAP_line2 + THINTHICK_SMALLGAP_gap;
253 break;
255 case THINTHICK_LARGEGAP:
256 return fWidth + THINTHICK_LARGEGAP_line1 + THINTHICK_LARGEGAP_line2;
257 break;
259 case THICKTHIN_SMALLGAP:
260 return fWidth + THICKTHIN_SMALLGAP_line1 + THICKTHIN_SMALLGAP_gap;
261 break;
263 case THICKTHIN_LARGEGAP:
264 return fWidth + THICKTHIN_LARGEGAP_line1 + THICKTHIN_LARGEGAP_line2;
265 break;
267 case OUTSET:
268 return (fWidth * 2.0) + OUTSET_line1;
269 break;
271 case INSET:
272 return (fWidth * 2.0) + INSET_line2;
273 break;
275 default:
276 assert(false); // should only be called for known border style
277 return 0;
278 break;
282 double
283 ConvertBorderWidthToWord(SvxBorderStyle const eStyle, double const fWidth)
285 switch (eStyle)
287 // Single lines
288 case SOLID:
289 case DOTTED:
290 case DASHED:
291 case FINE_DASHED:
292 return fWidth;
293 break;
295 // Double lines
296 case DOUBLE:
297 return fWidth / 3.0;
298 break;
300 case THINTHICK_MEDIUMGAP:
301 case THICKTHIN_MEDIUMGAP:
302 case EMBOSSED:
303 case ENGRAVED:
304 return fWidth / 2.0;
305 break;
307 case THINTHICK_SMALLGAP:
308 return fWidth - THINTHICK_SMALLGAP_line2 - THINTHICK_SMALLGAP_gap;
309 break;
311 case THINTHICK_LARGEGAP:
312 return fWidth - THINTHICK_LARGEGAP_line1 - THINTHICK_LARGEGAP_line2;
313 break;
315 case THICKTHIN_SMALLGAP:
316 return fWidth - THICKTHIN_SMALLGAP_line1 - THICKTHIN_SMALLGAP_gap;
317 break;
319 case THICKTHIN_LARGEGAP:
320 return fWidth - THICKTHIN_LARGEGAP_line1 - THICKTHIN_LARGEGAP_line2;
321 break;
323 case OUTSET:
324 return (fWidth - OUTSET_line1) / 2.0;
325 break;
327 case INSET:
328 return (fWidth - INSET_line2) / 2.0;
329 break;
331 default:
332 assert(false); // should only be called for known border style
333 return 0;
334 break;
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;
346 switch ( nStyle )
348 // No line: no width
349 case NONE:
350 aImpl = BorderWidthImpl( 0, 0.0 );
351 break;
353 // Single lines
354 case SOLID:
355 case DOTTED:
356 case DASHED:
357 case FINE_DASHED:
358 aImpl = BorderWidthImpl( CHANGE_LINE1, 1.0 );
359 break;
361 // Double lines
363 case DOUBLE:
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 );
369 break;
371 case THINTHICK_SMALLGAP:
372 aImpl = BorderWidthImpl( CHANGE_LINE1, 1.0,
373 THINTHICK_SMALLGAP_line2, THINTHICK_SMALLGAP_gap );
374 break;
376 case THINTHICK_MEDIUMGAP:
377 aImpl = BorderWidthImpl(
378 CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST,
379 0.5, 0.25, 0.25 );
380 break;
382 case THINTHICK_LARGEGAP:
383 aImpl = BorderWidthImpl( CHANGE_DIST,
384 THINTHICK_LARGEGAP_line1, THINTHICK_LARGEGAP_line2, 1.0 );
385 break;
387 case THICKTHIN_SMALLGAP:
388 aImpl = BorderWidthImpl( CHANGE_LINE2, THICKTHIN_SMALLGAP_line1,
389 1.0, THICKTHIN_SMALLGAP_gap );
390 break;
392 case THICKTHIN_MEDIUMGAP:
393 aImpl = BorderWidthImpl(
394 CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST,
395 0.25, 0.5, 0.25 );
396 break;
398 case THICKTHIN_LARGEGAP:
399 aImpl = BorderWidthImpl( CHANGE_DIST, THICKTHIN_LARGEGAP_line1,
400 THICKTHIN_LARGEGAP_line2, 1.0 );
401 break;
403 // Engraved / Embossed
405 * Word compat: the lines widths are exactly following this rule, shouldbe:
406 * 0.75pt up to 3pt and then 3pt
409 case EMBOSSED:
410 case ENGRAVED:
411 aImpl = BorderWidthImpl(
412 CHANGE_LINE1 | CHANGE_LINE2 | CHANGE_DIST,
413 0.25, 0.25, 0.5 );
414 break;
416 // Inset / Outset
418 * Word compat: the gap width should be measured relatively to the biggest width for the
419 * row or column.
421 case OUTSET:
422 aImpl = BorderWidthImpl(
423 CHANGE_LINE2 | CHANGE_DIST,
424 OUTSET_line1, 0.5, 0.5 );
425 break;
427 case INSET:
428 aImpl = BorderWidthImpl(
429 CHANGE_LINE1 | CHANGE_DIST,
430 0.5, INSET_line2, 0.5 );
431 break;
434 return aImpl;
437 // -----------------------------------------------------------------------
439 SvxBorderLine::SvxBorderLine( const SvxBorderLine& r )
441 *this = r;
444 // -----------------------------------------------------------------------
446 SvxBorderLine& SvxBorderLine::operator=( const SvxBorderLine& r )
448 aColor = r.aColor;
449 m_nWidth = r.m_nWidth;
450 m_aWidthImpl = r.m_aWidthImpl;
451 m_bMirrorWidths = r.m_bMirrorWidths;
452 m_nMult = r.m_nMult;
453 m_nDiv = r.m_nDiv;
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;
459 return *this;
462 // -----------------------------------------------------------------------
464 void SvxBorderLine::ScaleMetrics( long nMult, long nDiv )
466 m_nMult = nMult;
467 m_nDiv = nDiv;
470 void SvxBorderLine::GuessLinesWidths( SvxBorderStyle nStyle, sal_uInt16 nOut, sal_uInt16 nIn, sal_uInt16 nDist )
472 if (NONE == nStyle)
474 nStyle = SOLID;
475 if ( nOut > 0 && nIn > 0 )
476 nStyle = DOUBLE;
479 if ( nStyle == DOUBLE )
481 static SvxBorderStyle aDoubleStyles[] =
483 DOUBLE,
484 THINTHICK_SMALLGAP,
485 THINTHICK_MEDIUMGAP,
486 THINTHICK_LARGEGAP,
487 THICKTHIN_SMALLGAP,
488 THICKTHIN_MEDIUMGAP,
489 THICKTHIN_LARGEGAP
492 size_t const len = SAL_N_ELEMENTS(aDoubleStyles);
493 long nWidth = 0;
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
503 if ( nWidth > 0 )
505 nStyle = nTestStyle;
506 SetBorderLineStyle(nStyle);
507 m_nWidth = nWidth;
509 else
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));
524 else
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.
532 switch (nStyle)
534 case SOLID:
535 case DOTTED:
536 case DASHED:
537 case FINE_DASHED:
538 ::std::swap( nOut, nIn);
539 break;
540 default:
541 ; // nothing
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 );
553 return nOut;
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 );
561 return nIn;
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 )
586 m_nStyle = nNew;
587 m_aWidthImpl = getWidthImpl( m_nStyle );
589 switch ( nNew )
591 case EMBOSSED:
592 m_pColorOutFn = threeDLightColor;
593 m_pColorInFn = threeDDarkColor;
594 m_pColorGapFn = threeDMediumColor;
595 m_bUseLeftTop = true;
596 break;
597 case ENGRAVED:
598 m_pColorOutFn = threeDDarkColor;
599 m_pColorInFn = threeDLightColor;
600 m_pColorGapFn = threeDMediumColor;
601 m_bUseLeftTop = true;
602 break;
603 case OUTSET:
604 m_pColorOutFn = lightColor;
605 m_pColorInFn = darkColor;
606 m_bUseLeftTop = true;
607 m_pColorGapFn = NULL;
608 break;
609 case INSET:
610 m_pColorOutFn = darkColor;
611 m_pColorInFn = lightColor;
612 m_bUseLeftTop = true;
613 m_pColorGapFn = NULL;
614 break;
615 default:
616 m_pColorOutFn = darkColor;
617 m_pColorInFn = darkColor;
618 m_bUseLeftTop = false;
619 m_pColorGapFn = NULL;
620 break;
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 );
632 else
633 aResult = (*m_pColorOutFn)( aColor );
636 return aResult;
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 );
647 else
648 aResult = (*m_pColorInFn)( aColor );
651 return aResult;
654 Color SvxBorderLine::GetColorGap( ) const
656 Color aResult = aColor;
658 if ( m_aWidthImpl.IsDouble() && m_pColorGapFn != NULL )
660 aResult = (*m_pColorGapFn)( aColor );
663 return aResult;
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[] =
675 RID_SOLID,
676 RID_DOTTED,
677 RID_DASHED,
678 RID_DOUBLE,
679 RID_THINTHICK_SMALLGAP,
680 RID_THINTHICK_MEDIUMGAP,
681 RID_THINTHICK_LARGEGAP,
682 RID_THICKTHIN_SMALLGAP,
683 RID_THICKTHIN_MEDIUMGAP,
684 RID_THICKTHIN_LARGEGAP,
685 RID_EMBOSSED,
686 RID_ENGRAVED,
687 RID_OUTSET,
688 RID_INSET
690 sal_uInt16 nResId = aStyleIds[m_nStyle];
691 String aStr;
692 aStr += sal_Unicode('(');
693 aStr += ::GetColorString( aColor );
694 aStr += cpDelim;
696 if ( nResId )
697 aStr += EE_RESSTR(nResId);
698 else
700 String sMetric = EE_RESSTR(GetMetricId( eDestUnit ));
701 aStr += GetMetricText( (long)GetInWidth(), eSrcUnit, eDestUnit, pIntl );
702 if ( bMetricStr )
703 aStr += sMetric;
704 aStr += cpDelim;
705 aStr += GetMetricText( (long)GetOutWidth(), eSrcUnit, eDestUnit, pIntl );
706 if ( bMetricStr )
707 aStr += sMetric;
708 aStr += cpDelim;
709 aStr += GetMetricText( (long)GetDistance(), eSrcUnit, eDestUnit, pIntl );
710 if ( bMetricStr )
711 aStr += sMetric;
713 aStr += sal_Unicode(')');
714 return aStr;
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 )
724 return true;
726 else if ( nThisSize < nOtherSize )
728 return false;
730 else if ( rOtherLine.GetInWidth() && !GetInWidth() )
732 return true;
735 return false;
738 } // namespace editeng
740 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */