Simplify tools::Rectangle a bit
[LibreOffice.git] / include / tools / gen.hxx
blob3c97728c7402abe9f73601ce01b738ece48fc879
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
19 #ifndef INCLUDED_TOOLS_GEN_HXX
20 #define INCLUDED_TOOLS_GEN_HXX
22 #include <tools/toolsdllapi.h>
24 #include <tools/long.hxx>
25 #include <tools/degree.hxx>
26 #include <limits.h>
27 #include <algorithm>
28 #include <ostream>
29 #include <config_options.h>
30 #include <o3tl/unit_conversion.hxx>
32 class SvStream;
33 namespace rtl
35 class OString;
38 enum TriState { TRISTATE_FALSE, TRISTATE_TRUE, TRISTATE_INDET };
40 // Pair
42 class SAL_WARN_UNUSED Pair
44 public:
45 constexpr Pair() : nA(0), nB(0) {}
46 constexpr Pair( tools::Long _nA, tools::Long _nB ) : nA(_nA), nB(_nB) {}
48 tools::Long A() const { return nA; }
49 tools::Long B() const { return nB; }
51 tools::Long& A() { return nA; }
52 tools::Long& B() { return nB; }
54 TOOLS_DLLPUBLIC rtl::OString toString() const;
56 protected:
57 tools::Long nA;
58 tools::Long nB;
61 namespace tools::detail {
63 // Used to implement operator == for subclasses of Pair:
64 inline bool equal(Pair const & p1, Pair const & p2)
66 return p1.A() == p2.A() && p1.B() == p2.B();
71 // Point
73 class Size;
74 class SAL_WARN_UNUSED UNLESS_MERGELIBS(SAL_DLLPUBLIC_EXPORT) Point final : protected Pair
76 public:
77 constexpr Point() {}
78 constexpr Point( tools::Long nX, tools::Long nY ) : Pair( nX, nY ) {}
80 constexpr tools::Long X() const { return nA; }
81 constexpr tools::Long Y() const { return nB; }
83 void Move( tools::Long nHorzMove, tools::Long nVertMove );
84 void Move( Size const & s );
85 tools::Long AdjustX( tools::Long nHorzMove ) { nA += nHorzMove; return nA; }
86 tools::Long AdjustY( tools::Long nVertMove ) { nB += nVertMove; return nB; }
88 void RotateAround( tools::Long& rX, tools::Long& rY, Degree10 nOrientation ) const;
89 void RotateAround( Point&, Degree10 nOrientation ) const;
91 Point& operator += ( const Point& rPoint );
92 Point& operator -= ( const Point& rPoint );
93 Point& operator *= ( const tools::Long nVal );
94 Point& operator /= ( const tools::Long nVal );
96 friend inline Point operator+( const Point &rVal1, const Point &rVal2 );
97 friend inline Point operator-( const Point &rVal1, const Point &rVal2 );
98 friend inline Point operator*( const Point &rVal1, const tools::Long nVal2 );
99 friend inline Point operator/( const Point &rVal1, const tools::Long nVal2 );
101 constexpr tools::Long getX() const { return X(); }
102 constexpr tools::Long getY() const { return Y(); }
103 void setX(tools::Long nX) { nA = nX; }
104 void setY(tools::Long nY) { nB = nY; }
106 Pair const & toPair() const { return *this; }
107 Pair & toPair() { return *this; }
109 using Pair::toString;
112 inline void Point::Move( tools::Long nHorzMove, tools::Long nVertMove )
114 nA += nHorzMove;
115 nB += nVertMove;
118 inline Point& Point::operator += ( const Point& rPoint )
120 nA += rPoint.nA;
121 nB += rPoint.nB;
122 return *this;
125 inline Point& Point::operator -= ( const Point& rPoint )
127 nA -= rPoint.nA;
128 nB -= rPoint.nB;
129 return *this;
132 inline Point& Point::operator *= ( const tools::Long nVal )
134 nA *= nVal;
135 nB *= nVal;
136 return *this;
139 inline Point& Point::operator /= ( const tools::Long nVal )
141 nA /= nVal;
142 nB /= nVal;
143 return *this;
146 inline Point operator+( const Point &rVal1, const Point &rVal2 )
148 return Point( rVal1.nA+rVal2.nA, rVal1.nB+rVal2.nB );
151 inline Point operator-( const Point &rVal1, const Point &rVal2 )
153 return Point( rVal1.nA-rVal2.nA, rVal1.nB-rVal2.nB );
156 inline Point operator*( const Point &rVal1, const tools::Long nVal2 )
158 return Point( rVal1.nA*nVal2, rVal1.nB*nVal2 );
161 inline Point operator/( const Point &rVal1, const tools::Long nVal2 )
163 return Point( rVal1.nA/nVal2, rVal1.nB/nVal2 );
166 inline bool operator ==(Point const & p1, Point const & p2)
168 return tools::detail::equal(p1.toPair(), p2.toPair());
171 inline bool operator !=(Point const & p1, Point const & p2)
173 return !(p1 == p2);
176 namespace o3tl
179 constexpr Point convert(const Point& rPoint, o3tl::Length eFrom, o3tl::Length eTo)
181 return Point(
182 o3tl::convert(rPoint.getX(), eFrom, eTo),
183 o3tl::convert(rPoint.getY(), eFrom, eTo));
186 } // end o3tl
188 template< typename charT, typename traits >
189 inline std::basic_ostream<charT, traits> & operator <<(
190 std::basic_ostream<charT, traits> & stream, const Point& point )
192 return stream << point.X() << ',' << point.Y();
195 // Size
197 class SAL_WARN_UNUSED Size final : protected Pair
199 public:
200 constexpr Size() {}
201 constexpr Size( tools::Long nWidth, tools::Long nHeight ) : Pair( nWidth, nHeight ) {}
203 constexpr tools::Long Width() const { return nA; }
204 constexpr tools::Long Height() const { return nB; }
206 tools::Long AdjustWidth( tools::Long n ) { nA += n; return nA; }
207 tools::Long AdjustHeight( tools::Long n ) { nB += n; return nB; }
209 constexpr tools::Long getWidth() const { return Width(); }
210 constexpr tools::Long getHeight() const { return Height(); }
211 void setWidth(tools::Long nWidth) { nA = nWidth; }
212 void setHeight(tools::Long nHeight) { nB = nHeight; }
214 bool IsEmpty() const { return nA <= 0 || nB <= 0; }
216 void extendBy(tools::Long x, tools::Long y)
218 nA += x;
219 nB += y;
222 Pair const & toPair() const { return *this; }
223 Pair & toPair() { return *this; }
225 using Pair::toString;
227 Size& operator += ( const Size& rSize );
228 Size& operator -= ( const Size& rSize );
229 Size& operator *= ( const tools::Long nVal );
230 Size& operator /= ( const tools::Long nVal );
232 friend inline Size operator+( const Size &rVal1, const Size &rVal2 );
233 friend inline Size operator-( const Size &rVal1, const Size &rVal2 );
234 friend inline Size operator*( const Size &rVal1, const tools::Long nVal2 );
235 friend inline Size operator/( const Size &rVal1, const tools::Long nVal2 );
239 inline bool operator ==(Size const & s1, Size const & s2)
241 return tools::detail::equal(s1.toPair(), s2.toPair());
244 inline bool operator !=(Size const & s1, Size const & s2)
246 return !(s1 == s2);
249 inline Size& Size::operator += ( const Size& rSize )
251 nA += rSize.nA;
252 nB += rSize.nB;
253 return *this;
256 inline Size& Size::operator -= ( const Size& rSize )
258 nA -= rSize.nA;
259 nB -= rSize.nB;
260 return *this;
263 inline Size& Size::operator *= ( const tools::Long nVal )
265 nA *= nVal;
266 nB *= nVal;
267 return *this;
270 inline Size& Size::operator /= ( const tools::Long nVal )
272 nA /= nVal;
273 nB /= nVal;
274 return *this;
277 inline Size operator+( const Size &rVal1, const Size &rVal2 )
279 return Size( rVal1.nA+rVal2.nA, rVal1.nB+rVal2.nB );
282 inline Size operator-( const Size &rVal1, const Size &rVal2 )
284 return Size( rVal1.nA-rVal2.nA, rVal1.nB-rVal2.nB );
287 inline Size operator*( const Size &rVal1, const tools::Long nVal2 )
289 return Size( rVal1.nA*nVal2, rVal1.nB*nVal2 );
292 inline Size operator/( const Size &rVal1, const tools::Long nVal2 )
294 return Size( rVal1.nA/nVal2, rVal1.nB/nVal2 );
297 namespace o3tl
300 constexpr Size convert(const Size& rSize, o3tl::Length eFrom, o3tl::Length eTo)
302 return Size(
303 o3tl::convert(rSize.Width(), eFrom, eTo),
304 o3tl::convert(rSize.Height(), eFrom, eTo));
307 } // end o3tl
309 template< typename charT, typename traits >
310 inline std::basic_ostream<charT, traits> & operator <<(
311 std::basic_ostream<charT, traits> & stream, const Size& size )
313 return stream << size.Width() << 'x' << size.Height();
316 inline void Point::Move( Size const & s )
318 AdjustX(s.Width());
319 AdjustY(s.Height());
322 // Range
324 #define RANGE_MAX LONG_MAX
326 class SAL_WARN_UNUSED Range final : protected Pair
328 public:
329 constexpr Range() {}
330 constexpr Range( tools::Long nMin, tools::Long nMax ) : Pair( nMin, nMax ) {}
332 tools::Long Min() const { return nA; }
333 tools::Long Max() const { return nB; }
334 tools::Long Len() const { return nB - nA + 1; }
336 tools::Long& Min() { return nA; }
337 tools::Long& Max() { return nB; }
339 bool IsInside( tools::Long nIs ) const;
341 void Justify();
343 Pair const & toPair() const { return *this; }
344 Pair & toPair() { return *this; }
346 using Pair::toString;
349 inline bool Range::IsInside( tools::Long nIs ) const
351 return ((nA <= nIs) && (nIs <= nB ));
354 inline void Range::Justify()
356 if ( nA > nB )
358 tools::Long nHelp = nA;
359 nA = nB;
360 nB = nHelp;
364 inline bool operator ==(Range const & r1, Range const & r2)
366 return tools::detail::equal(r1.toPair(), r2.toPair());
369 inline bool operator !=(Range const & r1, Range const & r2)
371 return !(r1 == r2);
374 template< typename charT, typename traits >
375 inline std::basic_ostream<charT, traits> & operator <<(
376 std::basic_ostream<charT, traits> & stream, const Range& range )
378 return stream << range.Min() << '-' << range.Max();
381 // Selection
383 #define SELECTION_MIN LONG_MIN
384 #define SELECTION_MAX LONG_MAX
386 class SAL_WARN_UNUSED Selection final : protected Pair
388 public:
389 Selection() {}
390 Selection( tools::Long nPos ) : Pair( nPos, nPos ) {}
391 Selection( tools::Long nMin, tools::Long nMax ) : Pair( nMin, nMax ) {}
393 tools::Long Min() const { return nA; }
394 tools::Long Max() const { return nB; }
395 tools::Long Len() const { return nB - nA; }
397 tools::Long& Min() { return nA; }
398 tools::Long& Max() { return nB; }
400 bool IsInside( tools::Long nIs ) const;
402 void Justify();
404 bool operator !() const { return !Len(); }
406 tools::Long getMin() const { return Min(); }
407 void setMin(tools::Long nMin) { Min() = nMin; }
408 void setMax(tools::Long nMax) { Max() = nMax; }
410 Pair const & toPair() const { return *this; }
411 Pair & toPair() { return *this; }
413 using Pair::toString;
416 inline bool Selection::IsInside( tools::Long nIs ) const
418 return ((nA <= nIs) && (nIs < nB ));
421 inline void Selection::Justify()
423 if ( nA > nB )
425 tools::Long nHelp = nA;
426 nA = nB;
427 nB = nHelp;
431 inline bool operator ==(Selection const & s1, Selection const & s2)
433 return tools::detail::equal(s1.toPair(), s2.toPair());
436 inline bool operator !=(Selection const & s1, Selection const & s2)
438 return !(s1 == s2);
441 template< typename charT, typename traits >
442 inline std::basic_ostream<charT, traits> & operator <<(
443 std::basic_ostream<charT, traits> & stream, const Selection& selection )
445 return stream << selection.Min() << '-' << selection.Max();
447 // Rectangle
449 #define RECT_MAX LONG_MAX
450 #define RECT_MIN LONG_MIN
452 /// Note: this class is a true marvel of engineering: because the author
453 /// could not decide whether it's better to have a closed or half-open
454 /// interval, they just implemented *both* in the same class!
456 /// If you have the misfortune of having to use this class, don't immediately
457 /// despair but first take note that the uppercase GetWidth() / GetHeight()
458 /// etc. methods interpret the interval as closed, while the lowercase
459 /// getWidth() / getHeight() etc. methods interpret the interval as half-open.
460 /// Ok, now is the time for despair.
461 namespace tools
463 class SAL_WARN_UNUSED TOOLS_DLLPUBLIC Rectangle final
465 static constexpr short RECT_EMPTY = -32767;
466 public:
467 constexpr Rectangle() = default;
468 constexpr Rectangle( const Point& rLT, const Point& rRB );
469 constexpr Rectangle( tools::Long nLeft, tools::Long nTop,
470 tools::Long nRight, tools::Long nBottom );
471 /// Constructs an empty Rectangle, with top/left at the specified params
472 constexpr Rectangle( tools::Long nLeft, tools::Long nTop );
473 constexpr Rectangle( const Point& rLT, const Size& rSize );
475 static Rectangle Justify( const Point& rLT, const Point& rRB );
477 constexpr tools::Long Left() const { return nLeft; }
478 constexpr tools::Long Right() const { return IsWidthEmpty() ? nLeft : nRight; }
479 constexpr tools::Long Top() const { return nTop; }
480 constexpr tools::Long Bottom() const { return IsHeightEmpty() ? nTop : nBottom; }
482 constexpr void SetLeft(tools::Long v) { nLeft = v; }
483 constexpr void SetRight(tools::Long v) { nRight = v; }
484 constexpr void SetTop(tools::Long v) { nTop = v; }
485 constexpr void SetBottom(tools::Long v) { nBottom = v; }
487 constexpr Point TopLeft() const { return { Left(), Top() }; }
488 constexpr Point TopRight() const { return { Right(), Top() }; }
489 constexpr Point TopCenter() const { return { (Left() + Right()) / 2, Top() }; }
490 constexpr Point BottomLeft() const { return { Left(), Bottom() }; }
491 constexpr Point BottomRight() const { return { Right(), Bottom() }; }
492 constexpr Point BottomCenter() const { return { (Left() + Right()) / 2, Bottom() }; }
493 constexpr Point LeftCenter() const { return { Left(), (Top() + Bottom()) / 2 }; }
494 constexpr Point RightCenter() const { return { Right(), (Top() + Bottom()) / 2 }; }
495 constexpr Point Center() const { return { (Left() + Right()) / 2, (Top() + Bottom()) / 2 }; }
497 /// Move the top and left edges by a delta, preserving width and height
498 inline void Move( tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta );
499 void Move( Size const & s ) { Move(s.Width(), s.Height()); }
500 tools::Long AdjustLeft( tools::Long nHorzMoveDelta ) { nLeft += nHorzMoveDelta; return nLeft; }
501 tools::Long AdjustRight( tools::Long nHorzMoveDelta );
502 tools::Long AdjustTop( tools::Long nVertMoveDelta ) { nTop += nVertMoveDelta; return nTop; }
503 tools::Long AdjustBottom( tools::Long nVertMoveDelta );
504 inline void SetPos( const Point& rPoint );
505 void SetSize( const Size& rSize );
507 constexpr Size GetSize() const { return { GetWidth(), GetHeight() }; }
509 /// Returns the difference between right and left, assuming the range is inclusive.
510 constexpr tools::Long GetWidth() const
512 tools::Long n = 0;
514 if (!IsWidthEmpty())
516 n = nRight - nLeft;
517 if (n < 0)
518 n--;
519 else
520 n++;
523 return n;
526 /// Returns the difference between bottom and top, assuming the range is inclusive.
527 constexpr tools::Long GetHeight() const
529 tools::Long n = 0;
531 if (!IsHeightEmpty())
533 n = nBottom - nTop;
534 if (n < 0)
535 n--;
536 else
537 n++;
540 return n;
543 tools::Rectangle& Union( const tools::Rectangle& rRect );
544 tools::Rectangle& Intersection( const tools::Rectangle& rRect );
545 inline tools::Rectangle GetUnion( const tools::Rectangle& rRect ) const;
546 inline tools::Rectangle GetIntersection( const tools::Rectangle& rRect ) const;
548 void Justify();
550 bool IsInside( const Point& rPOINT ) const;
551 bool IsInside( const tools::Rectangle& rRect ) const;
552 bool IsOver( const tools::Rectangle& rRect ) const;
554 void SetEmpty() { nRight = nBottom = RECT_EMPTY; }
555 void SetWidthEmpty() { nRight = RECT_EMPTY; }
556 void SetHeightEmpty() { nBottom = RECT_EMPTY; }
557 constexpr bool IsEmpty() const { return IsWidthEmpty() || IsHeightEmpty(); }
558 constexpr bool IsWidthEmpty() const { return nRight == RECT_EMPTY; }
559 constexpr bool IsHeightEmpty() const { return nBottom == RECT_EMPTY; }
561 inline bool operator == ( const tools::Rectangle& rRect ) const;
562 inline bool operator != ( const tools::Rectangle& rRect ) const;
564 inline tools::Rectangle& operator += ( const Point& rPt );
565 inline tools::Rectangle& operator -= ( const Point& rPt );
567 friend inline tools::Rectangle operator + ( const tools::Rectangle& rRect, const Point& rPt );
568 friend inline tools::Rectangle operator - ( const tools::Rectangle& rRect, const Point& rPt );
570 // ONE
571 tools::Long getX() const { return nLeft; }
572 tools::Long getY() const { return nTop; }
573 /// Returns the difference between right and left, assuming the range includes one end, but not the other.
574 tools::Long getWidth() const { return Right() - Left(); }
575 /// Returns the difference between bottom and top, assuming the range includes one end, but not the other.
576 tools::Long getHeight() const { return Bottom() - Top(); }
577 /// Set the left edge of the rectangle to x, preserving the width
578 void setX( tools::Long x );
579 /// Set the top edge of the rectangle to y, preserving the height
580 void setY( tools::Long y );
581 void setWidth( tools::Long n ) { nRight = nLeft + n; }
582 void setHeight( tools::Long n ) { nBottom = nTop + n; }
583 /// Returns the string representation of the rectangle, format is "x, y, width, height".
584 rtl::OString toString() const;
587 * Expands the rectangle in all directions by the input value.
589 void expand(tools::Long nExpandBy);
590 void shrink(tools::Long nShrinkBy);
593 * Sanitizing variants for handling data from the outside
595 void SaturatingSetSize(const Size& rSize);
596 void SaturatingSetX(tools::Long x);
597 void SaturatingSetY(tools::Long y);
599 private:
600 tools::Long nLeft = 0;
601 tools::Long nTop = 0;
602 tools::Long nRight = RECT_EMPTY;
603 tools::Long nBottom = RECT_EMPTY;
607 constexpr inline tools::Rectangle::Rectangle( const Point& rLT, const Point& rRB )
608 : Rectangle(rLT.X(), rLT.Y(), rRB.X(), rRB.Y())
611 constexpr inline tools::Rectangle::Rectangle( tools::Long _nLeft, tools::Long _nTop,
612 tools::Long _nRight, tools::Long _nBottom )
613 : nLeft( _nLeft )
614 , nTop( _nTop )
615 , nRight( _nRight )
616 , nBottom( _nBottom )
619 constexpr inline tools::Rectangle::Rectangle( tools::Long _nLeft, tools::Long _nTop )
620 : nLeft(_nLeft)
621 , nTop(_nTop)
624 constexpr inline tools::Rectangle::Rectangle( const Point& rLT, const Size& rSize )
625 : nLeft( rLT.X())
626 , nTop( rLT.Y())
627 , nRight( rSize.Width() ? nLeft+(rSize.Width()-1) : RECT_EMPTY )
628 , nBottom( rSize.Height() ? nTop+(rSize.Height()-1) : RECT_EMPTY )
631 inline void tools::Rectangle::Move( tools::Long nHorzMove, tools::Long nVertMove )
633 nLeft += nHorzMove;
634 nTop += nVertMove;
635 if (!IsWidthEmpty())
636 nRight += nHorzMove;
637 if (!IsHeightEmpty())
638 nBottom += nVertMove;
641 inline void tools::Rectangle::SetPos( const Point& rPoint )
643 if (!IsWidthEmpty())
644 nRight += rPoint.X() - nLeft;
645 if (!IsHeightEmpty())
646 nBottom += rPoint.Y() - nTop;
647 nLeft = rPoint.X();
648 nTop = rPoint.Y();
651 inline tools::Rectangle tools::Rectangle::GetUnion( const tools::Rectangle& rRect ) const
653 tools::Rectangle aTmpRect( *this );
654 return aTmpRect.Union( rRect );
657 inline tools::Rectangle tools::Rectangle::GetIntersection( const tools::Rectangle& rRect ) const
659 tools::Rectangle aTmpRect( *this );
660 return aTmpRect.Intersection( rRect );
663 inline bool tools::Rectangle::operator == ( const tools::Rectangle& rRect ) const
665 return (nLeft == rRect.nLeft ) &&
666 (nTop == rRect.nTop ) &&
667 (nRight == rRect.nRight ) &&
668 (nBottom == rRect.nBottom );
671 inline bool tools::Rectangle::operator != ( const tools::Rectangle& rRect ) const
673 return (nLeft != rRect.nLeft ) ||
674 (nTop != rRect.nTop ) ||
675 (nRight != rRect.nRight ) ||
676 (nBottom != rRect.nBottom );
679 inline tools::Rectangle& tools::Rectangle::operator +=( const Point& rPt )
681 Move(rPt.X(), rPt.Y());
682 return *this;
685 inline tools::Rectangle& tools::Rectangle::operator -= ( const Point& rPt )
687 Move(-rPt.X(), -rPt.Y());
688 return *this;
691 namespace tools
693 inline Rectangle operator + ( const Rectangle& rRect, const Point& rPt )
695 return Rectangle{ rRect }.operator+=(rPt);
698 inline Rectangle operator - ( const Rectangle& rRect, const Point& rPt )
700 return Rectangle{ rRect }.operator-=(rPt);
705 namespace o3tl
708 constexpr tools::Rectangle convert(const tools::Rectangle& rRectangle, o3tl::Length eFrom, o3tl::Length eTo)
710 return tools::Rectangle(o3tl::convert(rRectangle.TopLeft(), eFrom, eTo),
711 o3tl::convert(rRectangle.GetSize(), eFrom, eTo));
714 } // end o3tl
716 namespace tools
718 template< typename charT, typename traits >
719 inline std::basic_ostream<charT, traits> & operator <<(
720 std::basic_ostream<charT, traits> & stream, const tools::Rectangle& rectangle )
722 if (rectangle.IsEmpty())
723 return stream << "EMPTY";
724 else
725 return stream << rectangle.GetWidth() << 'x' << rectangle.GetHeight()
726 << "@(" << rectangle.getX() << ',' << rectangle.getY() << ")";
730 #endif
732 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */