summaryrefslogtreecommitdiffstats
path: root/include/tools/gen.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'include/tools/gen.hxx')
-rw-r--r--include/tools/gen.hxx925
1 files changed, 925 insertions, 0 deletions
diff --git a/include/tools/gen.hxx b/include/tools/gen.hxx
new file mode 100644
index 0000000000..d6ac5f2ec7
--- /dev/null
+++ b/include/tools/gen.hxx
@@ -0,0 +1,925 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/toolsdllapi.h>
+
+#include <tools/long.hxx>
+#include <tools/degree.hxx>
+#include <limits.h>
+#include <algorithm>
+#include <ostream>
+#include <o3tl/unit_conversion.hxx>
+
+class SvStream;
+namespace rtl
+{
+ class OString;
+}
+
+enum TriState { TRISTATE_FALSE, TRISTATE_TRUE, TRISTATE_INDET };
+
+// Pair
+
+class SAL_WARN_UNUSED Pair
+{
+public:
+ constexpr Pair() : mnA(0), mnB(0) {}
+ constexpr Pair( tools::Long nA, tools::Long nB ) : mnA(nA), mnB(nB) {}
+
+ tools::Long A() const { return mnA; }
+ tools::Long B() const { return mnB; }
+
+ tools::Long& A() { return mnA; }
+ tools::Long& B() { return mnB; }
+
+ TOOLS_DLLPUBLIC rtl::OString toString() const;
+
+ // Compute value usable as hash.
+ TOOLS_DLLPUBLIC size_t GetHashValue() const;
+
+protected:
+ tools::Long mnA;
+ tools::Long mnB;
+};
+
+namespace tools::detail {
+
+// Used to implement operator == for subclasses of Pair:
+inline bool equal(Pair const & p1, Pair const & p2)
+{
+ return p1.A() == p2.A() && p1.B() == p2.B();
+}
+
+}
+
+// Point
+
+class RectangleTemplateBase;
+
+class TOOLS_DLLPUBLIC PointTemplateBase : protected Pair
+{
+friend class RectangleTemplateBase;
+public:
+ PointTemplateBase() = default;
+protected:
+ constexpr PointTemplateBase( tools::Long nX, tools::Long nY ) : Pair( nX, nY ) {}
+ // Rotate parameter point using This as origin; store result back into parameter point
+ void RotateAround( tools::Long& rX, tools::Long& rY, Degree10 nOrientation ) const;
+ void RotateAround( PointTemplateBase&, Degree10 nOrientation ) const;
+
+public:
+ constexpr tools::Long X() const { return mnA; }
+ constexpr tools::Long Y() const { return mnB; }
+};
+
+template<class PointT, class SizeT>
+class PointTemplate : public PointTemplateBase
+{
+public:
+ using SizeType = SizeT;
+
+ constexpr PointTemplate() {}
+ constexpr PointTemplate( tools::Long nX, tools::Long nY ) : PointTemplateBase( nX, nY ) {}
+
+ void Move( tools::Long nHorzMove, tools::Long nVertMove )
+ {
+ mnA += nHorzMove;
+ mnB += nVertMove;
+ }
+ void Move( SizeT const & s )
+ {
+ AdjustX(s.Width());
+ AdjustY(s.Height());
+ }
+
+ tools::Long AdjustX( tools::Long nHorzMove ) { mnA += nHorzMove; return mnA; }
+ tools::Long AdjustY( tools::Long nVertMove ) { mnB += nVertMove; return mnB; }
+
+ void RotateAround( tools::Long& rX, tools::Long& rY, Degree10 nOrientation ) const
+ { PointTemplateBase::RotateAround(rX, rY, nOrientation); }
+ void RotateAround( PointT& p, Degree10 nOrientation ) const
+ { PointTemplateBase::RotateAround(p, nOrientation); }
+
+ PointT& operator+=( const PointT& rPoint )
+ {
+ mnA += rPoint.mnA;
+ mnB += rPoint.mnB;
+ return static_cast<PointT&>(*this);
+ }
+ PointT& operator-=( const PointT& rPoint )
+ {
+ mnA -= rPoint.mnA;
+ mnB -= rPoint.mnB;
+ return static_cast<PointT&>(*this);
+ }
+ PointT& operator*=( const tools::Long nVal )
+ {
+ mnA *= nVal;
+ mnB *= nVal;
+ return static_cast<PointT&>(*this);
+ }
+ PointT& operator/=( const tools::Long nVal )
+ {
+ mnA /= nVal;
+ mnB /= nVal;
+ return static_cast<PointT&>(*this);
+ }
+
+ constexpr tools::Long getX() const { return X(); }
+ constexpr tools::Long getY() const { return Y(); }
+ void setX(tools::Long nX) { mnA = nX; }
+ void setY(tools::Long nY) { mnB = nY; }
+
+ Pair const & toPair() const { return *this; }
+ Pair & toPair() { return *this; }
+
+ // Scales relative to 0,0
+ constexpr PointT scale(sal_Int64 nMulX, sal_Int64 nDivX,
+ sal_Int64 nMulY, sal_Int64 nDivY) const
+ {
+ return PointT(o3tl::convert(getX(), nMulX, nDivX),
+ o3tl::convert(getY(), nMulY, nDivY));
+ }
+
+ using Pair::toString;
+ using Pair::GetHashValue;
+};
+
+class Size;
+class AbsoluteScreenPixelSize;
+class Point;
+class AbsoluteScreenPixelPoint;
+namespace tools { class Rectangle; }
+class AbsoluteScreenPixelRectangle;
+
+class SAL_WARN_UNUSED Point : public PointTemplate<::Point, ::Size>
+{
+public:
+ constexpr Point() {}
+ constexpr Point( tools::Long nX, tools::Long nY ) : PointTemplate( nX, nY ) {}
+ // TODO delete this to expose more problems
+ constexpr explicit Point(const AbsoluteScreenPixelPoint&);
+};
+
+// A point relative to top-level parent or screen, in screen pixels
+class AbsoluteScreenPixelSize;
+class SAL_WARN_UNUSED AbsoluteScreenPixelPoint : public PointTemplate<AbsoluteScreenPixelPoint, AbsoluteScreenPixelSize> {
+public:
+ constexpr AbsoluteScreenPixelPoint() {}
+ constexpr AbsoluteScreenPixelPoint( tools::Long nX, tools::Long nY ) : PointTemplate( nX, nY ) {}
+ constexpr explicit AbsoluteScreenPixelPoint(const Point & pt) : PointTemplate(pt.X(), pt.Y()) {}
+};
+
+inline Point operator+( const Point &rVal1, const Point &rVal2 )
+{
+ return Point( rVal1.X()+rVal2.X(), rVal1.Y()+rVal2.Y() );
+}
+inline AbsoluteScreenPixelPoint operator+( const AbsoluteScreenPixelPoint &rVal1, const AbsoluteScreenPixelPoint &rVal2 )
+{
+ return AbsoluteScreenPixelPoint( rVal1.X()+rVal2.X(), rVal1.Y()+rVal2.Y() );
+}
+
+inline Point operator-( const Point &rVal1, const Point &rVal2 )
+{
+ return Point( rVal1.X()-rVal2.X(), rVal1.Y()-rVal2.Y() );
+}
+inline AbsoluteScreenPixelPoint operator-( const AbsoluteScreenPixelPoint &rVal1, const AbsoluteScreenPixelPoint &rVal2 )
+{
+ return AbsoluteScreenPixelPoint( rVal1.X()-rVal2.X(), rVal1.Y()-rVal2.Y() );
+}
+
+inline Point operator*( const Point &rVal1, const tools::Long nVal2 )
+{
+ return Point( rVal1.X()*nVal2, rVal1.Y()*nVal2 );
+}
+inline AbsoluteScreenPixelPoint operator*( const AbsoluteScreenPixelPoint &rVal1, const tools::Long nVal2 )
+{
+ return AbsoluteScreenPixelPoint( rVal1.X()*nVal2, rVal1.Y()*nVal2 );
+}
+
+inline Point operator/( const Point &rVal1, const tools::Long nVal2 )
+{
+ return Point( rVal1.X()/nVal2, rVal1.Y()/nVal2 );
+}
+inline AbsoluteScreenPixelPoint operator/( const AbsoluteScreenPixelPoint &rVal1, const tools::Long nVal2 )
+{
+ return AbsoluteScreenPixelPoint( rVal1.X()/nVal2, rVal1.Y()/nVal2 );
+}
+
+inline bool operator ==(Point const & p1, Point const & p2)
+{
+ return tools::detail::equal(p1.toPair(), p2.toPair());
+}
+inline bool operator ==(AbsoluteScreenPixelPoint const & p1, AbsoluteScreenPixelPoint const & p2)
+{
+ return tools::detail::equal(p1.toPair(), p2.toPair());
+}
+
+inline bool operator !=(Point const & p1, Point const & p2)
+{
+ return !(p1 == p2);
+}
+inline bool operator !=(AbsoluteScreenPixelPoint const & p1, AbsoluteScreenPixelPoint const & p2)
+{
+ return !(p1 == p2);
+}
+
+
+constexpr Point::Point(const AbsoluteScreenPixelPoint& p) : Point(p.X(), p.Y()) {}
+
+namespace o3tl
+{
+template <class PointT,
+ std::enable_if_t<std::is_base_of_v<PointTemplate<PointT, typename PointT::SizeType>, PointT>, int> = 0>
+constexpr auto convert(const PointT& rPoint, o3tl::Length eFrom, o3tl::Length eTo)
+{
+ const auto [num, den] = o3tl::getConversionMulDiv(eFrom, eTo);
+ return rPoint.scale(num, den, num, den);
+}
+} // namespace o3tl
+
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const PointTemplateBase& point )
+{
+ return stream << point.X() << ',' << point.Y();
+}
+
+// Size
+
+class SizeTemplateBase : protected Pair
+{
+public:
+ constexpr SizeTemplateBase() = default;
+ constexpr SizeTemplateBase( tools::Long nWidth, tools::Long nHeight ) : Pair( nWidth, nHeight ) {}
+
+ constexpr tools::Long Width() const { return mnA; }
+ constexpr tools::Long Height() const { return mnB; }
+
+};
+
+template<class SizeT>
+class SizeTemplate : public SizeTemplateBase
+{
+public:
+ constexpr SizeTemplate() {}
+ constexpr SizeTemplate( tools::Long nWidth, tools::Long nHeight ) : SizeTemplateBase( nWidth, nHeight ) {}
+
+ tools::Long AdjustWidth( tools::Long n ) { mnA += n; return mnA; }
+ tools::Long AdjustHeight( tools::Long n ) { mnB += n; return mnB; }
+
+ constexpr tools::Long getWidth() const { return Width(); }
+ constexpr tools::Long getHeight() const { return Height(); }
+ void setWidth(tools::Long nWidth) { mnA = nWidth; }
+ void setHeight(tools::Long nHeight) { mnB = nHeight; }
+
+ bool IsEmpty() const { return mnA <= 0 || mnB <= 0; }
+
+ void extendBy(tools::Long x, tools::Long y)
+ {
+ mnA += x;
+ mnB += y;
+ }
+
+ Pair const & toPair() const { return *this; }
+ Pair & toPair() { return *this; }
+
+ using Pair::toString;
+ using Pair::GetHashValue;
+
+ SizeT& operator += ( const SizeT& rSize )
+ {
+ mnA += rSize.mnA;
+ mnB += rSize.mnB;
+ return static_cast<SizeT&>(*this);
+ }
+ SizeT& operator -= ( const SizeT& rSize )
+ {
+ mnA -= rSize.mnA;
+ mnB -= rSize.mnB;
+ return static_cast<SizeT&>(*this);
+ }
+ SizeT& operator *= ( const tools::Long nVal )
+ {
+ mnA *= nVal;
+ mnB *= nVal;
+ return static_cast<SizeT&>(*this);
+ }
+ SizeT& operator /= ( const tools::Long nVal )
+ {
+ mnA /= nVal;
+ mnB /= nVal;
+ return static_cast<SizeT&>(*this);
+ }
+
+ constexpr SizeT scale(sal_Int64 nMulX, sal_Int64 nDivX,
+ sal_Int64 nMulY, sal_Int64 nDivY) const
+ {
+ return SizeT(o3tl::convert(Width(), nMulX, nDivX),
+ o3tl::convert(Height(), nMulY, nDivY));
+ }
+};
+
+class SAL_WARN_UNUSED Size : public SizeTemplate<::Size>
+{
+public:
+ constexpr Size() {}
+ constexpr Size( tools::Long nWidth, tools::Long nHeight ) : SizeTemplate( nWidth, nHeight ) {}
+ // TODO delete to find more problems
+ constexpr explicit Size(const AbsoluteScreenPixelSize& pt);
+};
+
+// Screen pixels
+class SAL_WARN_UNUSED AbsoluteScreenPixelSize : public SizeTemplate<AbsoluteScreenPixelSize>
+{
+public:
+ constexpr AbsoluteScreenPixelSize() {}
+ constexpr AbsoluteScreenPixelSize( tools::Long nWidth, tools::Long nHeight ) : SizeTemplate( nWidth, nHeight ) {}
+ constexpr explicit AbsoluteScreenPixelSize(const Size & pt) : SizeTemplate(pt.Width(), pt.Height()) {}
+};
+
+constexpr Size::Size(const AbsoluteScreenPixelSize& pt) : SizeTemplate(pt.Width(), pt.Height()) {}
+
+inline bool operator ==(Size const & s1, Size const & s2)
+{
+ return tools::detail::equal(s1.toPair(), s2.toPair());
+}
+inline bool operator ==(AbsoluteScreenPixelSize const & s1, AbsoluteScreenPixelSize const & s2)
+{
+ return tools::detail::equal(s1.toPair(), s2.toPair());
+}
+
+inline bool operator !=(Size const & s1, Size const & s2)
+{
+ return !(s1 == s2);
+}
+inline bool operator !=(AbsoluteScreenPixelSize const & s1, AbsoluteScreenPixelSize const & s2)
+{
+ return !(s1 == s2);
+}
+
+inline Size operator+( const Size &rVal1, const Size &rVal2 )
+{
+ return Size( rVal1.Width()+rVal2.Width(), rVal1.Height()+rVal2.Height() );
+}
+inline AbsoluteScreenPixelSize operator+( const AbsoluteScreenPixelSize &rVal1, const AbsoluteScreenPixelSize &rVal2 )
+{
+ return AbsoluteScreenPixelSize( rVal1.Width()+rVal2.Width(), rVal1.Height()+rVal2.Height() );
+}
+
+inline Size operator-( const Size &rVal1, const Size &rVal2 )
+{
+ return Size( rVal1.Width()-rVal2.Width(), rVal1.Height()-rVal2.Height() );
+}
+inline AbsoluteScreenPixelSize operator-( const AbsoluteScreenPixelSize &rVal1, const AbsoluteScreenPixelSize &rVal2 )
+{
+ return AbsoluteScreenPixelSize( rVal1.Width()-rVal2.Width(), rVal1.Height()-rVal2.Height() );
+}
+
+inline Size operator*( const Size &rVal1, const tools::Long nVal2 )
+{
+ return Size( rVal1.Width()*nVal2, rVal1.Height()*nVal2 );
+}
+inline AbsoluteScreenPixelSize operator*( const AbsoluteScreenPixelSize &rVal1, const tools::Long nVal2 )
+{
+ return AbsoluteScreenPixelSize( rVal1.Width()*nVal2, rVal1.Height()*nVal2 );
+}
+
+inline Size operator/( const Size &rVal1, const tools::Long nVal2 )
+{
+ return Size( rVal1.Width()/nVal2, rVal1.Height()/nVal2 );
+}
+inline AbsoluteScreenPixelSize operator/( const AbsoluteScreenPixelSize &rVal1, const tools::Long nVal2 )
+{
+ return AbsoluteScreenPixelSize( rVal1.Width()/nVal2, rVal1.Height()/nVal2 );
+}
+
+namespace o3tl
+{
+
+template <class SizeT,
+ std::enable_if_t<std::is_base_of_v<SizeTemplate<SizeT>, SizeT>, int> = 0>
+constexpr auto convert(const SizeT& rSize, o3tl::Length eFrom, o3tl::Length eTo)
+{
+ const auto [num, den] = o3tl::getConversionMulDiv(eFrom, eTo);
+ return rSize.scale(num, den, num, den);
+}
+
+} // end o3tl
+
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const SizeTemplateBase& size )
+{
+ return stream << size.Width() << 'x' << size.Height();
+}
+
+// Range
+
+#define RANGE_MAX LONG_MAX
+
+class SAL_WARN_UNUSED Range final : protected Pair
+{
+public:
+ constexpr Range() {}
+ constexpr Range( tools::Long nMin, tools::Long nMax ) : Pair( nMin, nMax ) {}
+
+ tools::Long Min() const { return mnA; }
+ tools::Long Max() const { return mnB; }
+ tools::Long Len() const { return mnB - mnA + 1; }
+
+ tools::Long& Min() { return mnA; }
+ tools::Long& Max() { return mnB; }
+
+ bool Contains( tools::Long nIs ) const;
+
+ void Normalize();
+
+ Pair const & toPair() const { return *this; }
+ Pair & toPair() { return *this; }
+
+ using Pair::toString;
+};
+
+inline bool Range::Contains( tools::Long nIs ) const
+{
+ return ((mnA <= nIs) && (nIs <= mnB ));
+}
+
+inline void Range::Normalize()
+{
+ if ( mnA > mnB )
+ std::swap(mnA, mnB);
+}
+
+inline bool operator ==(Range const & r1, Range const & r2)
+{
+ return tools::detail::equal(r1.toPair(), r2.toPair());
+}
+
+inline bool operator !=(Range const & r1, Range const & r2)
+{
+ return !(r1 == r2);
+}
+
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Range& range )
+{
+ return stream << range.Min() << '-' << range.Max();
+}
+
+// Selection
+
+#define SELECTION_MIN LONG_MIN
+#define SELECTION_MAX LONG_MAX
+
+class SAL_WARN_UNUSED Selection final : protected Pair
+{
+public:
+ Selection() {}
+ Selection( tools::Long nPos ) : Pair( nPos, nPos ) {}
+ Selection( tools::Long nMin, tools::Long nMax ) : Pair( nMin, nMax ) {}
+
+ tools::Long Min() const { return mnA; }
+ tools::Long Max() const { return mnB; }
+ tools::Long Len() const { return mnB - mnA; }
+
+ tools::Long& Min() { return mnA; }
+ tools::Long& Max() { return mnB; }
+
+ bool Contains( tools::Long nIs ) const;
+
+ void Normalize();
+
+ bool operator !() const { return !Len(); }
+
+ tools::Long getMin() const { return Min(); }
+ void setMin(tools::Long nMin) { Min() = nMin; }
+ void setMax(tools::Long nMax) { Max() = nMax; }
+
+ Pair const & toPair() const { return *this; }
+ Pair & toPair() { return *this; }
+
+ using Pair::toString;
+};
+
+inline bool Selection::Contains( tools::Long nIs ) const
+{
+ return ((mnA <= nIs) && (nIs < mnB ));
+}
+
+inline void Selection::Normalize()
+{
+ if ( mnA > mnB )
+ std::swap(mnA, mnB);
+}
+
+inline bool operator ==(Selection const & s1, Selection const & s2)
+{
+ return tools::detail::equal(s1.toPair(), s2.toPair());
+}
+
+inline bool operator !=(Selection const & s1, Selection const & s2)
+{
+ return !(s1 == s2);
+}
+
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const Selection& selection )
+{
+ return stream << selection.Min() << '-' << selection.Max();
+}
+// Rectangle
+
+#define RECT_MAX LONG_MAX
+#define RECT_MIN LONG_MIN
+
+/// Note: this class is a true marvel of engineering: because the author
+/// could not decide whether it's better to have a closed or half-open
+/// interval, they just implemented *both* in the same class!
+///
+/// If you have the misfortune of having to use this class, don't immediately
+/// despair but first take note that the uppercase GetWidth() / GetHeight()
+/// etc. methods interpret the interval as closed. To use the half open versions,
+/// use GetOpenWidth() / GetOpenHeight().
+///
+/// If you want to work with Size, you must use the closed interval functions!
+/// And don't add GetOpenSize() / setSize; this will probably just introduce
+/// bugs, especially when used in combination with list-initialization.
+///
+/// (Eventually you might notice, that the same engineer was also working on
+/// Qt at some point; see documentation on QRect::bottom / QRect::right ;-).
+
+class TOOLS_DLLPUBLIC RectangleTemplateBase
+{
+public:
+ static constexpr short RECT_EMPTY = -32767;
+
+ constexpr RectangleTemplateBase() = default;
+ constexpr RectangleTemplateBase( tools::Long nLeft, tools::Long nTop,
+ tools::Long nRight, tools::Long nBottom )
+ : mnLeft( nLeft ), mnTop( nTop ), mnRight( nRight ), mnBottom( nBottom )
+ {}
+ /// Constructs an empty Rectangle, with top/left at the specified params
+ constexpr RectangleTemplateBase( tools::Long nLeft, tools::Long nTop )
+ : mnLeft(nLeft), mnTop(nTop)
+ {}
+ /// Constructs a closed interval rectangle
+ constexpr RectangleTemplateBase( const PointTemplateBase& rLT, const SizeTemplateBase& rSize )
+ : mnLeft( rLT.X())
+ , mnTop( rLT.Y())
+ , mnRight(rSize.Width() ? mnLeft + (rSize.Width() + (rSize.Width() > 0 ? -1 : 1)) : RECT_EMPTY)
+ , mnBottom(rSize.Height() ? mnTop + (rSize.Height() + (rSize.Height() > 0 ? -1 : 1)) : RECT_EMPTY)
+ {}
+
+ constexpr tools::Long Left() const { return mnLeft; }
+ constexpr tools::Long Right() const { return IsWidthEmpty() ? mnLeft : mnRight; }
+ constexpr tools::Long Top() const { return mnTop; }
+ constexpr tools::Long Bottom() const { return IsHeightEmpty() ? mnTop : mnBottom; }
+
+ constexpr void SetLeft(tools::Long v) { mnLeft = v; }
+ constexpr void SetRight(tools::Long v) { mnRight = v; }
+ constexpr void SetTop(tools::Long v) { mnTop = v; }
+ constexpr void SetBottom(tools::Long v) { mnBottom = v; }
+
+ void SetEmpty() { mnRight = mnBottom = RECT_EMPTY; }
+ constexpr bool IsEmpty() const { return IsWidthEmpty() || IsHeightEmpty(); }
+ constexpr bool IsWidthEmpty() const { return mnRight == RECT_EMPTY; }
+ constexpr bool IsHeightEmpty() const { return mnBottom == RECT_EMPTY; }
+ void SetWidthEmpty() { mnRight = RECT_EMPTY; }
+ void SetHeightEmpty() { mnBottom = RECT_EMPTY; }
+
+ tools::Long getX() const { return mnLeft; }
+ tools::Long getY() const { return mnTop; }
+ /// Returns the difference between right and left, assuming the range includes one end, but not the other.
+ tools::Long getOpenWidth() const { return Right() - Left(); }
+ /// Returns the difference between bottom and top, assuming the range includes one end, but not the other.
+ tools::Long getOpenHeight() const { return Bottom() - Top(); }
+ void setWidth( tools::Long n ) { mnRight = mnLeft + n; }
+ void setHeight( tools::Long n ) { mnBottom = mnTop + n; }
+
+ /// Returns the difference between right and left, assuming the range is inclusive.
+ constexpr tools::Long GetWidth() const
+ {
+ tools::Long n = 0;
+
+ if (!IsWidthEmpty())
+ {
+ n = mnRight - mnLeft;
+ if (n < 0)
+ n--;
+ else
+ n++;
+ }
+
+ return n;
+ }
+ /// Returns the difference between bottom and top, assuming the range is inclusive.
+ constexpr tools::Long GetHeight() const
+ {
+ tools::Long n = 0;
+
+ if (!IsHeightEmpty())
+ {
+ n = mnBottom - mnTop;
+ if (n < 0)
+ n--;
+ else
+ n++;
+ }
+
+ return n;
+ }
+
+
+ tools::Long AdjustLeft( tools::Long nHorzMoveDelta ) { mnLeft += nHorzMoveDelta; return mnLeft; }
+ tools::Long AdjustRight( tools::Long nHorzMoveDelta );
+ tools::Long AdjustTop( tools::Long nVertMoveDelta ) { mnTop += nVertMoveDelta; return mnTop; }
+ tools::Long AdjustBottom( tools::Long nVertMoveDelta );
+ /// Set the left edge of the rectangle to x, preserving the width
+ void SetPosX(tools::Long x)
+ {
+ if (!IsWidthEmpty())
+ mnRight += x - mnLeft;
+ mnLeft = x;
+ }
+ /// Set the top edge of the rectangle to y, preserving the height
+ void SetPosY(tools::Long y)
+ {
+ if (!IsHeightEmpty())
+ mnBottom += y - mnTop;
+ mnTop = y;
+ }
+
+ void SaturatingSetPosX(tools::Long x);
+ void SaturatingSetPosY(tools::Long y);
+
+ void SetWidth(tools::Long nWidth)
+ {
+ if (nWidth < 0)
+ mnRight = mnLeft + nWidth + 1;
+ else if (nWidth > 0)
+ mnRight = mnLeft + nWidth - 1;
+ else
+ SetWidthEmpty();
+ }
+ void SetHeight(tools::Long nHeight)
+ {
+ if (nHeight < 0)
+ mnBottom = mnTop + nHeight + 1;
+ else if (nHeight > 0)
+ mnBottom = mnTop + nHeight - 1;
+ else
+ SetHeightEmpty();
+ }
+
+ void Normalize();
+
+ /**
+ * Expands the rectangle in all directions by the input value.
+ */
+ void expand(tools::Long nExpandBy);
+ void shrink(tools::Long nShrinkBy);
+
+ /// Move the top and left edges by a delta, preserving width and height
+ void Move( tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta )
+ {
+ mnLeft += nHorzMoveDelta;
+ mnTop += nVertMoveDelta;
+ if (!IsWidthEmpty())
+ mnRight += nHorzMoveDelta;
+ if (!IsHeightEmpty())
+ mnBottom += nVertMoveDelta;
+ }
+
+ /// Returns the string representation of the rectangle, format is "x, y, width, height".
+ rtl::OString toString() const;
+
+protected:
+ void SaturatingSetSize(const SizeTemplateBase& rSize);
+ void Union( const RectangleTemplateBase& rRect );
+ void Intersection( const RectangleTemplateBase& rRect );
+ bool Contains( const PointTemplateBase& rPOINT ) const;
+ bool Contains( const RectangleTemplateBase& rRect ) const;
+ bool Overlaps( const RectangleTemplateBase& rRect ) const;
+
+ tools::Long mnLeft = 0;
+ tools::Long mnTop = 0;
+ tools::Long mnRight = RECT_EMPTY;
+ tools::Long mnBottom = RECT_EMPTY;
+};
+
+template<class RectangleT, class PointT, class SizeT>
+class RectangleTemplate : public RectangleTemplateBase
+{
+friend class ::tools::Rectangle;
+friend class AbsoluteScreenPixelRectangle;
+public:
+ using PointType = PointT;
+ using SizeType = SizeT;
+
+public:
+ constexpr RectangleTemplate() = default;
+ constexpr RectangleTemplate( const PointT& rLT, const PointT& rRB )
+ : RectangleTemplate(rLT.X(), rLT.Y(), rRB.X(), rRB.Y()) {}
+ constexpr RectangleTemplate( tools::Long nLeft, tools::Long nTop,
+ tools::Long nRight, tools::Long nBottom )
+ : RectangleTemplateBase(nLeft, nTop, nRight, nBottom )
+ {}
+ /// Constructs an empty Rectangle, with top/left at the specified params
+ constexpr RectangleTemplate( tools::Long nLeft, tools::Long nTop )
+ : RectangleTemplateBase(nLeft, nTop)
+ {}
+ /// Constructs a closed interval rectangle
+ constexpr RectangleTemplate( const PointT& rLT, const SizeT& rSize )
+ : RectangleTemplateBase( rLT, rSize )
+ {}
+
+ using RectangleTemplateBase::Normalize;
+ constexpr static RectangleT Normalize(const PointT& rLT, const PointT& rRB)
+ {
+ const std::pair<tools::Long, tools::Long> aLeftRight = std::minmax(rLT.X(), rRB.X());
+ const std::pair<tools::Long, tools::Long> aTopBottom = std::minmax(rLT.Y(), rRB.Y());
+ return { aLeftRight.first, aTopBottom.first, aLeftRight.second, aTopBottom.second };
+ }
+
+ constexpr PointT TopLeft() const { return { Left(), Top() }; }
+ constexpr PointT TopRight() const { return { Right(), Top() }; }
+ constexpr PointT TopCenter() const { return { (Left() + Right()) / 2, Top() }; }
+ constexpr PointT BottomLeft() const { return { Left(), Bottom() }; }
+ constexpr PointT BottomRight() const { return { Right(), Bottom() }; }
+ constexpr PointT BottomCenter() const { return { (Left() + Right()) / 2, Bottom() }; }
+ constexpr PointT LeftCenter() const { return { Left(), (Top() + Bottom()) / 2 }; }
+ constexpr PointT RightCenter() const { return { Right(), (Top() + Bottom()) / 2 }; }
+ constexpr PointT Center() const { return { (Left() + Right()) / 2, (Top() + Bottom()) / 2 }; }
+
+ using RectangleTemplateBase::Move;
+ void Move( SizeT const & s ) { Move(s.Width(), s.Height()); }
+ void SetPos( const PointT& rPoint )
+ {
+ SetPosX(rPoint.X());
+ SetPosY(rPoint.Y());
+ }
+ void SetSize(const SizeT& rSize)
+ {
+ SetWidth(rSize.Width());
+ SetHeight(rSize.Height());
+ }
+
+ constexpr PointT GetPos() const { return TopLeft(); }
+ constexpr SizeT GetSize() const { return { GetWidth(), GetHeight() }; }
+
+ RectangleT& Union( const RectangleTemplate& rRect ) { RectangleTemplateBase::Union(rRect); return static_cast<RectangleT&>(*this); }
+ RectangleT& Intersection( const RectangleTemplate& rRect ) { RectangleTemplateBase::Intersection(rRect); return static_cast<RectangleT&>(*this); }
+ RectangleT GetUnion( const RectangleT& rRect ) const
+ {
+ RectangleT aTmpRect( rRect );
+ return aTmpRect.Union( *this );
+ }
+ RectangleT GetIntersection( const RectangleT& rRect ) const
+ {
+ RectangleT aTmpRect( rRect );
+ return aTmpRect.Intersection( *this );
+ }
+
+ bool Contains( const PointT& rPt ) const { return RectangleTemplateBase::Contains(rPt); }
+ bool Contains( const RectangleT& rRect ) const { return RectangleTemplateBase::Contains(rRect); }
+ bool Overlaps( const RectangleT& rRect ) const { return RectangleTemplateBase::Overlaps(rRect); }
+
+ bool operator == ( const RectangleTemplate& rRect ) const
+ {
+ return (mnLeft == rRect.mnLeft ) &&
+ (mnTop == rRect.mnTop ) &&
+ (mnRight == rRect.mnRight ) &&
+ (mnBottom == rRect.mnBottom );
+ }
+ bool operator != ( const RectangleTemplate& rRect ) const
+ {
+ return (mnLeft != rRect.mnLeft ) ||
+ (mnTop != rRect.mnTop ) ||
+ (mnRight != rRect.mnRight ) ||
+ (mnBottom != rRect.mnBottom );
+ }
+
+ RectangleT& operator += ( const PointT& rPt )
+ {
+ Move(rPt.X(), rPt.Y());
+ return static_cast<RectangleT&>(*this);
+ }
+ RectangleT& operator -= ( const PointT& rPt )
+ {
+ Move(-rPt.X(), -rPt.Y());
+ return static_cast<RectangleT&>(*this);
+ }
+
+ RectangleT operator+( const Point& rPt ) const
+ {
+ RectangleT aTmp(mnLeft, mnTop, mnRight, mnBottom);
+ aTmp += rPt;
+ return aTmp;
+ }
+ RectangleT operator-( const Point& rPt ) const
+ {
+ RectangleT aTmp(mnLeft, mnTop, mnRight, mnBottom);
+ aTmp -= rPt;
+ return aTmp;
+ }
+
+ /**
+ * Sanitizing variants for handling data from the outside
+ */
+ void SaturatingSetSize(const SizeT& rSize) { RectangleTemplateBase::SaturatingSetSize(rSize); }
+
+ // Scales relative to 0,0
+ constexpr RectangleT scale(sal_Int64 nMulX, sal_Int64 nDivX,
+ sal_Int64 nMulY, sal_Int64 nDivY) const
+ {
+ // 1. Create an empty rectangle with correct left and top
+ RectangleT aRect(o3tl::convert(Left(), nMulX, nDivX),
+ o3tl::convert(Top(), nMulY, nDivY));
+ // 2. If source has width/height, set respective right and bottom
+ if (!IsWidthEmpty())
+ aRect.SetRight(o3tl::convert(Right(), nMulX, nDivX));
+ if (!IsHeightEmpty())
+ aRect.SetBottom(o3tl::convert(Bottom(), nMulY, nDivY));
+ return aRect;
+ }
+};
+
+namespace tools
+{
+class SAL_WARN_UNUSED Rectangle final : public RectangleTemplate<Rectangle, Point, Size>
+{
+public:
+ using RectangleTemplate::RectangleTemplate;
+ // TODO remove this to find more issues
+ constexpr Rectangle(const AbsoluteScreenPixelPoint& pt, const Size& sz) : RectangleTemplate(Point(pt.X(), pt.Y()), sz) {}
+ // TODO remove this to find more issues
+ constexpr Rectangle(const Point& pt, const AbsoluteScreenPixelSize& sz) : RectangleTemplate(pt, Size(sz.Width(), sz.Height())) {}
+ // TODO remove this to find more issues
+ constexpr explicit Rectangle(const AbsoluteScreenPixelRectangle & r);
+};
+
+} // namespace tools
+
+
+// A rectangle relative to top-level screen, in screen pixels
+class SAL_WARN_UNUSED AbsoluteScreenPixelRectangle : public RectangleTemplate<AbsoluteScreenPixelRectangle, AbsoluteScreenPixelPoint, AbsoluteScreenPixelSize> {
+public:
+ using RectangleTemplate::RectangleTemplate;
+ // TODO remove
+ constexpr explicit AbsoluteScreenPixelRectangle(const tools::Rectangle & r) : RectangleTemplate(r.mnLeft, r.mnTop, r.mnRight, r.mnBottom) {}
+ // TODO remove
+ constexpr AbsoluteScreenPixelRectangle(const AbsoluteScreenPixelPoint& pt, const Size& sz) : RectangleTemplate(pt, AbsoluteScreenPixelSize(sz.Width(), sz.Height())) {}
+};
+
+namespace tools
+{
+ constexpr Rectangle::Rectangle(const AbsoluteScreenPixelRectangle & r) : RectangleTemplate(r.mnLeft, r.mnTop, r.mnRight, r.mnBottom) {}
+}
+
+namespace o3tl
+{
+
+template <class RectangleT,
+ std::enable_if_t<std::is_base_of_v<RectangleTemplate<RectangleT, typename RectangleT::PointType, typename RectangleT::SizeType>, RectangleT>, int> = 0>
+constexpr auto convert(const RectangleT& rRectangle, o3tl::Length eFrom, o3tl::Length eTo)
+{
+ const auto [num, den] = o3tl::getConversionMulDiv(eFrom, eTo);
+ return rRectangle.scale(num, den, num, den);
+}
+
+} // end o3tl
+
+template< typename charT, typename traits >
+inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const RectangleTemplateBase& rectangle )
+{
+ if (rectangle.IsEmpty())
+ return stream << "EMPTY";
+ else
+ return stream << rectangle.GetWidth() << 'x' << rectangle.GetHeight()
+ << "@(" << rectangle.getX() << ',' << rectangle.getY() << ")";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */