merge the formfield patch from ooo-build
[ooovba.git] / svx / source / dialog / framelink.cxx
blob2fe4d8187d9254390c90f1d66fea00905e2b46a9
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: framelink.cxx,v $
10 * $Revision: 1.10 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <svx/framelink.hxx>
35 #include <math.h>
36 #include <vcl/outdev.hxx>
37 #include <svx/borderline.hxx>
39 // ----------------------------------------------------------------------------
41 /** Define to select the drawing mode of thin dotted lines.
43 0 = Draw lines using an own implementation (recommended). Draws always
44 little dots in an appropriate distance.
45 1 = Draw dotted lines using vcl/LineInfo. Results in dashed lines instead
46 of dotted lines, which may look ugly for diagonal lines.
48 #define SVX_FRAME_USE_LINEINFO 0
50 // ----------------------------------------------------------------------------
52 #if SVX_FRAME_USE_LINEINFO
53 #include <vcl/lineinfo.hxx>
54 #endif
56 namespace svx {
57 namespace frame {
59 // ============================================================================
60 // ============================================================================
62 namespace {
64 typedef std::vector< Point > PointVec;
66 // ----------------------------------------------------------------------------
67 // Link result structs for horizontal and vertical lines and borders.
69 /** Result struct used by the horizontal/vertical frame link functions.
71 This struct is used to return coordinate offsets for one end of a single
72 line in a frame border, i.e. the left end of the primary line of a
73 horizontal frame border.
75 1) Usage for horizontal lines
77 If this struct is returned by the lclLinkHorFrameBorder() function, each
78 member refers to the X coordinate of one edge of a single line end in a
79 horizontal frame border. They specify an offset to modify this coordinate
80 when the line is painted. The values in this struct may change a
81 rectangular line shape into a line with slanted left or right border, which
82 is used to connect the line with diagonal lines.
84 Usage for a left line end: Usage for a right line end:
85 mnOffs1 mnOffs1
86 <-------> <------->
87 +-------------------------------+
88 | the original horizontal line |
89 +-------------------------------+
90 <-------> <------->
91 mnOffs2 mnOffs2
93 2) Usage for vertical lines
95 If this struct is returned by the lclLinkVerFrameBorder() function, each
96 member refers to the Y coordinate of one edge of a single line end in a
97 vertical frame border. They specify an offset to modify this coordinate
98 when the line is painted. The values in this struct may change a
99 rectangular line shape into a line with slanted top or bottom border, which
100 is used to connect the line with diagonal lines.
102 Usage for a top line end: mnOffs1 ^ ^ mnOffs2
103 | +-------+ |
104 v | | v
107 the original vertical line ---> | |
110 ^ | | ^
111 | +-------+ |
112 Usage for a bottom line end: mnOffs1 v v mnOffs2
114 struct LineEndResult
116 long mnOffs1; /// Offset for top or left edge, dependent of context.
117 long mnOffs2; /// Offset for bottom or right edge, dependent of context
119 inline explicit LineEndResult() : mnOffs1( 0 ), mnOffs2( 0 ) {}
121 inline void Swap() { std::swap( mnOffs1, mnOffs2 ); }
122 inline void Negate() { mnOffs1 = -mnOffs1; mnOffs2 = -mnOffs2; }
125 /** Result struct used by the horizontal/vertical frame link functions.
127 This struct contains the linking results for one end of a frame border,
128 including both the primary and secondary line ends.
130 struct BorderEndResult
132 LineEndResult maPrim; /// Result for primary line.
133 LineEndResult maSecn; /// Result for secondary line.
135 inline void Negate() { maPrim.Negate(); maSecn.Negate(); }
138 /** Result struct used by the horizontal/vertical frame link functions.
140 This struct contains the linking results for both frame border ends, and
141 therefore for the complete frame border.
143 struct BorderResult
145 BorderEndResult maBeg; /// Result for begin of border line (left or top end).
146 BorderEndResult maEnd; /// Result for end of border line (right or bottom end).
149 // ----------------------------------------------------------------------------
150 // Link result structs for diagonal lines and borders.
152 /** Result struct used by the diagonal frame link functions.
154 This struct contains the linking results for one line of a diagonal frame
155 border.
157 struct DiagLineResult
159 long mnLClip; /// Offset for left border of clipping rectangle.
160 long mnRClip; /// Offset for right border of clipping rectangle.
161 long mnTClip; /// Offset for top border of clipping rectangle.
162 long mnBClip; /// Offset for bottom border of clipping rectangle.
164 inline explicit DiagLineResult() : mnLClip( 0 ), mnRClip( 0 ), mnTClip( 0 ), mnBClip( 0 ) {}
167 /** Result struct used by the diagonal frame link functions.
169 This struct contains the linking results for one diagonal frame border.
171 struct DiagBorderResult
173 DiagLineResult maPrim; /// Result for primary line.
174 DiagLineResult maSecn; /// Result for secondary line.
177 /** Result struct used by the diagonal frame link functions.
179 This struct contains the linking results for both diagonal frame borders.
181 struct DiagBordersResult
183 DiagBorderResult maTLBR; /// Result for top-left to bottom-right frame border.
184 DiagBorderResult maBLTR; /// Result for bottom-left to top-right frame border.
187 // ----------------------------------------------------------------------------
189 /** A helper struct containing two points of a line.
191 struct LinePoints
193 Point maBeg; /// Start position of the line.
194 Point maEnd; /// End position of the line.
196 explicit LinePoints( const Point& rBeg, const Point& rEnd ) :
197 maBeg( rBeg ), maEnd( rEnd ) {}
198 explicit LinePoints( const Rectangle& rRect, bool bTLBR ) :
199 maBeg( bTLBR ? rRect.TopLeft() : rRect.TopRight() ),
200 maEnd( bTLBR ? rRect.BottomRight() : rRect.BottomLeft() ) {}
203 // ============================================================================
205 /** Rounds and casts a double value to a long value. */
206 inline long lclD2L( double fValue )
208 return static_cast< long >( (fValue < 0.0) ? (fValue - 0.5) : (fValue + 0.5) );
211 /** Converts a width in twips to a width in another map unit (specified by fScale). */
212 sal_uInt16 lclScaleValue( long nValue, double fScale, sal_uInt16 nMaxWidth )
214 // convert any width except 0 to at least 1 unit
215 // #i61324# 1 twip must scale to 1/100mm
216 return nValue ? static_cast< sal_uInt16 >( std::min< long >( std::max(
217 static_cast< long >( nValue * fScale ), 1L ), nMaxWidth ) ) : 0;
220 // ----------------------------------------------------------------------------
221 // Line width offset calculation.
223 /** Returns the start offset of the single/primary line across the frame border.
225 All following lclGet*Beg() and lclGet*End() functions return sub units to
226 increase the computational accuracy, where 256 sub units are equal to
227 1 map unit of the used OutputDevice.
229 The following pictures show the upper end of a vertical frame border and
230 illustrates the return values of all following lclGet*Beg() and lclGet*End()
231 functions. The first picture shows a single frame border, the second picture
232 shows a double frame border.
234 The functions regard the reference point handling mode of the passed border
235 style.
236 REFMODE_CENTERED:
237 All returned offsets are relative to the middle position of the frame
238 border (offsets left of the middle are returned negative, offsets right
239 of the middle are returned positive).
240 REFMODE_BEGIN:
241 All returned offsets are relative to the begin of the frame border
242 (lclGetBeg() always returns 0).
243 REFMODE_END:
244 All returned offsets are relative to the end of the frame border
245 (lclGetEnd() always returns 0).
247 |<- lclGetEnd()
248 |<- lclGetBeforeBeg() |<- lclGetPrimEnd()
250 ||<- lclGetBeg() ||<- lclGetBehindEnd()
251 || ||
252 |#################################|
253 direction of | #################################
254 the frame | #################################
255 border is | #################################
256 vertical | #################################
257 v #################################
259 |<- middle of the frame border
262 lclGetDistEnd() ->||<- lclGetSecnBeg()
264 lclGetBeg() ->| lclGetDistBeg() ->| || |<- lclGetEnd()
265 | | || |
266 lclGetBeforeBeg()->|| lclGetPrimEnd() ->|| || ||<- lclGetBehindEnd()
267 || || || ||
268 |######################| |#############|
269 direction of | ###################### #############
270 the frame | ###################### #############
271 border is | ###################### #############
272 vertical | ###################### | #############
273 v ###################### | #############
274 primary line | secondary line
276 |<- middle of the frame border
278 @return
279 The start offset of the single/primary line relative to the reference
280 position of the frame border (sub units; 0 for invisible or one pixel
281 wide single frame styles).
283 long lclGetBeg( const Style& rBorder )
285 long nPos = 0;
286 switch( rBorder.GetRefMode() )
288 case REFMODE_CENTERED: if( rBorder.Prim() ) nPos = -128 * (rBorder.GetWidth() - 1); break;
289 case REFMODE_END: if( rBorder.Prim() ) nPos = -256 * (rBorder.GetWidth() - 1); break;
290 case REFMODE_BEGIN: break;
292 return nPos;
295 /** Returns the end offset of the single/secondary line across the frame border.
296 @descr See description of lclGetBeg() for an illustration.
297 @return The end offset of the single/secondary line relative to the
298 reference position of the frame border (sub units; 0 for invisible or one
299 pixel wide single frame styles). */
300 long lclGetEnd( const Style& rBorder )
302 long nPos = 0;
303 switch( rBorder.GetRefMode() )
305 case REFMODE_CENTERED: if( rBorder.Prim() ) nPos = 128 * (rBorder.GetWidth() - 1); break;
306 case REFMODE_BEGIN: if( rBorder.Prim() ) nPos = 256 * (rBorder.GetWidth() - 1); break;
307 case REFMODE_END: break;
309 return nPos;
312 /** Returns the end offset of the primary line across the frame border.
313 @descr See description of lclGetBeg() for an illustration.
314 @return The end offset of the primary line relative to the reference
315 position of the frame border (sub units; the end of the primary line in a
316 double frame style, otherwise the same as lclGetEnd()). */
317 inline long lclGetPrimEnd( const Style& rBorder )
318 { return rBorder.Prim() ? (lclGetBeg( rBorder ) + 256 * (rBorder.Prim() - 1)) : 0; }
320 /** Returns the start offset of the secondary line across the frame border.
321 @descr See description of lclGetBeg() for an illustration.
322 @return The start offset of the secondary line relative to the reference
323 position of the frame border (sub units; 0 for single/invisible border
324 styles). */
325 inline long lclGetSecnBeg( const Style& rBorder )
326 { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * (rBorder.Secn() - 1)) : 0; }
328 /** Returns the start offset of the distance space across the frame border.
329 @descr See description of lclGetBeg() for an illustration.
330 @return The start offset of the distance space relative to the reference
331 position of the frame border (sub units; 0 for single/invisible border
332 styles). */
333 inline long lclGetDistBeg( const Style& rBorder )
334 { return rBorder.Secn() ? (lclGetBeg( rBorder ) + 256 * rBorder.Prim()) : 0; }
336 /** Returns the end offset of the distance space across the frame border.
337 @descr See description of lclGetBeg() for an illustration.
338 @return The end offset of the distance space relative to the reference
339 position of the frame border (sub units; 0 for single/invisible border
340 styles). */
341 inline long lclGetDistEnd( const Style& rBorder )
342 { return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * rBorder.Secn()) : 0; }
344 /** Returns the offset before start of single/primary line across the frame border.
345 @descr See description of lclGetBeg() for an illustration.
346 @return The offset directly before start of single/primary line relative
347 to the reference position of the frame border (sub units; a value one less
348 than lclGetBeg() for visible frame styles, or 0 for invisible frame style). */
349 inline long lclGetBeforeBeg( const Style& rBorder )
350 { return rBorder.Prim() ? (lclGetBeg( rBorder ) - 256) : 0; }
352 /** Returns the offset behind end of single/secondary line across the frame border.
353 @descr See description of lclGetBeg() for an illustration.
354 @return The offset directly behind end of single/secondary line relative
355 to the reference position of the frame border (sub units; a value one
356 greater than lclGetEnd() for visible frame styles, or 0 for invisible frame
357 style). */
358 inline long lclGetBehindEnd( const Style& rBorder )
359 { return rBorder.Prim() ? (lclGetEnd( rBorder ) + 256) : 0; }
361 // ============================================================================
362 // Linking functions
363 // ============================================================================
365 // ----------------------------------------------------------------------------
366 // Linking of single horizontal line ends.
368 /** Calculates X offsets for the left end of a single horizontal frame border.
370 See DrawHorFrameBorder() function for a description of all parameters.
372 @param rResult
373 (out-param) The contained values (sub units) specify offsets for the
374 X coordinates of the left line end.
376 void lclLinkLeftEnd_Single(
377 LineEndResult& rResult, const Style& rBorder,
378 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
380 // both vertical and diagonal frame borders are double
381 if( rLFromT.Secn() && rLFromB.Secn() && rLFromTR.Secn() && rLFromBR.Secn() )
383 // take left position of upper and lower secondary start
384 rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
385 rResult.mnOffs2 = GetTLDiagOffset( lclGetEnd( rBorder ), lclGetSecnBeg( rLFromBR ), rLFromBR.GetAngle() );
387 else
389 // both vertical frame borders are double
390 if( rLFromT.Secn() && rLFromB.Secn() )
391 rResult.mnOffs1 = (!rLFromTR.Secn() && !rLFromBR.Secn() && (rLFromT.GetWidth() == rLFromB.GetWidth())) ?
392 // don't overdraw vertical borders with equal width
393 lclGetBehindEnd( rLFromT ) :
394 // take leftmost start of both secondary lines (#46488#)
395 rResult.mnOffs1 = std::min( lclGetSecnBeg( rLFromT ), lclGetSecnBeg( rLFromB ) );
397 // single border with equal width coming from left
398 else if( !rLFromL.Secn() && (rLFromL.Prim() == rBorder.Prim()) )
399 // draw to connection point
400 rResult.mnOffs1 = 0;
402 // single border coming from left
403 else if( !rLFromL.Secn() && rLFromL.Prim() )
405 if( rLFromL.Prim() == rBorder.Prim() )
406 // draw to reference position, if from left has equal width
407 rResult.mnOffs1 = 0;
408 else
409 rResult.mnOffs1 = (rLFromL < rBorder) ?
410 // take leftmost start of both frame borders, if from left is thinner
411 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
412 // do not overdraw vertical, if from left is thicker
413 std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
416 // no border coming from left
417 else if( !rLFromL.Prim() )
418 // don't overdraw vertical borders with equal width
419 rResult.mnOffs1 = (rLFromT.GetWidth() == rLFromB.GetWidth()) ?
420 lclGetBehindEnd( rLFromT ) :
421 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) );
423 // double frame border coming from left and from top
424 else if( rLFromT.Secn() )
425 // do not overdraw the vertical double frame border
426 rResult.mnOffs1 = lclGetBehindEnd( rLFromT );
428 // double frame border coming from left and from bottom
429 else if( rLFromB.Secn() )
430 // do not overdraw the vertical double frame border
431 rResult.mnOffs1 = lclGetBehindEnd( rLFromB );
433 // double frame border coming from left, both vertical frame borders are single or off
434 else
435 // draw from leftmost start of both frame borders, if from left is not thicker
436 rResult.mnOffs1 = (rLFromL <= rBorder) ?
437 std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
438 std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
440 // bottom-left point is equal to top-left point (results in rectangle)
441 rResult.mnOffs2 = rResult.mnOffs1;
445 /** Calculates X offsets for the left end of a primary horizontal line.
447 See DrawHorFrameBorder() function for a description of all parameters.
449 @param rResult
450 (out-param) The contained values (sub units) specify offsets for the
451 X coordinates of the left end of the primary line.
453 void lclLinkLeftEnd_Prim(
454 LineEndResult& rResult, const Style& rBorder,
455 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ )
457 // double diagonal frame border coming from top right
458 if( rLFromTR.Secn() )
460 // draw from where secondary diagonal line meets the own primary
461 rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
462 rResult.mnOffs2 = GetBLDiagOffset( lclGetPrimEnd( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
465 // no or single diagonal frame border - ignore it
466 else
468 // double frame border coming from top
469 if( rLFromT.Secn() )
470 // draw from left edge of secondary vertical
471 rResult.mnOffs1 = lclGetSecnBeg( rLFromT );
473 // double frame border coming from left (from top is not double)
474 else if( rLFromL.Secn() )
475 // do not overdraw single frame border coming from top
476 rResult.mnOffs1 = (rLFromL.GetWidth() == rBorder.GetWidth()) ?
477 0 : lclGetBehindEnd( rLFromT );
479 // double frame border coming from bottom (from top and from left are not double)
480 else if( rLFromB.Secn() )
481 // draw from left edge of primary vertical from bottom
482 rResult.mnOffs1 = lclGetBeg( rLFromB );
484 // no other frame border is double
485 else
486 // do not overdraw vertical frame borders
487 rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
489 // bottom-left point is equal to top-left point (results in rectangle)
490 rResult.mnOffs2 = rResult.mnOffs1;
494 /** Calculates X offsets for the left end of a secondary horizontal line.
496 See DrawHorFrameBorder() function for a description of all parameters.
498 @param rResult
499 (out-param) The contained values (sub units) specify offsets for the
500 X coordinates of the left end of the secondary line.
502 void lclLinkLeftEnd_Secn(
503 LineEndResult& rResult, const Style& rBorder,
504 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
506 /* Recycle lclLinkLeftEnd_Prim() function with mirrored horizontal borders. */
507 lclLinkLeftEnd_Prim( rResult, rBorder.Mirror(), rLFromBR, rLFromB, rLFromL.Mirror(), rLFromT, rLFromTR );
508 rResult.Swap();
511 // ----------------------------------------------------------------------------
512 // Linking of horizontal frame border ends.
514 /** Calculates X offsets for the left end of a horizontal frame border.
516 This function can be used for single and double frame borders.
517 See DrawHorFrameBorder() function for a description of all parameters.
519 @param rResult
520 (out-param) The contained values (sub units) specify offsets for the
521 X coordinates of the left end of the line(s) in the frame border.
523 void lclLinkLeftEnd(
524 BorderEndResult& rResult, const Style& rBorder,
525 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
527 if( rBorder.Secn() )
529 // current frame border is double
530 lclLinkLeftEnd_Prim( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
531 lclLinkLeftEnd_Secn( rResult.maSecn, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
533 else if( rBorder.Prim() )
535 // current frame border is single
536 lclLinkLeftEnd_Single( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
538 else
540 DBG_ERRORFILE( "lclLinkLeftEnd - called for invisible frame style" );
544 /** Calculates X offsets for the right end of a horizontal frame border.
546 This function can be used for single and double frame borders.
547 See DrawHorFrameBorder() function for a description of all parameters.
549 @param rResult
550 (out-param) The contained values (sub units) specify offsets for the
551 X coordinates of the right end of the line(s) in the frame border.
553 void lclLinkRightEnd(
554 BorderEndResult& rResult, const Style& rBorder,
555 const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
557 /* Recycle lclLinkLeftEnd() function with mirrored vertical borders. */
558 lclLinkLeftEnd( rResult, rBorder, rRFromTL.Mirror(), rRFromT.Mirror(), rRFromR, rRFromB.Mirror(), rRFromBL.Mirror() );
559 rResult.Negate();
562 // ----------------------------------------------------------------------------
563 // Linking of horizontal and vertical frame borders.
565 /** Calculates X offsets for all line ends of a horizontal frame border.
567 This function can be used for single and double frame borders.
568 See DrawHorFrameBorder() function for a description of all parameters.
570 @param rResult
571 (out-param) The contained values (sub units) specify offsets for the
572 X coordinates of both ends of the line(s) in the frame border. To get
573 the actual X coordinates to draw the lines, these offsets have to be
574 added to the X coordinates of the reference points of the frame border
575 (the offsets may be negative).
577 void lclLinkHorFrameBorder(
578 BorderResult& rResult, const Style& rBorder,
579 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
580 const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
582 lclLinkLeftEnd( rResult.maBeg, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
583 lclLinkRightEnd( rResult.maEnd, rBorder, rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
586 /** Calculates Y offsets for all line ends of a vertical frame border.
588 This function can be used for single and double frame borders.
589 See DrawVerFrameBorder() function for a description of all parameters.
591 @param rResult
592 (out-param) The contained values (sub units) specify offsets for the
593 Y coordinates of both ends of the line(s) in the frame border. To get
594 the actual Y coordinates to draw the lines, these offsets have to be
595 added to the Y coordinates of the reference points of the frame border
596 (the offsets may be negative).
598 void lclLinkVerFrameBorder(
599 BorderResult& rResult, const Style& rBorder,
600 const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
601 const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR )
603 /* Recycle lclLinkHorFrameBorder() function with correct parameters. The
604 frame border is virtually mirrored at the top-left to bottom-right
605 diagonal. rTFromBR and rBFromTL are mirrored to process their primary
606 and secondary lines correctly. */
607 lclLinkHorFrameBorder( rResult, rBorder,
608 rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR.Mirror(),
609 rBFromTL.Mirror(), rBFromL, rBFromB, rBFromR, rBFromTR );
612 // ============================================================================
614 #if 0
615 // Not used anymore, but not deleted for possible future usage.
617 /** Returns the relative Y offset of the intercept point of 2 diagonal borders.
619 @param nTLBROffs
620 Width offset (sub units) across the top-left to bottom-right frame border.
621 @param fTLBRAngle
622 Inner angle between horizontal and top-left to bottom-right frame border.
623 @param nBLTROffs
624 Width offset (sub units) across the bottom-left to top-right frame border.
625 @param fBLTRAngle
626 Inner angle between horizontal and bottom-left to top-right frame border.
627 @return
628 Offset (sub units) relative to the Y position of the centered intercept
629 point of both diagonal frame borders.
631 long lclGetDiagDiagOffset( long nTLBROffs, double fTLBRAngle, long nBLTROffs, double fBLTRAngle )
633 double fASin = sin( fTLBRAngle );
634 double fACos = cos( fTLBRAngle );
635 double fAX = -nTLBROffs * fASin;
636 double fAY = nTLBROffs * fACos;
637 double fRAX = fACos;
638 double fRAY = fASin;
640 double fBSin = sin( fBLTRAngle );
641 double fBCos = cos( fBLTRAngle );
642 double fBX = nBLTROffs * fBSin;
643 double fBY = nBLTROffs * fBCos;
644 double fRBX = fBCos;
645 double fRBY = -fBSin;
647 double fKA = (fRBX * (fBY - fAY) - fRBY * (fBX - fAX)) / (fRBX * fRAY - fRAX * fRBY);
648 return lclD2L( fAY + fKA * fRAY );
650 #endif
652 // ----------------------------------------------------------------------------
653 // Linking of diagonal frame borders.
655 /** Calculates clipping offsets for a top-left to bottom-right frame border.
657 This function can be used for single and double frame borders.
658 See DrawDiagFrameBorders() function for a description of all parameters.
660 @param rResult
661 (out-param) The contained values (sub units) specify offsets for all
662 borders of the reference rectangle containing the diagonal frame border.
664 void lclLinkTLBRFrameBorder(
665 DiagBorderResult& rResult, const Style& rBorder,
666 const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL )
668 bool bIsDbl = rBorder.Secn() != 0;
670 rResult.maPrim.mnLClip = lclGetBehindEnd( rTLFromB );
671 rResult.maPrim.mnRClip = (bIsDbl && rBRFromT.Secn()) ? lclGetEnd( rBRFromT ) : lclGetBeforeBeg( rBRFromT );
672 rResult.maPrim.mnTClip = (bIsDbl && rTLFromR.Secn()) ? lclGetBeg( rTLFromR ) : lclGetBehindEnd( rTLFromR );
673 rResult.maPrim.mnBClip = lclGetBeforeBeg( rBRFromL );
675 if( bIsDbl )
677 rResult.maSecn.mnLClip = rTLFromB.Secn() ? lclGetBeg( rTLFromB ) : lclGetBehindEnd( rTLFromB );
678 rResult.maSecn.mnRClip = lclGetBeforeBeg( rBRFromT );
679 rResult.maSecn.mnTClip = lclGetBehindEnd( rTLFromR );
680 rResult.maSecn.mnBClip = rBRFromL.Secn() ? lclGetEnd( rBRFromL ) : lclGetBeforeBeg( rBRFromL );
684 /** Calculates clipping offsets for a bottom-left to top-right frame border.
686 This function can be used for single and double frame borders.
687 See DrawDiagFrameBorders() function for a description of all parameters.
689 @param rResult
690 (out-param) The contained values (sub units) specify offsets for all
691 borders of the reference rectangle containing the diagonal frame border.
693 void lclLinkBLTRFrameBorder(
694 DiagBorderResult& rResult, const Style& rBorder,
695 const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
697 bool bIsDbl = rBorder.Secn() != 0;
699 rResult.maPrim.mnLClip = lclGetBehindEnd( rBLFromT );
700 rResult.maPrim.mnRClip = (bIsDbl && rTRFromB.Secn()) ? lclGetEnd( rTRFromB ) : lclGetBeforeBeg( rTRFromB );
701 rResult.maPrim.mnTClip = lclGetBehindEnd( rTRFromL );
702 rResult.maPrim.mnBClip = (bIsDbl && rBLFromR.Secn()) ? lclGetEnd( rBLFromR ) : lclGetBeforeBeg( rBLFromR );
704 if( bIsDbl )
706 rResult.maSecn.mnLClip = rBLFromT.Secn() ? lclGetBeg( rBLFromT ) : lclGetBehindEnd( rBLFromT );
707 rResult.maSecn.mnRClip = lclGetBeforeBeg( rTRFromB );
708 rResult.maSecn.mnTClip = rTRFromL.Secn() ? lclGetBeg( rTRFromL ) : lclGetBehindEnd( rTRFromL );
709 rResult.maSecn.mnBClip = lclGetBeforeBeg( rBLFromR );
713 /** Calculates clipping offsets for both diagonal frame borders.
715 This function can be used for single and double frame borders.
716 See DrawDiagFrameBorders() function for a description of all parameters.
718 @param rResult
719 (out-param) The contained values (sub units) specify offsets for all
720 borders of the reference rectangle containing the diagonal frame
721 borders.
723 void lclLinkDiagFrameBorders(
724 DiagBordersResult& rResult, const Style& rTLBR, const Style& rBLTR,
725 const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
726 const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
728 lclLinkTLBRFrameBorder( rResult.maTLBR, rTLBR, rTLFromB, rTLFromR, rBRFromT, rBRFromL );
729 lclLinkBLTRFrameBorder( rResult.maBLTR, rBLTR, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
732 // ============================================================================
733 // Drawing functions
734 // ============================================================================
736 // ----------------------------------------------------------------------------
737 // Simple helper functions
739 /** Converts sub units to OutputDevice map units. */
740 inline long lclToMapUnit( long nSubUnits )
742 return ((nSubUnits < 0) ? (nSubUnits - 127) : (nSubUnits + 128)) / 256;
745 /** Converts a point in sub units to an OutputDevice point. */
746 inline Point lclToMapUnit( long nSubXPos, long nSubYPos )
748 return Point( lclToMapUnit( nSubXPos ), lclToMapUnit( nSubYPos ) );
751 /** Returns a polygon constructed from a vector of points. */
752 inline Polygon lclCreatePolygon( const PointVec& rPoints )
754 return Polygon( static_cast< USHORT >( rPoints.size() ), &rPoints[ 0 ] );
757 /** Returns a polygon constructed from the four passed points. */
758 Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 )
760 PointVec aPoints;
761 aPoints.reserve( 4 );
762 aPoints.push_back( rP1 );
763 aPoints.push_back( rP2 );
764 aPoints.push_back( rP3 );
765 aPoints.push_back( rP4 );
766 return lclCreatePolygon( aPoints );
769 /** Returns a polygon constructed from the five passed points. */
770 Polygon lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4, const Point& rP5 )
772 PointVec aPoints;
773 aPoints.reserve( 5 );
774 aPoints.push_back( rP1 );
775 aPoints.push_back( rP2 );
776 aPoints.push_back( rP3 );
777 aPoints.push_back( rP4 );
778 aPoints.push_back( rP5 );
779 return lclCreatePolygon( aPoints );
782 /** Returns a polygon constructed from the two passed line positions. */
783 inline Polygon lclCreatePolygon( const LinePoints& rPoints1, const LinePoints& rPoints2 )
785 return lclCreatePolygon( rPoints1.maBeg, rPoints1.maEnd, rPoints2.maEnd, rPoints2.maBeg );
788 /** Sets the color of the passed frame style to the output device.
790 Sets the line color and fill color in the output device.
792 @param rDev
793 The output device the color has to be set to. The old colors are pushed
794 onto the device's stack and can be restored with a call to
795 OutputDevice::Pop(). Please take care about the correct calling order
796 of Pop() if this function is used with other functions pushing
797 something onto the stack.
798 @param rStyle
799 The border style that contains the line color to be set to the device.
801 void lclSetColorToOutDev( OutputDevice& rDev, const Style& rStyle, const Color* pForceColor )
803 rDev.Push( PUSH_LINECOLOR | PUSH_FILLCOLOR );
804 rDev.SetLineColor( pForceColor ? *pForceColor : rStyle.GetColor() );
805 rDev.SetFillColor( pForceColor ? *pForceColor : rStyle.GetColor() );
808 // ----------------------------------------------------------------------------
809 // Generic drawing functions.
811 /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */
812 void lclDrawThinLine( OutputDevice& rDev, const Point& rBeg, const Point& rEnd, bool bDotted )
814 #if SVX_FRAME_USE_LINEINFO
815 if( bDotted && (rBeg != rEnd) )
817 // using LineInfo for dotted lines looks ugly and does not work well for diagonal lines
818 LineInfo aLineInfo( LINE_DASH, 1 );
819 aLineInfo.SetDotCount( 1 );
820 aLineInfo.SetDotLen( 1 );
821 aLineInfo.SetDistance( 3 );
822 rDev.DrawLine( rBeg, rEnd, aLineInfo );
824 #else
825 Point aBeg( rDev.LogicToPixel( rBeg ) );
826 Point aEnd( rDev.LogicToPixel( rEnd ) );
827 if( bDotted && (aBeg != aEnd) )
829 bool bHor = Abs( aEnd.X() - aBeg.X() ) > Abs( aEnd.Y() - aBeg.Y() );
830 const Point& rBegPos( bHor ? ((aBeg.X() < aEnd.X()) ? aBeg : aEnd) : ((aBeg.Y() < aEnd.Y()) ? aBeg : aEnd ) );
831 const Point& rEndPos( (rBegPos == aBeg) ? aEnd : aBeg );
833 long nAlongBeg = bHor ? rBegPos.X() : rBegPos.Y();
834 long nAcrssBeg = bHor ? rBegPos.Y() : rBegPos.X();
835 long nAlongSize = (bHor ? rEndPos.X() : rEndPos.Y()) - nAlongBeg;
836 long nAcrssSize = (bHor ? rEndPos.Y() : rEndPos.X()) - nAcrssBeg;
837 double fGradient = static_cast< double >( nAcrssSize ) / nAlongSize;
839 PointVec aPoints;
840 aPoints.reserve( (nAlongSize + 1) / 2 );
841 for( long nAlongIdx = 0; nAlongIdx <= nAlongSize; nAlongIdx += 2 )
843 long nAl = nAlongBeg + nAlongIdx;
844 long nAc = nAcrssBeg + lclD2L( fGradient * nAlongIdx );
845 aPoints.push_back( Point( bHor ? nAl : nAc, bHor ? nAc : nAl ) );
848 rDev.Push( PUSH_MAPMODE );
849 rDev.SetMapMode( MAP_PIXEL );
850 rDev.DrawPixel( lclCreatePolygon( aPoints ) );
851 rDev.Pop(); // map mode
853 #endif
854 else
855 rDev.DrawLine( rBeg, rEnd );
858 /** Draws a thin (1 pixel wide) line, optionally dotted, into the passed output device. */
859 inline void lclDrawThinLine( OutputDevice& rDev, const LinePoints& rPoints, bool bDotted )
861 lclDrawThinLine( rDev, rPoints.maBeg, rPoints.maEnd, bDotted );
864 /** Draws a polygon with four points into the passed output device. */
865 inline void lclDrawPolygon( OutputDevice& rDev, const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4 )
867 rDev.DrawPolygon( lclCreatePolygon( rP1, rP2, rP3, rP4 ) );
870 /** Draws a polygon specified by two borders into the passed output device. */
871 inline void lclDrawPolygon( OutputDevice& rDev, const LinePoints& rPoints1, const LinePoints& rPoints2 )
873 rDev.DrawPolygon( lclCreatePolygon( rPoints1, rPoints2 ) );
876 // ============================================================================
877 // Drawing of horizontal frame borders.
879 /** Draws a horizontal thin or thick line into the passed output device.
881 The X coordinates of the edges of the line are adjusted according to the
882 passed LineEndResult structs. A one pixel wide line can be drawn dotted.
884 void lclDrawHorLine(
885 OutputDevice& rDev,
886 const Point& rLPos, const LineEndResult& rLRes,
887 const Point& rRPos, const LineEndResult& rRRes,
888 long nTOffs, long nBOffs, bool bDotted )
890 LinePoints aTPoints( rLPos + lclToMapUnit( rLRes.mnOffs1, nTOffs ), rRPos + lclToMapUnit( rRRes.mnOffs1, nTOffs ) );
891 if( nTOffs == nBOffs )
892 lclDrawThinLine( rDev, aTPoints, bDotted );
893 else
895 LinePoints aBPoints( rLPos + lclToMapUnit( rLRes.mnOffs2, nBOffs ), rRPos + lclToMapUnit( rRRes.mnOffs2, nBOffs ) );
896 lclDrawPolygon( rDev, aTPoints, aBPoints );
900 /** Draws a horizontal frame border into the passed output device.
902 @param rLPos
903 The top-left or bottom-left reference point of the diagonal frame border.
904 @param rRPos
905 The top-right or bottom-right reference point of the diagonal frame border.
906 @param rBorder
907 The frame style used to draw the border.
908 @param rResult
909 The X coordinates of the edges of all lines of the frame border are
910 adjusted according to the offsets contained here.
912 void lclDrawHorFrameBorder(
913 OutputDevice& rDev, const Point& rLPos, const Point& rRPos,
914 const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
916 DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawHorFrameBorder - line not visible" );
917 DBG_ASSERT( rLPos.X() <= rRPos.X(), "svx::frame::lclDrawHorFrameBorder - wrong order of line ends" );
918 DBG_ASSERT( rLPos.Y() == rRPos.Y(), "svx::frame::lclDrawHorFrameBorder - line not horizontal" );
919 if( rLPos.X() <= rRPos.X() )
921 lclSetColorToOutDev( rDev, rBorder, pForceColor );
922 lclDrawHorLine( rDev, rLPos, rResult.maBeg.maPrim, rRPos, rResult.maEnd.maPrim,
923 lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
924 if( rBorder.Secn() )
925 lclDrawHorLine( rDev, rLPos, rResult.maBeg.maSecn, rRPos, rResult.maEnd.maSecn,
926 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
927 rDev.Pop(); // colors
931 // ----------------------------------------------------------------------------
932 // Drawing of vertical frame borders.
934 /** Draws a vertical thin or thick line into the passed output device.
936 The Y coordinates of the edges of the line are adjusted according to the
937 passed LineEndResult structs. A one pixel wide line can be drawn dotted.
939 void lclDrawVerLine(
940 OutputDevice& rDev,
941 const Point& rTPos, const LineEndResult& rTRes,
942 const Point& rBPos, const LineEndResult& rBRes,
943 long nLOffs, long nROffs, bool bDotted )
945 LinePoints aLPoints( rTPos + lclToMapUnit( nLOffs, rTRes.mnOffs1 ), rBPos + lclToMapUnit( nLOffs, rBRes.mnOffs1 ) );
946 if( nLOffs == nROffs )
947 lclDrawThinLine( rDev, aLPoints, bDotted );
948 else
950 LinePoints aRPoints( rTPos + lclToMapUnit( nROffs, rTRes.mnOffs2 ), rBPos + lclToMapUnit( nROffs, rBRes.mnOffs2 ) );
951 lclDrawPolygon( rDev, aLPoints, aRPoints );
955 /** Draws a vertical frame border into the passed output device.
957 @param rTPos
958 The top-left or top-right reference point of the diagonal frame border.
959 @param rBPos
960 The bottom-left or bottom-right reference point of the diagonal frame border.
961 @param rBorder
962 The frame style used to draw the border.
963 @param rResult
964 The Y coordinates of the edges of all lines of the frame border are
965 adjusted according to the offsets contained here.
967 void lclDrawVerFrameBorder(
968 OutputDevice& rDev, const Point& rTPos, const Point& rBPos,
969 const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
971 DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawVerFrameBorder - line not visible" );
972 DBG_ASSERT( rTPos.Y() <= rBPos.Y(), "svx::frame::lclDrawVerFrameBorder - wrong order of line ends" );
973 DBG_ASSERT( rTPos.X() == rBPos.X(), "svx::frame::lclDrawVerFrameBorder - line not vertical" );
974 if( rTPos.Y() <= rBPos.Y() )
976 lclSetColorToOutDev( rDev, rBorder, pForceColor );
977 lclDrawVerLine( rDev, rTPos, rResult.maBeg.maPrim, rBPos, rResult.maEnd.maPrim,
978 lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
979 if( rBorder.Secn() )
980 lclDrawVerLine( rDev, rTPos, rResult.maBeg.maSecn, rBPos, rResult.maEnd.maSecn,
981 lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
982 rDev.Pop(); // colors
986 // ============================================================================
987 // Drawing of diagonal frame borders, incudes clipping functions.
989 /** Returns the drawing coordinates for a diagonal thin line.
991 This function can be used for top-left to bottom-right and for bottom-left
992 to top-right lines.
994 @param rRect
995 The reference rectangle of the diagonal frame border.
996 @param bTLBR
997 true = top-left to bottom-right; false = bottom-left to top-right.
998 @param nDiagOffs
999 Width offset (sub units) across the diagonal frame border.
1000 @return
1001 A struct containg start and end position of the diagonal line.
1003 LinePoints lclGetDiagLineEnds( const Rectangle& rRect, bool bTLBR, long nDiagOffs )
1005 LinePoints aPoints( rRect, bTLBR );
1006 bool bVert = rRect.GetWidth() < rRect.GetHeight();
1007 double fAngle = bVert ? GetVerDiagAngle( rRect ) : GetHorDiagAngle( rRect );
1008 // vertical top-left to bottom-right borders are handled mirrored
1009 if( bVert && bTLBR )
1010 nDiagOffs = -nDiagOffs;
1011 long nTOffs = bTLBR ? GetTLDiagOffset( 0, nDiagOffs, fAngle ) : GetTRDiagOffset( 0, nDiagOffs, fAngle );
1012 long nBOffs = bTLBR ? GetBRDiagOffset( 0, nDiagOffs, fAngle ) : GetBLDiagOffset( 0, nDiagOffs, fAngle );
1013 // vertical bottom-left to top-right borders are handled with exchanged end points
1014 if( bVert && !bTLBR )
1015 std::swap( nTOffs, nBOffs );
1016 (bVert ? aPoints.maBeg.Y() : aPoints.maBeg.X()) += lclToMapUnit( nTOffs );
1017 (bVert ? aPoints.maEnd.Y() : aPoints.maEnd.X()) += lclToMapUnit( nBOffs );
1018 return aPoints;
1021 // ----------------------------------------------------------------------------
1022 // Clipping functions for diagonal frame borders.
1024 /** Limits the clipping region to the inner area of a rectange.
1026 Takes the values from the passed DiagLineResult struct into account. They
1027 may specify to not clip one or more borders of a rectangle.
1029 @param rDev
1030 The output device with the clipping region to be modified. The old
1031 clipping region is pushed onto the device's stack and can be restored
1032 with a call to OutputDevice::Pop(). Please take care about the correct
1033 calling order of Pop() if this function is used with other functions
1034 pushing something onto the stack.
1035 @param rRect
1036 The reference rectangle of the diagonal frame borders.
1037 @param rResult
1038 The result struct containing modifies for each border of the reference
1039 rectangle.
1041 void lclPushDiagClipRect( OutputDevice& rDev, const Rectangle& rRect, const DiagLineResult& rResult )
1043 // PixelToLogic() regards internal offset of the output device
1044 Rectangle aClipRect( rRect );
1045 aClipRect.Left() += lclToMapUnit( rResult.mnLClip );
1046 aClipRect.Top() += lclToMapUnit( rResult.mnTClip );
1047 aClipRect.Right() += lclToMapUnit( rResult.mnRClip );
1048 aClipRect.Bottom() += lclToMapUnit( rResult.mnBClip );
1049 // output device would adjust the rectangle -> invalidate it before
1050 if( (aClipRect.GetWidth() < 1) ||(aClipRect.GetHeight() < 1) )
1051 aClipRect.SetEmpty();
1053 rDev.Push( PUSH_CLIPREGION );
1054 rDev.IntersectClipRegion( aClipRect );
1057 /** Excludes inner area of a crossing double frame border from clipping region.
1059 This function is used to modify the clipping region so that it excludes the
1060 inner free area of a double diagonal frame border. This makes it possible
1061 to draw a diagonal frame border in one step without taking care of the
1062 crossing double frame border.
1064 @param rDev
1065 The output device with the clipping region to be modified. The old
1066 clipping region is pushed onto the device's stack and can be restored
1067 with a call to OutputDevice::Pop(). Please take care about the correct
1068 calling order of Pop() if this function is used with other functions
1069 pushing something onto the stack.
1070 @param rRect
1071 The reference rectangle of the diagonal frame borders.
1072 @param bTLBR
1073 The orientation of the processed frame border (not the orientation of
1074 the crossing frame border).
1075 @param bCrossStyle
1076 The style of the crossing frame border. Must be a double frame style.
1078 void lclPushCrossingClipRegion( OutputDevice& rDev, const Rectangle& rRect, bool bTLBR, const Style& rCrossStyle )
1080 DBG_ASSERT( rCrossStyle.Secn(), "lclGetCrossingClipRegion - use only for double styles" );
1081 LinePoints aLPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetPrimEnd( rCrossStyle ) ) );
1082 LinePoints aRPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetSecnBeg( rCrossStyle ) ) );
1084 Region aClipReg;
1085 if( bTLBR )
1087 aClipReg = lclCreatePolygon(
1088 aLPoints.maBeg, aLPoints.maEnd, rRect.BottomRight(), rRect.BottomLeft(), rRect.TopLeft() );
1089 aClipReg.Union( lclCreatePolygon(
1090 aRPoints.maBeg, aRPoints.maEnd, rRect.BottomRight(), rRect.TopRight(), rRect.TopLeft() ) );
1092 else
1094 aClipReg = lclCreatePolygon(
1095 aLPoints.maBeg, aLPoints.maEnd, rRect.BottomLeft(), rRect.TopLeft(), rRect.TopRight() );
1096 aClipReg.Union( lclCreatePolygon(
1097 aRPoints.maBeg, aRPoints.maEnd, rRect.BottomLeft(), rRect.BottomRight(), rRect.TopRight() ) );
1100 rDev.Push( PUSH_CLIPREGION );
1101 rDev.IntersectClipRegion( aClipReg );
1104 // ----------------------------------------------------------------------------
1105 // Drawing functions for diagonal frame borders.
1107 /** Draws a diagonal thin or thick line into the passed output device.
1109 The clipping region of the output device is modified according to the
1110 passed DiagLineResult struct. A one pixel wide line can be drawn dotted.
1112 void lclDrawDiagLine(
1113 OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1114 const DiagLineResult& rResult, long nDiagOffs1, long nDiagOffs2, bool bDotted )
1116 lclPushDiagClipRect( rDev, rRect, rResult );
1117 LinePoints aLPoints( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs1 ) );
1118 if( nDiagOffs1 == nDiagOffs2 )
1119 lclDrawThinLine( rDev, aLPoints, bDotted );
1120 else
1121 lclDrawPolygon( rDev, aLPoints, lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs2 ) );
1122 rDev.Pop(); // clipping region
1125 /** Draws a diagonal frame border into the passed output device.
1127 The lines of the frame border are drawn interrupted, if the style of the
1128 crossing frame border is double.
1130 @param rRect
1131 The reference rectangle of the diagonal frame border.
1132 @param bTLBR
1133 The orientation of the diagonal frame border.
1134 @param rBorder
1135 The frame style used to draw the border.
1136 @param rResult
1137 Offsets (sub units) to modify the clipping region of the output device.
1138 @param rCrossStyle
1139 Style of the crossing diagonal frame border.
1141 void lclDrawDiagFrameBorder(
1142 OutputDevice& rDev, const Rectangle& rRect, bool bTLBR,
1143 const Style& rBorder, const DiagBorderResult& rResult, const Style& rCrossStyle,
1144 const Color* pForceColor, bool bDiagDblClip )
1146 DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawDiagFrameBorder - line not visible" );
1148 bool bClip = bDiagDblClip && rCrossStyle.Secn();
1149 if( bClip )
1150 lclPushCrossingClipRegion( rDev, rRect, bTLBR, rCrossStyle );
1152 lclSetColorToOutDev( rDev, rBorder, pForceColor );
1153 lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maPrim, lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Dotted() );
1154 if( rBorder.Secn() )
1155 lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Dotted() );
1156 rDev.Pop(); // colors
1158 if( bClip )
1159 rDev.Pop(); // clipping region
1162 /** Draws both diagonal frame borders into the passed output device.
1164 The lines of each frame border is drawn interrupted, if the style of the
1165 other crossing frame border is double.
1167 @param rRect
1168 The reference rectangle of the diagonal frame borders.
1169 @param rTLBR
1170 The frame style of the top-left to bottom-right frame border.
1171 @param rBLTR
1172 The frame style of the bottom-left to top-right frame border.
1173 @param rResult
1174 Offsets (sub units) to modify the clipping region of the output device.
1176 void lclDrawDiagFrameBorders(
1177 OutputDevice& rDev, const Rectangle& rRect,
1178 const Style& rTLBR, const Style& rBLTR, const DiagBordersResult& rResult,
1179 const Color* pForceColor, bool bDiagDblClip )
1181 DBG_ASSERT( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1), "svx::frame::lclDrawDiagFrameBorders - rectangle too small" );
1182 if( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1) )
1184 bool bDrawTLBR = rTLBR.Prim() != 0;
1185 bool bDrawBLTR = rBLTR.Prim() != 0;
1186 bool bFirstDrawBLTR = rTLBR.Secn() != 0;
1188 if( bDrawBLTR && bFirstDrawBLTR )
1189 lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1190 if( bDrawTLBR )
1191 lclDrawDiagFrameBorder( rDev, rRect, true, rTLBR, rResult.maTLBR, rBLTR, pForceColor, bDiagDblClip );
1192 if( bDrawBLTR && !bFirstDrawBLTR )
1193 lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
1197 // ============================================================================
1199 } // namespace
1201 // ============================================================================
1202 // Classes
1203 // ============================================================================
1205 #define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth )
1207 void Style::Clear()
1209 Set( Color(), 0, 0, 0 );
1212 void Style::Set( sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS )
1214 /* nP nD nS -> mnPrim mnDist mnSecn
1215 --------------------------------------
1216 any any 0 nP 0 0
1217 0 any >0 nS 0 0
1218 >0 0 >0 nP 0 0
1219 >0 >0 >0 nP nD nS
1221 mnPrim = nP ? nP : nS;
1222 mnDist = (nP && nS) ? nD : 0;
1223 mnSecn = (nP && nD) ? nS : 0;
1226 void Style::Set( const Color& rColor, sal_uInt16 nP, sal_uInt16 nD, sal_uInt16 nS )
1228 maColor = rColor;
1229 Set( nP, nD, nS );
1232 void Style::Set( const SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots )
1234 maColor = rBorder.GetColor();
1236 USHORT nPrim = rBorder.GetOutWidth();
1237 USHORT nDist = rBorder.GetDistance();
1238 USHORT nSecn = rBorder.GetInWidth();
1240 if( !nSecn ) // no or single frame border
1242 Set( SCALEVALUE( nPrim ), 0, 0 );
1243 mbDotted = bUseDots && (0 < nPrim) && (nPrim < 10);
1245 else
1247 Set( SCALEVALUE( nPrim ), SCALEVALUE( nDist ), SCALEVALUE( nSecn ) );
1248 mbDotted = false;
1249 // Enlarge the style if distance is too small due to rounding losses.
1250 sal_uInt16 nPixWidth = SCALEVALUE( nPrim + nDist + nSecn );
1251 if( nPixWidth > GetWidth() )
1252 mnDist = nPixWidth - mnPrim - mnSecn;
1253 // Shrink the style if it is too thick for the control.
1254 while( GetWidth() > nMaxWidth )
1256 // First decrease space between lines.
1257 if( mnDist )
1258 --mnDist;
1259 // Still too thick? Decrease the line widths.
1260 if( GetWidth() > nMaxWidth )
1262 if( mnPrim && (mnPrim == mnSecn) )
1264 // Both lines equal - decrease both to keep symmetry.
1265 --mnPrim;
1266 --mnSecn;
1268 else
1270 // Decrease each line for itself
1271 if( mnPrim )
1272 --mnPrim;
1273 if( (GetWidth() > nMaxWidth) && mnSecn )
1274 --mnSecn;
1281 void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth, bool bUseDots )
1283 if( pBorder )
1284 Set( *pBorder, fScale, nMaxWidth, bUseDots );
1285 else
1287 Clear();
1288 mbDotted = false;
1292 Style& Style::ScaleSelf( double fScale, sal_uInt16 nMaxWidth )
1294 Set( SCALEVALUE( mnPrim ), SCALEVALUE( mnDist ), SCALEVALUE( mnSecn ) );
1295 return *this;
1298 Style Style::Scale( double fScale, sal_uInt16 nMaxWidth ) const
1300 return Style( *this ).ScaleSelf( fScale, nMaxWidth );
1303 Style& Style::MirrorSelf()
1305 if( mnSecn )
1306 std::swap( mnPrim, mnSecn );
1307 if( meRefMode != REFMODE_CENTERED )
1308 meRefMode = (meRefMode == REFMODE_BEGIN) ? REFMODE_END : REFMODE_BEGIN;
1309 return *this;
1312 Style Style::Mirror() const
1314 return Style( *this ).MirrorSelf();
1317 bool operator==( const Style& rL, const Style& rR )
1319 return (rL.Prim() == rR.Prim()) && (rL.Dist() == rR.Dist()) && (rL.Secn() == rR.Secn()) &&
1320 (rL.GetColor() == rR.GetColor()) && (rL.GetRefMode() == rR.GetRefMode()) && (rL.Dotted() == rR.Dotted());
1323 bool operator<( const Style& rL, const Style& rR )
1325 // different total widths -> rL<rR, if rL is thinner
1326 sal_uInt16 nLW = rL.GetWidth();
1327 sal_uInt16 nRW = rR.GetWidth();
1328 if( nLW != nRW ) return nLW < nRW;
1330 // one line double, the other single -> rL<rR, if rL is single
1331 if( (rL.Secn() == 0) != (rR.Secn() == 0) ) return rL.Secn() == 0;
1333 // both lines double with different distances -> rL<rR, if distance of rL greater
1334 if( (rL.Secn() && rR.Secn()) && (rL.Dist() != rR.Dist()) ) return rL.Dist() > rR.Dist();
1336 // both lines single and 1 unit thick, only one is dotted -> rL<rR, if rL is dotted
1337 if( (nLW == 1) && (rL.Dotted() != rR.Dotted()) ) return rL.Dotted();
1339 // seem to be equal
1340 return false;
1343 #undef SCALEVALUE
1345 // ============================================================================
1346 // Various helper functions
1347 // ============================================================================
1349 double GetHorDiagAngle( long nWidth, long nHeight )
1351 return atan2( static_cast< double >( Abs( nHeight ) ), static_cast< double >( Abs( nWidth ) ) );
1354 // ============================================================================
1356 long GetTLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1358 return lclD2L( nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1361 long GetBLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1363 return lclD2L( -nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
1366 long GetBRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1368 return -lclD2L( -nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1371 long GetTRDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
1373 return -lclD2L( nVerOffs / tan( fAngle ) - nDiagOffs / sin( fAngle ) );
1376 // ============================================================================
1378 bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
1379 const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR,
1380 const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR )
1382 return // returns 1 AND (2a OR 2b)
1383 // 1) only, if both frame borders are equal
1384 (rLBorder == rRBorder)
1388 // 2a) if the borders are not double, at least one of the vertical must not be double
1389 !rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn())
1393 // 2b) if the borders are double, all other borders must not be double
1394 rLBorder.Secn() &&
1395 !rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() &&
1396 !rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn()
1401 // ============================================================================
1402 // Drawing functions
1403 // ============================================================================
1405 void DrawHorFrameBorder( OutputDevice& rDev,
1406 const Point& rLPos, const Point& rRPos, const Style& rBorder,
1407 const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR,
1408 const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL,
1409 const Color* pForceColor )
1411 if( rBorder.Prim() )
1413 BorderResult aResult;
1414 lclLinkHorFrameBorder( aResult, rBorder,
1415 rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR,
1416 rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
1417 lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, aResult, pForceColor );
1421 void DrawHorFrameBorder( OutputDevice& rDev,
1422 const Point& rLPos, const Point& rRPos, const Style& rBorder,
1423 const Style& rLFromT, const Style& rLFromL, const Style& rLFromB,
1424 const Style& rRFromT, const Style& rRFromR, const Style& rRFromB,
1425 const Color* pForceColor )
1427 /* Recycle complex version of the DrawHorFrameBorder() function with empty diagonals. */
1428 const DiagStyle aNoStyle;
1429 DrawHorFrameBorder(
1430 rDev, rLPos, rRPos, rBorder,
1431 aNoStyle, rLFromT, rLFromL, rLFromB, aNoStyle,
1432 aNoStyle, rRFromT, rRFromR, rRFromB, aNoStyle,
1433 pForceColor );
1436 void DrawHorFrameBorder( OutputDevice& rDev,
1437 const Point& rLPos, const Point& rRPos, const Style& rBorder, const Color* pForceColor )
1439 if( rBorder.Prim() )
1440 lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, BorderResult(), pForceColor );
1443 // ----------------------------------------------------------------------------
1445 void DrawVerFrameBorder( OutputDevice& rDev,
1446 const Point& rTPos, const Point& rBPos, const Style& rBorder,
1447 const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
1448 const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR,
1449 const Color* pForceColor )
1451 if( rBorder.Prim() )
1453 BorderResult aResult;
1454 lclLinkVerFrameBorder( aResult, rBorder,
1455 rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR,
1456 rBFromTL, rBFromL, rBFromB, rBFromR, rBFromTR );
1457 lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, aResult, pForceColor );
1461 void DrawVerFrameBorder( OutputDevice& rDev,
1462 const Point& rTPos, const Point& rBPos, const Style& rBorder,
1463 const Style& rTFromL, const Style& rTFromT, const Style& rTFromR,
1464 const Style& rBFromL, const Style& rBFromB, const Style& rBFromR,
1465 const Color* pForceColor )
1467 /* Recycle complex version of the DrawVerFrameBorder() function with empty diagonals. */
1468 const DiagStyle aNoStyle;
1469 DrawVerFrameBorder(
1470 rDev, rTPos, rBPos, rBorder,
1471 aNoStyle, rTFromL, rTFromT, rTFromR, aNoStyle,
1472 aNoStyle, rBFromL, rBFromB, rBFromR, aNoStyle,
1473 pForceColor );
1476 void DrawVerFrameBorder( OutputDevice& rDev,
1477 const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor )
1479 if( rBorder.Prim() )
1480 lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, BorderResult(), pForceColor );
1483 // ----------------------------------------------------------------------------
1485 void DrawVerFrameBorderSlanted( OutputDevice& rDev,
1486 const Point& rTPos, const Point& rBPos, const Style& rBorder, const Color* pForceColor )
1488 DBG_ASSERT( rTPos.Y() < rBPos.Y(), "svx::frame::DrawVerFrameBorderSlanted - wrong order of line ends" );
1489 if( rBorder.Prim() && (rTPos.Y() < rBPos.Y()) )
1491 if( rTPos.X() == rBPos.X() )
1493 DrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, pForceColor );
1495 else
1497 const LineEndResult aRes;
1499 Style aScaled( rBorder );
1500 aScaled.ScaleSelf( 1.0 / cos( GetVerDiagAngle( rTPos, rBPos ) ) );
1502 lclSetColorToOutDev( rDev, aScaled, pForceColor );
1503 lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes,
1504 lclGetBeg( aScaled ), lclGetPrimEnd( aScaled ), aScaled.Dotted() );
1505 if( aScaled.Secn() )
1506 lclDrawVerLine( rDev, rTPos, aRes, rBPos, aRes,
1507 lclGetSecnBeg( aScaled ), lclGetEnd( aScaled ), aScaled.Dotted() );
1508 rDev.Pop(); // colors
1513 // ============================================================================
1515 void DrawDiagFrameBorders(
1516 OutputDevice& rDev, const Rectangle& rRect, const Style& rTLBR, const Style& rBLTR,
1517 const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
1518 const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL,
1519 const Color* pForceColor, bool bDiagDblClip )
1521 if( rTLBR.Prim() || rBLTR.Prim() )
1523 DiagBordersResult aResult;
1524 lclLinkDiagFrameBorders( aResult, rTLBR, rBLTR,
1525 rTLFromB, rTLFromR, rBRFromT, rBRFromL, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
1526 lclDrawDiagFrameBorders( rDev, rRect, rTLBR, rBLTR, aResult, pForceColor, bDiagDblClip );
1530 // ============================================================================
1532 } // namespace frame
1533 } // namespace svx