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 <svx/framelink.hxx>
23 #include <vcl/outdev.hxx>
24 #include <tools/gen.hxx>
25 #include <editeng/borderline.hxx>
26 #include <svtools/borderhelper.hxx>
28 #include <basegfx/polygon/b2dpolygon.hxx>
29 #include <basegfx/polygon/b2dpolygontools.hxx>
31 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
32 #include <drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx>
35 using namespace ::com::sun::star
;
36 using namespace editeng
;
41 // ============================================================================
45 typedef std::vector
< Point
> PointVec
;
47 // ----------------------------------------------------------------------------
48 // Link result structs for horizontal and vertical lines and borders.
50 /** Result struct used by the horizontal/vertical frame link functions.
52 This struct is used to return coordinate offsets for one end of a single
53 line in a frame border, i.e. the left end of the primary line of a
54 horizontal frame border.
56 1) Usage for horizontal lines
58 If this struct is returned by the lclLinkHorFrameBorder() function, each
59 member refers to the X coordinate of one edge of a single line end in a
60 horizontal frame border. They specify an offset to modify this coordinate
61 when the line is painted. The values in this struct may change a
62 rectangular line shape into a line with slanted left or right border, which
63 is used to connect the line with diagonal lines.
65 Usage for a left line end: Usage for a right line end:
68 +-------------------------------+
69 | the original horizontal line |
70 +-------------------------------+
74 2) Usage for vertical lines
76 If this struct is returned by the lclLinkVerFrameBorder() function, each
77 member refers to the Y coordinate of one edge of a single line end in a
78 vertical frame border. They specify an offset to modify this coordinate
79 when the line is painted. The values in this struct may change a
80 rectangular line shape into a line with slanted top or bottom border, which
81 is used to connect the line with diagonal lines.
83 Usage for a top line end: mnOffs1 ^ ^ mnOffs2
88 the original vertical line ---> | |
93 Usage for a bottom line end: mnOffs1 v v mnOffs2
97 long mnOffs1
; /// Offset for top or left edge, dependent of context.
98 long mnOffs2
; /// Offset for bottom or right edge, dependent of context
100 inline explicit LineEndResult() : mnOffs1( 0 ), mnOffs2( 0 ) {}
102 inline void Swap() { std::swap( mnOffs1
, mnOffs2
); }
103 inline void Negate() { mnOffs1
= -mnOffs1
; mnOffs2
= -mnOffs2
; }
106 /** Result struct used by the horizontal/vertical frame link functions.
108 This struct contains the linking results for one end of a frame border,
109 including both the primary and secondary line ends.
111 struct BorderEndResult
113 LineEndResult maPrim
; /// Result for primary line.
114 LineEndResult maSecn
; /// Result for secondary line.
115 LineEndResult maGap
; /// Result for gap line.
117 inline void Negate() { maPrim
.Negate(); maSecn
.Negate(); maGap
.Negate(); }
120 /** Result struct used by the horizontal/vertical frame link functions.
122 This struct contains the linking results for both frame border ends, and
123 therefore for the complete frame border.
127 BorderEndResult maBeg
; /// Result for begin of border line (left or top end).
128 BorderEndResult maEnd
; /// Result for end of border line (right or bottom end).
131 // ----------------------------------------------------------------------------
132 // Link result structs for diagonal lines and borders.
134 /** Result struct used by the diagonal frame link functions.
136 This struct contains the linking results for one line of a diagonal frame
139 struct DiagLineResult
141 long mnLClip
; /// Offset for left border of clipping rectangle.
142 long mnRClip
; /// Offset for right border of clipping rectangle.
143 long mnTClip
; /// Offset for top border of clipping rectangle.
144 long mnBClip
; /// Offset for bottom border of clipping rectangle.
146 inline explicit DiagLineResult() : mnLClip( 0 ), mnRClip( 0 ), mnTClip( 0 ), mnBClip( 0 ) {}
149 /** Result struct used by the diagonal frame link functions.
151 This struct contains the linking results for one diagonal frame border.
153 struct DiagBorderResult
155 DiagLineResult maPrim
; /// Result for primary line.
156 DiagLineResult maSecn
; /// Result for secondary line.
159 /** Result struct used by the diagonal frame link functions.
161 This struct contains the linking results for both diagonal frame borders.
163 struct DiagBordersResult
165 DiagBorderResult maTLBR
; /// Result for top-left to bottom-right frame border.
166 DiagBorderResult maBLTR
; /// Result for bottom-left to top-right frame border.
169 // ----------------------------------------------------------------------------
171 /** A helper struct containing two points of a line.
175 Point maBeg
; /// Start position of the line.
176 Point maEnd
; /// End position of the line.
178 explicit LinePoints( const Point
& rBeg
, const Point
& rEnd
) :
179 maBeg( rBeg
), maEnd( rEnd
) {}
180 explicit LinePoints( const Rectangle
& rRect
, bool bTLBR
) :
181 maBeg( bTLBR
? rRect
.TopLeft() : rRect
.TopRight() ),
182 maEnd( bTLBR
? rRect
.BottomRight() : rRect
.BottomLeft() ) {}
185 // ============================================================================
187 /** Rounds and casts a double value to a long value. */
188 inline long lclD2L( double fValue
)
190 return static_cast< long >( (fValue
< 0.0) ? (fValue
- 0.5) : (fValue
+ 0.5) );
193 /** Converts a width in twips to a width in another map unit (specified by fScale). */
194 double lclScaleValue( double nValue
, double fScale
, sal_uInt16 nMaxWidth
)
196 return std::min
<double>(nValue
* fScale
, nMaxWidth
);
199 // ----------------------------------------------------------------------------
200 // Line width offset calculation.
202 /** Returns the start offset of the single/primary line across the frame border.
204 All following lclGet*Beg() and lclGet*End() functions return sub units to
205 increase the computational accuracy, where 256 sub units are equal to
206 1 map unit of the used OutputDevice.
208 The following pictures show the upper end of a vertical frame border and
209 illustrates the return values of all following lclGet*Beg() and lclGet*End()
210 functions. The first picture shows a single frame border, the second picture
211 shows a double frame border.
213 The functions regard the reference point handling mode of the passed border
216 All returned offsets are relative to the middle position of the frame
217 border (offsets left of the middle are returned negative, offsets right
218 of the middle are returned positive).
220 All returned offsets are relative to the begin of the frame border
221 (lclGetBeg() always returns 0).
223 All returned offsets are relative to the end of the frame border
224 (lclGetEnd() always returns 0).
227 |<- lclGetBeforeBeg() |<- lclGetPrimEnd()
229 ||<- lclGetBeg() ||<- lclGetBehindEnd()
231 |#################################|
232 direction of | #################################
233 the frame | #################################
234 border is | #################################
235 vertical | #################################
236 v #################################
238 |<- middle of the frame border
240 lclGetDistEnd() ->||<- lclGetSecnBeg()
242 lclGetBeg() ->| lclGetDistBeg() ->| || |<- lclGetEnd()
244 lclGetBeforeBeg()->|| lclGetPrimEnd() ->|| || ||<- lclGetBehindEnd()
246 |######################| |#############|
247 direction of | ###################### #############
248 the frame | ###################### #############
249 border is | ###################### #############
250 vertical | ###################### | #############
251 v ###################### | #############
252 primary line | secondary line
254 |<- middle of the frame border
257 The start offset of the single/primary line relative to the reference
258 position of the frame border (sub units; 0 for invisible or one pixel
259 wide single frame styles).
261 long lclGetBeg( const Style
& rBorder
)
264 switch( rBorder
.GetRefMode() )
266 case REFMODE_CENTERED
: if( rBorder
.Prim() ) nPos
= -128 * (rBorder
.GetWidth() - 1); break;
267 case REFMODE_END
: if( rBorder
.Prim() ) nPos
= -256 * (rBorder
.GetWidth() - 1); break;
268 case REFMODE_BEGIN
: break;
273 /** Returns the end offset of the single/secondary line across the frame border.
274 @descr See description of lclGetBeg() for an illustration.
275 @return The end offset of the single/secondary line relative to the
276 reference position of the frame border (sub units; 0 for invisible or one
277 pixel wide single frame styles). */
278 long lclGetEnd( const Style
& rBorder
)
281 switch( rBorder
.GetRefMode() )
283 case REFMODE_CENTERED
: if( rBorder
.Prim() ) nPos
= 128 * (rBorder
.GetWidth() - 1); break;
284 case REFMODE_BEGIN
: if( rBorder
.Prim() ) nPos
= 256 * (rBorder
.GetWidth() - 1); break;
285 case REFMODE_END
: break;
290 /** Returns the end offset of the primary line across the frame border.
291 @descr See description of lclGetBeg() for an illustration.
292 @return The end offset of the primary line relative to the reference
293 position of the frame border (sub units; the end of the primary line in a
294 double frame style, otherwise the same as lclGetEnd()). */
295 inline long lclGetPrimEnd( const Style
& rBorder
)
296 { return rBorder
.Prim() ? (lclGetBeg( rBorder
) + 256 * (rBorder
.Prim() - 1)) : 0; }
298 /** Returns the start offset of the secondary line across the frame border.
299 @descr See description of lclGetBeg() for an illustration.
300 @return The start offset of the secondary line relative to the reference
301 position of the frame border (sub units; 0 for single/invisible border
303 inline long lclGetSecnBeg( const Style
& rBorder
)
304 { return rBorder
.Secn() ? (lclGetEnd( rBorder
) - 256 * (rBorder
.Secn() - 1)) : 0; }
306 /** Returns the start offset of the distance space across the frame border.
307 @descr See description of lclGetBeg() for an illustration.
308 @return The start offset of the distance space relative to the reference
309 position of the frame border (sub units; 0 for single/invisible border
311 inline long lclGetDistBeg( const Style
& rBorder
)
312 { return rBorder
.Secn() ? (lclGetBeg( rBorder
) + 256 * rBorder
.Prim()) : 0; }
314 /** Returns the end offset of the distance space across the frame border.
315 @descr See description of lclGetBeg() for an illustration.
316 @return The end offset of the distance space relative to the reference
317 position of the frame border (sub units; 0 for single/invisible border
319 inline long lclGetDistEnd( const Style
& rBorder
)
320 { return rBorder
.Secn() ? (lclGetEnd( rBorder
) - 256 * rBorder
.Secn()) : 0; }
322 /** Returns the offset before start of single/primary line across the frame border.
323 @descr See description of lclGetBeg() for an illustration.
324 @return The offset directly before start of single/primary line relative
325 to the reference position of the frame border (sub units; a value one less
326 than lclGetBeg() for visible frame styles, or 0 for invisible frame style). */
327 inline long lclGetBeforeBeg( const Style
& rBorder
)
328 { return rBorder
.Prim() ? (lclGetBeg( rBorder
) - 256) : 0; }
330 /** Returns the offset behind end of single/secondary line across the frame border.
331 @descr See description of lclGetBeg() for an illustration.
332 @return The offset directly behind end of single/secondary line relative
333 to the reference position of the frame border (sub units; a value one
334 greater than lclGetEnd() for visible frame styles, or 0 for invisible frame
336 inline long lclGetBehindEnd( const Style
& rBorder
)
337 { return rBorder
.Prim() ? (lclGetEnd( rBorder
) + 256) : 0; }
339 // ============================================================================
341 // ============================================================================
343 // ----------------------------------------------------------------------------
344 // Linking of single horizontal line ends.
346 /** Calculates X offsets for the left end of a single horizontal frame border.
348 See DrawHorFrameBorder() function for a description of all parameters.
351 (out-param) The contained values (sub units) specify offsets for the
352 X coordinates of the left line end.
354 void lclLinkLeftEnd_Single(
355 LineEndResult
& rResult
, const Style
& rBorder
,
356 const DiagStyle
& rLFromTR
, const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
, const DiagStyle
& rLFromBR
)
358 // both vertical and diagonal frame borders are double
359 if( rLFromT
.Secn() && rLFromB
.Secn() && rLFromTR
.Secn() && rLFromBR
.Secn() )
361 // take left position of upper and lower secondary start
362 rResult
.mnOffs1
= GetBLDiagOffset( lclGetBeg( rBorder
), lclGetSecnBeg( rLFromTR
), rLFromTR
.GetAngle() );
363 rResult
.mnOffs2
= GetTLDiagOffset( lclGetEnd( rBorder
), lclGetSecnBeg( rLFromBR
), rLFromBR
.GetAngle() );
367 // both vertical frame borders are double
368 if( rLFromT
.Secn() && rLFromB
.Secn() )
370 rResult
.mnOffs1
= (!rLFromTR
.Secn() && !rLFromBR
.Secn() && (rLFromT
.GetWidth() == rLFromB
.GetWidth())) ?
371 // don't overdraw vertical borders with equal width
372 lclGetBehindEnd( rLFromT
) :
373 // take leftmost start of both secondary lines (#46488#)
374 std::min( lclGetSecnBeg( rLFromT
), lclGetSecnBeg( rLFromB
) );
377 // single border with equal width coming from left
378 else if( !rLFromL
.Secn() && (rLFromL
.Prim() == rBorder
.Prim()) )
379 // draw to connection point
382 // single border coming from left
383 else if( !rLFromL
.Secn() && rLFromL
.Prim() )
385 if( rLFromL
.Prim() == rBorder
.Prim() )
386 // draw to reference position, if from left has equal width
389 rResult
.mnOffs1
= (rLFromL
< rBorder
) ?
390 // take leftmost start of both frame borders, if from left is thinner
391 std::min( lclGetBeg( rLFromT
), lclGetBeg( rLFromB
) ) :
392 // do not overdraw vertical, if from left is thicker
393 std::max( lclGetBehindEnd( rLFromT
), lclGetBehindEnd( rLFromB
) );
396 // no border coming from left
397 else if( !rLFromL
.Prim() )
398 // don't overdraw vertical borders with equal width
399 rResult
.mnOffs1
= (rLFromT
.GetWidth() == rLFromB
.GetWidth()) ?
400 lclGetBehindEnd( rLFromT
) :
401 std::min( lclGetBeg( rLFromT
), lclGetBeg( rLFromB
) );
403 // double frame border coming from left and from top
404 else if( rLFromT
.Secn() )
405 // do not overdraw the vertical double frame border
406 rResult
.mnOffs1
= lclGetBehindEnd( rLFromT
);
408 // double frame border coming from left and from bottom
409 else if( rLFromB
.Secn() )
410 // do not overdraw the vertical double frame border
411 rResult
.mnOffs1
= lclGetBehindEnd( rLFromB
);
413 // double frame border coming from left, both vertical frame borders are single or off
415 // draw from leftmost start of both frame borders, if from left is not thicker
416 rResult
.mnOffs1
= (rLFromL
<= rBorder
) ?
417 std::min( lclGetBeg( rLFromT
), lclGetBeg( rLFromB
) ) :
418 std::max( lclGetBehindEnd( rLFromT
), lclGetBehindEnd( rLFromB
) );
420 // bottom-left point is equal to top-left point (results in rectangle)
421 rResult
.mnOffs2
= rResult
.mnOffs1
;
425 /** Calculates X offsets for the left end of a primary horizontal line.
427 See DrawHorFrameBorder() function for a description of all parameters.
430 (out-param) The contained values (sub units) specify offsets for the
431 X coordinates of the left end of the primary line.
433 void lclLinkLeftEnd_Prim(
434 LineEndResult
& rResult
, const Style
& rBorder
,
435 const DiagStyle
& rLFromTR
, const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
, const DiagStyle
& /*rLFromBR*/ )
437 // double diagonal frame border coming from top right
438 if( rLFromTR
.Secn() )
440 // draw from where secondary diagonal line meets the own primary
441 rResult
.mnOffs1
= GetBLDiagOffset( lclGetBeg( rBorder
), lclGetSecnBeg( rLFromTR
), rLFromTR
.GetAngle() );
442 rResult
.mnOffs2
= GetBLDiagOffset( lclGetPrimEnd( rBorder
), lclGetSecnBeg( rLFromTR
), rLFromTR
.GetAngle() );
445 // no or single diagonal frame border - ignore it
448 // double frame border coming from top
450 // draw from left edge of secondary vertical
451 rResult
.mnOffs1
= lclGetSecnBeg( rLFromT
);
453 // double frame border coming from left (from top is not double)
454 else if( rLFromL
.Secn() )
455 // do not overdraw single frame border coming from top
456 rResult
.mnOffs1
= (rLFromL
.GetWidth() == rBorder
.GetWidth()) ?
457 0 : lclGetBehindEnd( rLFromT
);
459 // double frame border coming from bottom (from top and from left are not double)
460 else if( rLFromB
.Secn() )
461 // draw from left edge of primary vertical from bottom
462 rResult
.mnOffs1
= lclGetBeg( rLFromB
);
464 // no other frame border is double
466 // do not overdraw vertical frame borders
467 rResult
.mnOffs1
= std::max( lclGetBehindEnd( rLFromT
), lclGetBehindEnd( rLFromB
) );
469 // bottom-left point is equal to top-left point (results in rectangle)
470 rResult
.mnOffs2
= rResult
.mnOffs1
;
474 /** Calculates X offsets for the left end of a secondary horizontal line.
476 See DrawHorFrameBorder() function for a description of all parameters.
479 (out-param) The contained values (sub units) specify offsets for the
480 X coordinates of the left end of the secondary line.
482 void lclLinkLeftEnd_Secn(
483 LineEndResult
& rResult
, const Style
& rBorder
,
484 const DiagStyle
& rLFromTR
, const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
, const DiagStyle
& rLFromBR
)
486 /* Recycle lclLinkLeftEnd_Prim() function with mirrored horizontal borders. */
487 lclLinkLeftEnd_Prim( rResult
, rBorder
.Mirror(), rLFromBR
, rLFromB
, rLFromL
.Mirror(), rLFromT
, rLFromTR
);
491 void lclLinkLeftEnd_Gap(
492 LineEndResult
& rResult
, const Style
& rBorder
,
493 const DiagStyle
& /*rLFromTR*/, const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
, const DiagStyle
& /*rLFromBR*/ )
496 if ( rLFromT
.Secn() )
497 rResult
.mnOffs1
= lclGetDistBeg( rLFromT
);
498 else if ( rLFromL
.Secn( ) )
499 rResult
.mnOffs1
= ( rLFromL
.GetWidth() == rBorder
.GetWidth() )?
500 0 : lclGetBehindEnd( rLFromT
);
501 else if ( rLFromB
.Secn( ) )
502 rResult
.mnOffs1
= lclGetDistBeg( rLFromB
);
504 rResult
.mnOffs1
= std::max( lclGetBehindEnd( rLFromT
), lclGetBehindEnd( rLFromB
) );
506 rResult
.mnOffs2
= rResult
.mnOffs1
;
508 // ----------------------------------------------------------------------------
509 // Linking of horizontal frame border ends.
511 /** Calculates X offsets for the left end of a horizontal frame border.
513 This function can be used for single and double frame borders.
514 See DrawHorFrameBorder() function for a description of all parameters.
517 (out-param) The contained values (sub units) specify offsets for the
518 X coordinates of the left end of the line(s) in the frame border.
521 BorderEndResult
& rResult
, const Style
& rBorder
,
522 const DiagStyle
& rLFromTR
, const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
, const DiagStyle
& rLFromBR
)
526 // current frame border is double
527 lclLinkLeftEnd_Prim( rResult
.maPrim
, rBorder
, rLFromTR
, rLFromT
, rLFromL
, rLFromB
, rLFromBR
);
528 lclLinkLeftEnd_Secn( rResult
.maSecn
, rBorder
, rLFromTR
, rLFromT
, rLFromL
, rLFromB
, rLFromBR
);
529 lclLinkLeftEnd_Gap( rResult
.maGap
, rBorder
, rLFromTR
, rLFromT
, rLFromL
, rLFromB
, rLFromBR
);
531 else if( rBorder
.Prim() )
533 // current frame border is single
534 lclLinkLeftEnd_Single( rResult
.maPrim
, rBorder
, rLFromTR
, rLFromT
, rLFromL
, rLFromB
, rLFromBR
);
538 SAL_WARN( "svx.dialog", "lclLinkLeftEnd - called for invisible frame style" );
542 /** Calculates X offsets for the right end of a horizontal frame border.
544 This function can be used for single and double frame borders.
545 See DrawHorFrameBorder() function for a description of all parameters.
548 (out-param) The contained values (sub units) specify offsets for the
549 X coordinates of the right end of the line(s) in the frame border.
551 void lclLinkRightEnd(
552 BorderEndResult
& rResult
, const Style
& rBorder
,
553 const DiagStyle
& rRFromTL
, const Style
& rRFromT
, const Style
& rRFromR
, const Style
& rRFromB
, const DiagStyle
& rRFromBL
)
555 /* Recycle lclLinkLeftEnd() function with mirrored vertical borders. */
556 lclLinkLeftEnd( rResult
, rBorder
, rRFromTL
.Mirror(), rRFromT
.Mirror(), rRFromR
, rRFromB
.Mirror(), rRFromBL
.Mirror() );
560 // ----------------------------------------------------------------------------
561 // Linking of horizontal and vertical frame borders.
563 /** Calculates X offsets for all line ends of a horizontal frame border.
565 This function can be used for single and double frame borders.
566 See DrawHorFrameBorder() function for a description of all parameters.
569 (out-param) The contained values (sub units) specify offsets for the
570 X coordinates of both ends of the line(s) in the frame border. To get
571 the actual X coordinates to draw the lines, these offsets have to be
572 added to the X coordinates of the reference points of the frame border
573 (the offsets may be negative).
575 void lclLinkHorFrameBorder(
576 BorderResult
& rResult
, const Style
& rBorder
,
577 const DiagStyle
& rLFromTR
, const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
, const DiagStyle
& rLFromBR
,
578 const DiagStyle
& rRFromTL
, const Style
& rRFromT
, const Style
& rRFromR
, const Style
& rRFromB
, const DiagStyle
& rRFromBL
)
580 lclLinkLeftEnd( rResult
.maBeg
, rBorder
, rLFromTR
, rLFromT
, rLFromL
, rLFromB
, rLFromBR
);
581 lclLinkRightEnd( rResult
.maEnd
, rBorder
, rRFromTL
, rRFromT
, rRFromR
, rRFromB
, rRFromBL
);
584 /** Calculates Y offsets for all line ends of a vertical frame border.
586 This function can be used for single and double frame borders.
587 See DrawVerFrameBorder() function for a description of all parameters.
590 (out-param) The contained values (sub units) specify offsets for the
591 Y coordinates of both ends of the line(s) in the frame border. To get
592 the actual Y coordinates to draw the lines, these offsets have to be
593 added to the Y coordinates of the reference points of the frame border
594 (the offsets may be negative).
596 void lclLinkVerFrameBorder(
597 BorderResult
& rResult
, const Style
& rBorder
,
598 const DiagStyle
& rTFromBL
, const Style
& rTFromL
, const Style
& rTFromT
, const Style
& rTFromR
, const DiagStyle
& rTFromBR
,
599 const DiagStyle
& rBFromTL
, const Style
& rBFromL
, const Style
& rBFromB
, const Style
& rBFromR
, const DiagStyle
& rBFromTR
)
601 /* Recycle lclLinkHorFrameBorder() function with correct parameters. The
602 frame border is virtually mirrored at the top-left to bottom-right
603 diagonal. rTFromBR and rBFromTL are mirrored to process their primary
604 and secondary lines correctly. */
605 lclLinkHorFrameBorder( rResult
, rBorder
,
606 rTFromBL
, rTFromL
, rTFromT
, rTFromR
, rTFromBR
.Mirror(),
607 rBFromTL
.Mirror(), rBFromL
, rBFromB
, rBFromR
, rBFromTR
);
610 // ============================================================================
612 // ----------------------------------------------------------------------------
613 // Linking of diagonal frame borders.
615 /** Calculates clipping offsets for a top-left to bottom-right frame border.
617 This function can be used for single and double frame borders.
618 See DrawDiagFrameBorders() function for a description of all parameters.
621 (out-param) The contained values (sub units) specify offsets for all
622 borders of the reference rectangle containing the diagonal frame border.
624 void lclLinkTLBRFrameBorder(
625 DiagBorderResult
& rResult
, const Style
& rBorder
,
626 const Style
& rTLFromB
, const Style
& rTLFromR
, const Style
& rBRFromT
, const Style
& rBRFromL
)
628 bool bIsDbl
= rBorder
.Secn() != 0;
630 rResult
.maPrim
.mnLClip
= lclGetBehindEnd( rTLFromB
);
631 rResult
.maPrim
.mnRClip
= (bIsDbl
&& rBRFromT
.Secn()) ? lclGetEnd( rBRFromT
) : lclGetBeforeBeg( rBRFromT
);
632 rResult
.maPrim
.mnTClip
= (bIsDbl
&& rTLFromR
.Secn()) ? lclGetBeg( rTLFromR
) : lclGetBehindEnd( rTLFromR
);
633 rResult
.maPrim
.mnBClip
= lclGetBeforeBeg( rBRFromL
);
637 rResult
.maSecn
.mnLClip
= rTLFromB
.Secn() ? lclGetBeg( rTLFromB
) : lclGetBehindEnd( rTLFromB
);
638 rResult
.maSecn
.mnRClip
= lclGetBeforeBeg( rBRFromT
);
639 rResult
.maSecn
.mnTClip
= lclGetBehindEnd( rTLFromR
);
640 rResult
.maSecn
.mnBClip
= rBRFromL
.Secn() ? lclGetEnd( rBRFromL
) : lclGetBeforeBeg( rBRFromL
);
644 /** Calculates clipping offsets for a bottom-left to top-right frame border.
646 This function can be used for single and double frame borders.
647 See DrawDiagFrameBorders() function for a description of all parameters.
650 (out-param) The contained values (sub units) specify offsets for all
651 borders of the reference rectangle containing the diagonal frame border.
653 void lclLinkBLTRFrameBorder(
654 DiagBorderResult
& rResult
, const Style
& rBorder
,
655 const Style
& rBLFromT
, const Style
& rBLFromR
, const Style
& rTRFromB
, const Style
& rTRFromL
)
657 bool bIsDbl
= rBorder
.Secn() != 0;
659 rResult
.maPrim
.mnLClip
= lclGetBehindEnd( rBLFromT
);
660 rResult
.maPrim
.mnRClip
= (bIsDbl
&& rTRFromB
.Secn()) ? lclGetEnd( rTRFromB
) : lclGetBeforeBeg( rTRFromB
);
661 rResult
.maPrim
.mnTClip
= lclGetBehindEnd( rTRFromL
);
662 rResult
.maPrim
.mnBClip
= (bIsDbl
&& rBLFromR
.Secn()) ? lclGetEnd( rBLFromR
) : lclGetBeforeBeg( rBLFromR
);
666 rResult
.maSecn
.mnLClip
= rBLFromT
.Secn() ? lclGetBeg( rBLFromT
) : lclGetBehindEnd( rBLFromT
);
667 rResult
.maSecn
.mnRClip
= lclGetBeforeBeg( rTRFromB
);
668 rResult
.maSecn
.mnTClip
= rTRFromL
.Secn() ? lclGetBeg( rTRFromL
) : lclGetBehindEnd( rTRFromL
);
669 rResult
.maSecn
.mnBClip
= lclGetBeforeBeg( rBLFromR
);
673 /** Calculates clipping offsets for both diagonal frame borders.
675 This function can be used for single and double frame borders.
676 See DrawDiagFrameBorders() function for a description of all parameters.
679 (out-param) The contained values (sub units) specify offsets for all
680 borders of the reference rectangle containing the diagonal frame
683 void lclLinkDiagFrameBorders(
684 DiagBordersResult
& rResult
, const Style
& rTLBR
, const Style
& rBLTR
,
685 const Style
& rTLFromB
, const Style
& rTLFromR
, const Style
& rBRFromT
, const Style
& rBRFromL
,
686 const Style
& rBLFromT
, const Style
& rBLFromR
, const Style
& rTRFromB
, const Style
& rTRFromL
)
688 lclLinkTLBRFrameBorder( rResult
.maTLBR
, rTLBR
, rTLFromB
, rTLFromR
, rBRFromT
, rBRFromL
);
689 lclLinkBLTRFrameBorder( rResult
.maBLTR
, rBLTR
, rBLFromT
, rBLFromR
, rTRFromB
, rTRFromL
);
692 // ============================================================================
694 // ============================================================================
696 // ----------------------------------------------------------------------------
697 // Simple helper functions
699 /** Converts sub units to OutputDevice map units. */
700 inline long lclToMapUnit( long nSubUnits
)
702 return ((nSubUnits
< 0) ? (nSubUnits
- 127) : (nSubUnits
+ 128)) / 256;
705 /** Converts a point in sub units to an OutputDevice point. */
706 inline Point
lclToMapUnit( long nSubXPos
, long nSubYPos
)
708 return Point( lclToMapUnit( nSubXPos
), lclToMapUnit( nSubYPos
) );
711 /** Returns a polygon constructed from a vector of points. */
712 inline Polygon
lclCreatePolygon( const PointVec
& rPoints
)
714 return Polygon( static_cast< sal_uInt16
>( rPoints
.size() ), &rPoints
[ 0 ] );
717 /** Returns a polygon constructed from the five passed points. */
718 Region
lclCreatePolygon( const Point
& rP1
, const Point
& rP2
, const Point
& rP3
, const Point
& rP4
, const Point
& rP5
)
721 aPoints
.reserve( 5 );
722 aPoints
.push_back( rP1
);
723 aPoints
.push_back( rP2
);
724 aPoints
.push_back( rP3
);
725 aPoints
.push_back( rP4
);
726 aPoints
.push_back( rP5
);
727 return Region(lclCreatePolygon(aPoints
));
730 /** Sets the color of the passed frame style to the output device.
732 Sets the line color and fill color in the output device.
735 The output device the color has to be set to. The old colors are pushed
736 onto the device's stack and can be restored with a call to
737 OutputDevice::Pop(). Please take care about the correct calling order
738 of Pop() if this function is used with other functions pushing
739 something onto the stack.
741 The border style that contains the line color to be set to the device.
743 void lclSetColorToOutDev( OutputDevice
& rDev
, const Color
& rColor
, const Color
* pForceColor
)
745 rDev
.Push( PUSH_LINECOLOR
| PUSH_FILLCOLOR
);
746 rDev
.SetLineColor( pForceColor
? *pForceColor
: rColor
);
747 rDev
.SetFillColor( pForceColor
? *pForceColor
: rColor
);
750 // ----------------------------------------------------------------------------
751 // ============================================================================
752 // Drawing of horizontal frame borders.
754 /** Draws a horizontal thin or thick line into the passed output device.
756 The X coordinates of the edges of the line are adjusted according to the
757 passed LineEndResult structs. A one pixel wide line can be drawn dotted.
761 const Point
& rLPos
, const LineEndResult
& rLRes
,
762 const Point
& rRPos
, const LineEndResult
& rRRes
,
763 long nTOffs
, long nBOffs
, SvxBorderStyle nDashing
)
765 LinePoints
aTPoints( rLPos
+ lclToMapUnit( rLRes
.mnOffs1
, nTOffs
), rRPos
+ lclToMapUnit( rRRes
.mnOffs1
, nTOffs
) );
766 LinePoints
aBPoints( rLPos
+ lclToMapUnit( rLRes
.mnOffs2
, nBOffs
), rRPos
+ lclToMapUnit( rRRes
.mnOffs2
, nBOffs
) );
768 sal_uInt32 nWidth
= lclToMapUnit( abs( nTOffs
) ) + lclToMapUnit( abs( nBOffs
) );
769 if ( ( nTOffs
>= 0 && nBOffs
>= 0 ) || ( nTOffs
<= 0 && nBOffs
<= 0 ) )
770 nWidth
= abs( lclToMapUnit( nTOffs
) - lclToMapUnit( nBOffs
) ) + 1;
771 Point rLMid
= ( aTPoints
.maBeg
+ aBPoints
.maBeg
) / 2;
772 Point rRMid
= ( aTPoints
.maEnd
+ aBPoints
.maEnd
) / 2;
774 ::svtools::DrawLine( rDev
, rLMid
, rRMid
, nWidth
, nDashing
);
777 /** Draws a horizontal frame border into the passed output device.
780 The top-left or bottom-left reference point of the diagonal frame border.
782 The top-right or bottom-right reference point of the diagonal frame border.
784 The frame style used to draw the border.
786 The X coordinates of the edges of all lines of the frame border are
787 adjusted according to the offsets contained here.
789 void lclDrawHorFrameBorder(
790 OutputDevice
& rDev
, const Point
& rLPos
, const Point
& rRPos
,
791 const Style
& rBorder
, const BorderResult
& rResult
, const Color
* pForceColor
)
793 DBG_ASSERT( rBorder
.Prim(), "svx::frame::lclDrawHorFrameBorder - line not visible" );
794 DBG_ASSERT( rLPos
.X() <= rRPos
.X(), "svx::frame::lclDrawHorFrameBorder - wrong order of line ends" );
795 DBG_ASSERT( rLPos
.Y() == rRPos
.Y(), "svx::frame::lclDrawHorFrameBorder - line not horizontal" );
796 if( rLPos
.X() <= rRPos
.X() )
798 if ( rBorder
.UseGapColor( ) )
800 lclSetColorToOutDev( rDev
, rBorder
.GetColorGap(), pForceColor
);
801 lclDrawHorLine( rDev
, rLPos
, rResult
.maBeg
.maGap
, rRPos
, rResult
.maEnd
.maGap
,
802 lclGetPrimEnd( rBorder
), lclGetSecnBeg( rBorder
), rBorder
.Type() );
803 rDev
.Pop(); // Gap color
806 lclSetColorToOutDev( rDev
, rBorder
.GetColorPrim(), pForceColor
);
807 lclDrawHorLine( rDev
, rLPos
, rResult
.maBeg
.maPrim
, rRPos
, rResult
.maEnd
.maPrim
,
808 lclGetBeg( rBorder
), lclGetPrimEnd( rBorder
), rBorder
.Type() );
809 rDev
.Pop(); // colors
813 lclSetColorToOutDev( rDev
, rBorder
.GetColorSecn(), pForceColor
);
814 lclDrawHorLine( rDev
, rLPos
, rResult
.maBeg
.maSecn
, rRPos
, rResult
.maEnd
.maSecn
,
815 lclGetSecnBeg( rBorder
), lclGetEnd( rBorder
), rBorder
.Type() );
816 rDev
.Pop(); // colors
821 // ----------------------------------------------------------------------------
822 // Drawing of vertical frame borders.
824 /** Draws a vertical thin or thick line into the passed output device.
826 The Y coordinates of the edges of the line are adjusted according to the
827 passed LineEndResult structs. A one pixel wide line can be drawn dotted.
831 const Point
& rTPos
, const LineEndResult
& rTRes
,
832 const Point
& rBPos
, const LineEndResult
& rBRes
,
833 long nLOffs
, long nROffs
, SvxBorderStyle nDashing
)
835 LinePoints
aLPoints( rTPos
+ lclToMapUnit( nLOffs
, rTRes
.mnOffs1
), rBPos
+ lclToMapUnit( nLOffs
, rBRes
.mnOffs1
) );
836 LinePoints
aRPoints( rTPos
+ lclToMapUnit( nROffs
, rTRes
.mnOffs2
), rBPos
+ lclToMapUnit( nROffs
, rBRes
.mnOffs2
) );
838 sal_uInt32 nWidth
= lclToMapUnit( abs( nLOffs
) ) + lclToMapUnit( abs( nROffs
) );
839 if ( ( nLOffs
>= 0 && nROffs
>= 0 ) || ( nLOffs
<= 0 && nROffs
<= 0 ) )
840 nWidth
= abs( lclToMapUnit( nLOffs
) - lclToMapUnit( nROffs
) ) + 1;
841 Point rTMid
= ( aLPoints
.maBeg
+ aRPoints
.maBeg
) / 2;
842 Point rBMid
= ( aLPoints
.maEnd
+ aRPoints
.maEnd
) / 2;
844 ::svtools::DrawLine( rDev
, rTMid
, rBMid
, nWidth
, nDashing
);
847 /** Draws a vertical frame border into the passed output device.
850 The top-left or top-right reference point of the diagonal frame border.
852 The bottom-left or bottom-right reference point of the diagonal frame border.
854 The frame style used to draw the border.
856 The Y coordinates of the edges of all lines of the frame border are
857 adjusted according to the offsets contained here.
859 void lclDrawVerFrameBorder(
860 OutputDevice
& rDev
, const Point
& rTPos
, const Point
& rBPos
,
861 const Style
& rBorder
, const BorderResult
& rResult
, const Color
* pForceColor
)
863 DBG_ASSERT( rBorder
.Prim(), "svx::frame::lclDrawVerFrameBorder - line not visible" );
864 DBG_ASSERT( rTPos
.Y() <= rBPos
.Y(), "svx::frame::lclDrawVerFrameBorder - wrong order of line ends" );
865 DBG_ASSERT( rTPos
.X() == rBPos
.X(), "svx::frame::lclDrawVerFrameBorder - line not vertical" );
866 if( rTPos
.Y() <= rBPos
.Y() )
868 if ( rBorder
.UseGapColor( ) )
870 lclSetColorToOutDev( rDev
, rBorder
.GetColorGap(), pForceColor
);
871 lclDrawVerLine( rDev
, rTPos
, rResult
.maBeg
.maGap
, rBPos
, rResult
.maEnd
.maGap
,
872 lclGetPrimEnd( rBorder
), lclGetSecnBeg( rBorder
), rBorder
.Type() );
873 rDev
.Pop(); // Gap color
876 lclSetColorToOutDev( rDev
, rBorder
.GetColorPrim(), pForceColor
);
877 lclDrawVerLine( rDev
, rTPos
, rResult
.maBeg
.maPrim
, rBPos
, rResult
.maEnd
.maPrim
,
878 lclGetBeg( rBorder
), lclGetPrimEnd( rBorder
), rBorder
.Type() );
879 rDev
.Pop(); // colors
882 lclSetColorToOutDev( rDev
, rBorder
.GetColorSecn(), pForceColor
);
883 lclDrawVerLine( rDev
, rTPos
, rResult
.maBeg
.maSecn
, rBPos
, rResult
.maEnd
.maSecn
,
884 lclGetSecnBeg( rBorder
), lclGetEnd( rBorder
), rBorder
.Type() );
885 rDev
.Pop(); // colors
890 // ============================================================================
891 // Drawing of diagonal frame borders, incudes clipping functions.
893 /** Returns the drawing coordinates for a diagonal thin line.
895 This function can be used for top-left to bottom-right and for bottom-left
899 The reference rectangle of the diagonal frame border.
901 true = top-left to bottom-right; false = bottom-left to top-right.
903 Width offset (sub units) across the diagonal frame border.
905 A struct containg start and end position of the diagonal line.
907 LinePoints
lclGetDiagLineEnds( const Rectangle
& rRect
, bool bTLBR
, long nDiagOffs
)
909 LinePoints
aPoints( rRect
, bTLBR
);
910 bool bVert
= rRect
.GetWidth() < rRect
.GetHeight();
911 double fAngle
= bVert
? GetVerDiagAngle( rRect
) : GetHorDiagAngle( rRect
);
912 // vertical top-left to bottom-right borders are handled mirrored
914 nDiagOffs
= -nDiagOffs
;
915 long nTOffs
= bTLBR
? GetTLDiagOffset( 0, nDiagOffs
, fAngle
) : GetTRDiagOffset( 0, nDiagOffs
, fAngle
);
916 long nBOffs
= bTLBR
? GetBRDiagOffset( 0, nDiagOffs
, fAngle
) : GetBLDiagOffset( 0, nDiagOffs
, fAngle
);
917 // vertical bottom-left to top-right borders are handled with exchanged end points
918 if( bVert
&& !bTLBR
)
919 std::swap( nTOffs
, nBOffs
);
920 (bVert
? aPoints
.maBeg
.Y() : aPoints
.maBeg
.X()) += lclToMapUnit( nTOffs
);
921 (bVert
? aPoints
.maEnd
.Y() : aPoints
.maEnd
.X()) += lclToMapUnit( nBOffs
);
925 // ----------------------------------------------------------------------------
926 // Clipping functions for diagonal frame borders.
928 /** Limits the clipping region to the inner area of a rectange.
930 Takes the values from the passed DiagLineResult struct into account. They
931 may specify to not clip one or more borders of a rectangle.
934 The output device with the clipping region to be modified. The old
935 clipping region is pushed onto the device's stack and can be restored
936 with a call to OutputDevice::Pop(). Please take care about the correct
937 calling order of Pop() if this function is used with other functions
938 pushing something onto the stack.
940 The reference rectangle of the diagonal frame borders.
942 The result struct containing modifies for each border of the reference
945 void lclPushDiagClipRect( OutputDevice
& rDev
, const Rectangle
& rRect
, const DiagLineResult
& rResult
)
947 // PixelToLogic() regards internal offset of the output device
948 Rectangle
aClipRect( rRect
);
949 aClipRect
.Left() += lclToMapUnit( rResult
.mnLClip
);
950 aClipRect
.Top() += lclToMapUnit( rResult
.mnTClip
);
951 aClipRect
.Right() += lclToMapUnit( rResult
.mnRClip
);
952 aClipRect
.Bottom() += lclToMapUnit( rResult
.mnBClip
);
953 // output device would adjust the rectangle -> invalidate it before
954 if( (aClipRect
.GetWidth() < 1) ||(aClipRect
.GetHeight() < 1) )
955 aClipRect
.SetEmpty();
957 rDev
.Push( PUSH_CLIPREGION
);
958 rDev
.IntersectClipRegion( aClipRect
);
961 /** Excludes inner area of a crossing double frame border from clipping region.
963 This function is used to modify the clipping region so that it excludes the
964 inner free area of a double diagonal frame border. This makes it possible
965 to draw a diagonal frame border in one step without taking care of the
966 crossing double frame border.
969 The output device with the clipping region to be modified. The old
970 clipping region is pushed onto the device's stack and can be restored
971 with a call to OutputDevice::Pop(). Please take care about the correct
972 calling order of Pop() if this function is used with other functions
973 pushing something onto the stack.
975 The reference rectangle of the diagonal frame borders.
977 The orientation of the processed frame border (not the orientation of
978 the crossing frame border).
980 The style of the crossing frame border. Must be a double frame style.
982 void lclPushCrossingClipRegion( OutputDevice
& rDev
, const Rectangle
& rRect
, bool bTLBR
, const Style
& rCrossStyle
)
984 DBG_ASSERT( rCrossStyle
.Secn(), "lclGetCrossingClipRegion - use only for double styles" );
985 LinePoints
aLPoints( lclGetDiagLineEnds( rRect
, !bTLBR
, lclGetPrimEnd( rCrossStyle
) ) );
986 LinePoints
aRPoints( lclGetDiagLineEnds( rRect
, !bTLBR
, lclGetSecnBeg( rCrossStyle
) ) );
991 aClipReg
= lclCreatePolygon(
992 aLPoints
.maBeg
, aLPoints
.maEnd
, rRect
.BottomRight(), rRect
.BottomLeft(), rRect
.TopLeft() );
993 aClipReg
.Union( lclCreatePolygon(
994 aRPoints
.maBeg
, aRPoints
.maEnd
, rRect
.BottomRight(), rRect
.TopRight(), rRect
.TopLeft() ) );
998 aClipReg
= lclCreatePolygon(
999 aLPoints
.maBeg
, aLPoints
.maEnd
, rRect
.BottomLeft(), rRect
.TopLeft(), rRect
.TopRight() );
1000 aClipReg
.Union( lclCreatePolygon(
1001 aRPoints
.maBeg
, aRPoints
.maEnd
, rRect
.BottomLeft(), rRect
.BottomRight(), rRect
.TopRight() ) );
1004 rDev
.Push( PUSH_CLIPREGION
);
1005 rDev
.IntersectClipRegion( aClipReg
);
1008 // ----------------------------------------------------------------------------
1009 // Drawing functions for diagonal frame borders.
1011 /** Draws a diagonal thin or thick line into the passed output device.
1013 The clipping region of the output device is modified according to the
1014 passed DiagLineResult struct. A one pixel wide line can be drawn dotted.
1016 void lclDrawDiagLine(
1017 OutputDevice
& rDev
, const Rectangle
& rRect
, bool bTLBR
,
1018 const DiagLineResult
& rResult
, long nDiagOffs1
, long nDiagOffs2
, SvxBorderStyle nDashing
)
1020 lclPushDiagClipRect( rDev
, rRect
, rResult
);
1021 LinePoints
aLPoints( lclGetDiagLineEnds( rRect
, bTLBR
, nDiagOffs1
) );
1022 LinePoints
aL2Points( lclGetDiagLineEnds( rRect
, bTLBR
, nDiagOffs2
) );
1023 Point
aSMid( ( aLPoints
.maBeg
+ aL2Points
.maBeg
) / 2 );
1024 Point
aEMid( ( aLPoints
.maEnd
+ aL2Points
.maEnd
) / 2 );
1026 sal_uInt32 nWidth
= lclToMapUnit( abs( nDiagOffs1
) ) + lclToMapUnit( abs( nDiagOffs2
) );
1027 if ( ( nDiagOffs1
<= 0 && nDiagOffs2
<= 0 ) || ( nDiagOffs1
>=0 && nDiagOffs2
>=0 ) )
1028 nWidth
= lclToMapUnit( abs( nDiagOffs1
- nDiagOffs2
) );
1030 svtools::DrawLine( rDev
, aSMid
, aEMid
, nWidth
, nDashing
);
1031 rDev
.Pop(); // clipping region
1034 /** Draws a diagonal frame border into the passed output device.
1036 The lines of the frame border are drawn interrupted, if the style of the
1037 crossing frame border is double.
1040 The reference rectangle of the diagonal frame border.
1042 The orientation of the diagonal frame border.
1044 The frame style used to draw the border.
1046 Offsets (sub units) to modify the clipping region of the output device.
1048 Style of the crossing diagonal frame border.
1050 void lclDrawDiagFrameBorder(
1051 OutputDevice
& rDev
, const Rectangle
& rRect
, bool bTLBR
,
1052 const Style
& rBorder
, const DiagBorderResult
& rResult
, const Style
& rCrossStyle
,
1053 const Color
* pForceColor
, bool bDiagDblClip
)
1055 DBG_ASSERT( rBorder
.Prim(), "svx::frame::lclDrawDiagFrameBorder - line not visible" );
1057 bool bClip
= bDiagDblClip
&& rCrossStyle
.Secn();
1059 lclPushCrossingClipRegion( rDev
, rRect
, bTLBR
, rCrossStyle
);
1061 lclSetColorToOutDev( rDev
, rBorder
.GetColorPrim(), pForceColor
);
1062 lclDrawDiagLine( rDev
, rRect
, bTLBR
, rResult
.maPrim
, lclGetBeg( rBorder
), lclGetPrimEnd( rBorder
), rBorder
.Type() );
1063 rDev
.Pop(); // colors
1064 if( rBorder
.Secn() )
1066 if ( rBorder
.UseGapColor( ) )
1068 lclSetColorToOutDev( rDev
, rBorder
.GetColorGap(), pForceColor
);
1069 lclDrawDiagLine( rDev
, rRect
, bTLBR
, rResult
.maSecn
, lclGetDistBeg( rBorder
), lclGetDistEnd( rBorder
), rBorder
.Type() );
1070 rDev
.Pop(); // colors
1073 lclSetColorToOutDev( rDev
, rBorder
.GetColorSecn(), pForceColor
);
1074 lclDrawDiagLine( rDev
, rRect
, bTLBR
, rResult
.maSecn
, lclGetSecnBeg( rBorder
), lclGetEnd( rBorder
), rBorder
.Type() );
1075 rDev
.Pop(); // colors
1079 rDev
.Pop(); // clipping region
1082 /** Draws both diagonal frame borders into the passed output device.
1084 The lines of each frame border is drawn interrupted, if the style of the
1085 other crossing frame border is double.
1088 The reference rectangle of the diagonal frame borders.
1090 The frame style of the top-left to bottom-right frame border.
1092 The frame style of the bottom-left to top-right frame border.
1094 Offsets (sub units) to modify the clipping region of the output device.
1096 void lclDrawDiagFrameBorders(
1097 OutputDevice
& rDev
, const Rectangle
& rRect
,
1098 const Style
& rTLBR
, const Style
& rBLTR
, const DiagBordersResult
& rResult
,
1099 const Color
* pForceColor
, bool bDiagDblClip
)
1101 DBG_ASSERT( (rRect
.GetWidth() > 1) && (rRect
.GetHeight() > 1), "svx::frame::lclDrawDiagFrameBorders - rectangle too small" );
1102 if( (rRect
.GetWidth() > 1) && (rRect
.GetHeight() > 1) )
1104 bool bDrawTLBR
= rTLBR
.Prim() != 0;
1105 bool bDrawBLTR
= rBLTR
.Prim() != 0;
1106 bool bFirstDrawBLTR
= rTLBR
.Secn() != 0;
1108 if( bDrawBLTR
&& bFirstDrawBLTR
)
1109 lclDrawDiagFrameBorder( rDev
, rRect
, false, rBLTR
, rResult
.maBLTR
, rTLBR
, pForceColor
, bDiagDblClip
);
1111 lclDrawDiagFrameBorder( rDev
, rRect
, true, rTLBR
, rResult
.maTLBR
, rBLTR
, pForceColor
, bDiagDblClip
);
1112 if( bDrawBLTR
&& !bFirstDrawBLTR
)
1113 lclDrawDiagFrameBorder( rDev
, rRect
, false, rBLTR
, rResult
.maBLTR
, rTLBR
, pForceColor
, bDiagDblClip
);
1117 // ============================================================================
1121 // ============================================================================
1123 // ============================================================================
1125 #define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth )
1129 Set( Color(), Color(), Color(), false, 0, 0, 0 );
1132 void Style::Set( double nP
, double nD
, double nS
)
1134 /* nP nD nS -> mnPrim mnDist mnSecn
1135 --------------------------------------
1141 mnPrim
= rtl::math::round(nP
? nP
: nS
, 2);
1142 mnDist
= rtl::math::round((nP
&& nS
) ? nD
: 0, 2);
1143 mnSecn
= rtl::math::round((nP
&& nD
) ? nS
: 0, 2);
1146 void Style::Set( const Color
& rColorPrim
, const Color
& rColorSecn
, const Color
& rColorGap
, bool bUseGapColor
, double nP
, double nD
, double nS
)
1148 maColorPrim
= rColorPrim
;
1149 maColorSecn
= rColorSecn
;
1150 maColorGap
= rColorGap
;
1151 mbUseGapColor
= bUseGapColor
;
1155 void Style::Set( const SvxBorderLine
& rBorder
, double fScale
, sal_uInt16 nMaxWidth
)
1157 maColorPrim
= rBorder
.GetColorOut();
1158 maColorSecn
= rBorder
.GetColorIn();
1159 maColorGap
= rBorder
.GetColorGap();
1160 mbUseGapColor
= rBorder
.HasGapColor();
1162 sal_uInt16 nPrim
= rBorder
.GetOutWidth();
1163 sal_uInt16 nDist
= rBorder
.GetDistance();
1164 sal_uInt16 nSecn
= rBorder
.GetInWidth();
1166 mnType
= rBorder
.GetBorderLineStyle();
1167 if( !nSecn
) // no or single frame border
1169 Set( SCALEVALUE( nPrim
), 0, 0 );
1173 Set( SCALEVALUE( nPrim
), SCALEVALUE( nDist
), SCALEVALUE( nSecn
) );
1174 // Enlarge the style if distance is too small due to rounding losses.
1175 double nPixWidth
= SCALEVALUE( nPrim
+ nDist
+ nSecn
);
1176 if( nPixWidth
> GetWidth() )
1177 mnDist
= nPixWidth
- mnPrim
- mnSecn
;
1178 // Shrink the style if it is too thick for the control.
1179 while( GetWidth() > nMaxWidth
)
1181 // First decrease space between lines.
1184 // Still too thick? Decrease the line widths.
1185 if( GetWidth() > nMaxWidth
)
1187 if( rtl::math::approxEqual(mnPrim
, 0.0) && rtl::math::approxEqual(mnPrim
, mnSecn
) )
1189 // Both lines equal - decrease both to keep symmetry.
1195 // Decrease each line for itself
1198 if( (GetWidth() > nMaxWidth
) && !rtl::math::approxEqual(mnSecn
, 0.0) )
1206 void Style::Set( const SvxBorderLine
* pBorder
, double fScale
, sal_uInt16 nMaxWidth
)
1209 Set( *pBorder
, fScale
, nMaxWidth
);
1213 mnType
= table::BorderLineStyle::SOLID
;
1217 Style
& Style::MirrorSelf()
1220 std::swap( mnPrim
, mnSecn
);
1221 if( meRefMode
!= REFMODE_CENTERED
)
1222 meRefMode
= (meRefMode
== REFMODE_BEGIN
) ? REFMODE_END
: REFMODE_BEGIN
;
1226 Style
Style::Mirror() const
1228 return Style( *this ).MirrorSelf();
1231 bool operator==( const Style
& rL
, const Style
& rR
)
1233 return (rL
.Prim() == rR
.Prim()) && (rL
.Dist() == rR
.Dist()) && (rL
.Secn() == rR
.Secn()) &&
1234 (rL
.GetColorPrim() == rR
.GetColorPrim()) && (rL
.GetColorSecn() == rR
.GetColorSecn()) &&
1235 (rL
.GetColorGap() == rR
.GetColorGap()) && (rL
.GetRefMode() == rR
.GetRefMode()) &&
1236 (rL
.UseGapColor() == rR
.UseGapColor() ) && (rL
.Type() == rR
.Type());
1239 bool operator<( const Style
& rL
, const Style
& rR
)
1241 // different total widths -> rL<rR, if rL is thinner
1242 double nLW
= rL
.GetWidth();
1243 double nRW
= rR
.GetWidth();
1244 if( nLW
!= nRW
) return nLW
< nRW
;
1246 // one line double, the other single -> rL<rR, if rL is single
1247 if( (rL
.Secn() == 0) != (rR
.Secn() == 0) ) return rL
.Secn() == 0;
1249 // both lines double with different distances -> rL<rR, if distance of rL greater
1250 if( (rL
.Secn() && rR
.Secn()) && (rL
.Dist() != rR
.Dist()) ) return rL
.Dist() > rR
.Dist();
1252 // both lines single and 1 unit thick, only one is dotted -> rL<rR, if rL is dotted
1253 if( (nLW
== 1) && (rL
.Type() != rR
.Type()) ) return rL
.Type();
1261 // ============================================================================
1262 // Various helper functions
1263 // ============================================================================
1265 double GetHorDiagAngle( long nWidth
, long nHeight
)
1267 return atan2( static_cast< double >( std::abs( nHeight
) ), static_cast< double >( std::abs( nWidth
) ) );
1270 // ============================================================================
1272 long GetTLDiagOffset( long nVerOffs
, long nDiagOffs
, double fAngle
)
1274 return lclD2L( nVerOffs
/ tan( fAngle
) + nDiagOffs
/ sin( fAngle
) );
1277 long GetBLDiagOffset( long nVerOffs
, long nDiagOffs
, double fAngle
)
1279 return lclD2L( -nVerOffs
/ tan( fAngle
) + nDiagOffs
/ sin( fAngle
) );
1282 long GetBRDiagOffset( long nVerOffs
, long nDiagOffs
, double fAngle
)
1284 return -lclD2L( -nVerOffs
/ tan( fAngle
) - nDiagOffs
/ sin( fAngle
) );
1287 long GetTRDiagOffset( long nVerOffs
, long nDiagOffs
, double fAngle
)
1289 return -lclD2L( nVerOffs
/ tan( fAngle
) - nDiagOffs
/ sin( fAngle
) );
1292 // ============================================================================
1294 bool CheckFrameBorderConnectable( const Style
& rLBorder
, const Style
& rRBorder
,
1295 const Style
& rTFromTL
, const Style
& rTFromT
, const Style
& rTFromTR
,
1296 const Style
& rBFromBL
, const Style
& rBFromB
, const Style
& rBFromBR
)
1298 return // returns 1 AND (2a OR 2b)
1299 // 1) only, if both frame borders are equal
1300 (rLBorder
== rRBorder
)
1304 // 2a) if the borders are not double, at least one of the vertical must not be double
1305 !rLBorder
.Secn() && (!rTFromT
.Secn() || !rBFromB
.Secn())
1309 // 2b) if the borders are double, all other borders must not be double
1311 !rTFromTL
.Secn() && !rTFromT
.Secn() && !rTFromTR
.Secn() &&
1312 !rBFromBL
.Secn() && !rBFromB
.Secn() && !rBFromBR
.Secn()
1317 // ============================================================================
1318 // Drawing functions
1319 // ============================================================================
1321 double lcl_GetExtent( const Style
& rBorder
, const Style
& rSide
, const Style
& rOpposite
,
1322 long nAngleSide
= 9000, long nAngleOpposite
= 9000 )
1324 Style aOtherBorder
= const_cast< Style
& >( rSide
);
1325 long nOtherAngle
= nAngleSide
;
1326 if ( rSide
.GetWidth() == 0 && rOpposite
.GetWidth() > 0 )
1328 nOtherAngle
= nAngleOpposite
;
1329 aOtherBorder
= const_cast< Style
& >( rOpposite
);
1331 else if ( rSide
.GetWidth() == 0 && rOpposite
.GetWidth() == 0 )
1333 if ( ( nAngleOpposite
% 18000 ) == 0 )
1334 nOtherAngle
= nAngleSide
;
1335 else if ( ( nAngleSide
% 18000 ) == 0 )
1336 nOtherAngle
= nAngleOpposite
;
1339 // Let's assume the border we are drawing is horizontal and compute all the angles / distances from this
1340 basegfx::B2DVector
aBaseVector( 1.0, 0.0 );
1341 basegfx::B2DPoint
aBasePoint( 0.0, static_cast<double>( rBorder
.GetWidth() / 2 ) );
1343 basegfx::B2DHomMatrix aRotation
;
1344 aRotation
.rotate( double( nOtherAngle
) * M_PI
/ 18000.0 );
1346 basegfx::B2DVector aOtherVector
= aRotation
* aBaseVector
;
1347 // Compute a line shifted by half the width of the other border
1348 basegfx::B2DVector aPerpendicular
= basegfx::getNormalizedPerpendicular( aOtherVector
);
1349 basegfx::B2DPoint aOtherPoint
= basegfx::B2DPoint() + aPerpendicular
* aOtherBorder
.GetWidth() / 2;
1351 // Find the cut between the two lines
1353 basegfx::tools::findCut(
1354 aBasePoint
, aBaseVector
, aOtherPoint
, aOtherVector
,
1355 CUTFLAG_ALL
, &nCut
);
1360 basegfx::B2DPoint
lcl_PointToB2DPoint( const Point aPoint
)
1362 return basegfx::B2DPoint( aPoint
.getX(), aPoint
.getY() );
1365 drawinglayer::primitive2d::Primitive2DSequence
CreateClippedBorderPrimitives (
1366 const Point
& rStart
, const Point
& rEnd
, const Style
& rBorder
,
1367 const Rectangle
& rClipRect
)
1369 drawinglayer::primitive2d::Primitive2DSequence
aSequence( 1 );
1370 basegfx::B2DPolygon aPolygon
;
1371 aPolygon
.append( lcl_PointToB2DPoint( rClipRect
.TopLeft( ) ) );
1372 aPolygon
.append( lcl_PointToB2DPoint( rClipRect
.TopRight( ) ) );
1373 aPolygon
.append( lcl_PointToB2DPoint( rClipRect
.BottomRight( ) ) );
1374 aPolygon
.append( lcl_PointToB2DPoint( rClipRect
.BottomLeft( ) ) );
1375 aPolygon
.setClosed( true );
1377 aSequence
[0] = new drawinglayer::primitive2d::ClippedBorderLinePrimitive2D(
1378 lcl_PointToB2DPoint( rStart
),
1379 lcl_PointToB2DPoint( rEnd
),
1384 rBorder
.GetColorSecn().getBColor(),
1385 rBorder
.GetColorPrim().getBColor(),
1386 rBorder
.GetColorGap().getBColor(),
1387 rBorder
.UseGapColor(), rBorder
.Type() );
1392 drawinglayer::primitive2d::Primitive2DSequence
CreateBorderPrimitives(
1393 const Point
& rLPos
, const Point
& rRPos
, const Style
& rBorder
,
1394 const DiagStyle
& /*rLFromTR*/, const Style
& rLFromT
, const Style
& /*rLFromL*/, const Style
& rLFromB
, const DiagStyle
& /*rLFromBR*/,
1395 const DiagStyle
& /*rRFromTL*/, const Style
& rRFromT
, const Style
& /*rRFromR*/, const Style
& rRFromB
, const DiagStyle
& /*rRFromBL*/,
1396 const Color
* /*pForceColor*/, const long& nRotateT
, const long& nRotateB
)
1398 drawinglayer::primitive2d::Primitive2DSequence
aSequence( 1 );
1400 basegfx::B2DPoint
aStart( rLPos
.getX(), rLPos
.getY() );
1401 basegfx::B2DPoint
aEnd( rRPos
.getX(), rRPos
.getY() );
1403 aSequence
[0] = new drawinglayer::primitive2d::BorderLinePrimitive2D(
1408 lcl_GetExtent( rBorder
, rLFromT
, rLFromB
, nRotateT
, - nRotateB
),
1409 lcl_GetExtent( rBorder
, rRFromT
, rRFromB
, 18000 - nRotateT
, nRotateB
- 18000 ),
1410 lcl_GetExtent( rBorder
, rLFromB
, rLFromT
, nRotateB
, - nRotateT
),
1411 lcl_GetExtent( rBorder
, rRFromB
, rRFromT
, 18000 - nRotateB
, nRotateT
- 18000 ),
1412 rBorder
.GetColorSecn().getBColor(),
1413 rBorder
.GetColorPrim().getBColor(),
1414 rBorder
.GetColorGap().getBColor(),
1415 rBorder
.UseGapColor(), rBorder
.Type() );
1420 drawinglayer::primitive2d::Primitive2DSequence
CreateBorderPrimitives(
1421 const Point
& rLPos
, const Point
& rRPos
, const Style
& rBorder
,
1422 const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
,
1423 const Style
& rRFromT
, const Style
& rRFromR
, const Style
& rRFromB
,
1424 const Color
* pForceColor
, const long& nRotateT
, const long& nRotateB
)
1426 return CreateBorderPrimitives( rLPos
, rRPos
, rBorder
,
1427 DiagStyle(), rLFromT
, rLFromL
, rLFromB
, DiagStyle(),
1428 DiagStyle(), rRFromT
, rRFromR
, rRFromB
, DiagStyle(),
1429 pForceColor
, nRotateT
, nRotateB
);
1432 void DrawHorFrameBorder( OutputDevice
& rDev
,
1433 const Point
& rLPos
, const Point
& rRPos
, const Style
& rBorder
,
1434 const DiagStyle
& rLFromTR
, const Style
& rLFromT
, const Style
& rLFromL
, const Style
& rLFromB
, const DiagStyle
& rLFromBR
,
1435 const DiagStyle
& rRFromTL
, const Style
& rRFromT
, const Style
& rRFromR
, const Style
& rRFromB
, const DiagStyle
& rRFromBL
,
1436 const Color
* pForceColor
)
1438 if( rBorder
.Prim() )
1440 BorderResult aResult
;
1441 lclLinkHorFrameBorder( aResult
, rBorder
,
1442 rLFromTR
, rLFromT
, rLFromL
, rLFromB
, rLFromBR
,
1443 rRFromTL
, rRFromT
, rRFromR
, rRFromB
, rRFromBL
);
1444 lclDrawHorFrameBorder( rDev
, rLPos
, rRPos
, rBorder
, aResult
, pForceColor
);
1448 // ----------------------------------------------------------------------------
1450 void DrawVerFrameBorder( OutputDevice
& rDev
,
1451 const Point
& rTPos
, const Point
& rBPos
, const Style
& rBorder
,
1452 const DiagStyle
& rTFromBL
, const Style
& rTFromL
, const Style
& rTFromT
, const Style
& rTFromR
, const DiagStyle
& rTFromBR
,
1453 const DiagStyle
& rBFromTL
, const Style
& rBFromL
, const Style
& rBFromB
, const Style
& rBFromR
, const DiagStyle
& rBFromTR
,
1454 const Color
* pForceColor
)
1456 if( rBorder
.Prim() )
1458 BorderResult aResult
;
1459 lclLinkVerFrameBorder( aResult
, rBorder
,
1460 rTFromBL
, rTFromL
, rTFromT
, rTFromR
, rTFromBR
,
1461 rBFromTL
, rBFromL
, rBFromB
, rBFromR
, rBFromTR
);
1462 lclDrawVerFrameBorder( rDev
, rTPos
, rBPos
, rBorder
, aResult
, pForceColor
);
1466 // ============================================================================
1468 void DrawDiagFrameBorders(
1469 OutputDevice
& rDev
, const Rectangle
& rRect
, const Style
& rTLBR
, const Style
& rBLTR
,
1470 const Style
& rTLFromB
, const Style
& rTLFromR
, const Style
& rBRFromT
, const Style
& rBRFromL
,
1471 const Style
& rBLFromT
, const Style
& rBLFromR
, const Style
& rTRFromB
, const Style
& rTRFromL
,
1472 const Color
* pForceColor
, bool bDiagDblClip
)
1474 if( rTLBR
.Prim() || rBLTR
.Prim() )
1476 DiagBordersResult aResult
;
1477 lclLinkDiagFrameBorders( aResult
, rTLBR
, rBLTR
,
1478 rTLFromB
, rTLFromR
, rBRFromT
, rBRFromL
, rBLFromT
, rBLFromR
, rTRFromB
, rTRFromL
);
1479 lclDrawDiagFrameBorders( rDev
, rRect
, rTLBR
, rBLTR
, aResult
, pForceColor
, bDiagDblClip
);
1483 // ============================================================================
1485 } // namespace frame
1488 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */