diff --git a/src/tests/kits/interface/NewRegion/ClipRegion.cpp b/src/tests/kits/interface/NewRegion/ClipRegion.cpp new file mode 100644 index 0000000000..9c84550adb --- /dev/null +++ b/src/tests/kits/interface/NewRegion/ClipRegion.cpp @@ -0,0 +1,529 @@ +#include +#include + +#include "clipping.h" +#include "ClipRegion.h" + +#include + +const static int32 kMaxPoints = 1024; +const static int32 kMaxVerticalExtent = 0x10000000; +const static int32 kMaxPositive = 0x7ffffffd; +const static int32 kMaxNegative = 0x80000003; +const static int32 kInitialDataSize = 8; + + +ClipRegion::ClipRegion() + : + fDataSize(0), + fData(NULL) +{ + _Resize(kInitialDataSize); + _Invalidate(); +} + + +ClipRegion::ClipRegion(const ClipRegion ®ion) + : + fDataSize(0), + fData(NULL) +{ + *this = region; +} + + +ClipRegion::ClipRegion(const clipping_rect &rect) + : + fDataSize(0), + fData(NULL) +{ + Set(rect); +} + + +ClipRegion::ClipRegion(const BRect &rect) + : + fDataSize(0), + fData(NULL) +{ + Set(rect); +} + + +ClipRegion::ClipRegion(const clipping_rect *rects, const int32 &count) + : + fDataSize(0), + fData(NULL) +{ + Set(rects, count); +} + + +ClipRegion::~ClipRegion() +{ + free(fData); +} + + +void +ClipRegion::Set(const clipping_rect &rect) +{ + if (!valid_rect(rect) || (fDataSize <= 1 && !_Resize(kInitialDataSize))) + _Invalidate(); + else { + fCount = 1; + fData[0] = fBound = rect; + } +} + + +void +ClipRegion::Set(const BRect &rect) +{ + Set(to_clipping_rect(rect)); +} + + +void +ClipRegion::Set(const clipping_rect *rects, const int32 &count) +{ + _Invalidate(); + _Append(rects, count); +} + + +bool +ClipRegion::Intersects(const clipping_rect &rect) const +{ + if (!rects_intersect(rect, fBound)) + return false; + + for (int32 c = 0; c < fCount; c++) { + if (rects_intersect(fData[c], rect)) + return true; + } + + return false; +} + + +bool +ClipRegion::Intersects(const BRect &rect) const +{ + return Intersects(to_clipping_rect(rect)); +} + + +bool +ClipRegion::Contains(const BPoint &pt) const +{ + // If the point doesn't lie within the region's bounds, + // don't even try it against the region's rects. + if (!point_in(fBound, pt)) + return false; + + for (int32 c = 0; c < fCount; c++) { + if (point_in(fData[c], pt)) + return true; + } + + return false; +} + + +void +ClipRegion::OffsetBy(const int32 &dh, const int32 &dv) +{ + if (fCount > 0) { + for (int32 c = 0; c < fCount; c++) + offset_rect(fData[c], dh, dv); + + offset_rect(fBound, dh, dv); + } +} + + +void +ClipRegion::OffsetBy(const BPoint &point) +{ + return OffsetBy((int32)point.x, (int32)point.y); +} + + +void +ClipRegion::IntersectWith(const clipping_rect &rect) +{ + if (!rects_intersect(rect, fBound)) + _Invalidate(); + else + _IntersectWith(rect); +} + + +void +ClipRegion::IntersectWith(const BRect &rect) +{ + IntersectWith(to_clipping_rect(rect)); +} + + +void +ClipRegion::IntersectWith(const ClipRegion ®ion) +{ + clipping_rect intersection = sect_rect(fBound, region.fBound); + + if (fCount == 0 || region.fCount == 0 || !valid_rect(intersection)) + _Invalidate(); + + else if (fCount == 1 && region.fCount == 1) + Set(intersection); + + else if (fCount > 1 && region.fCount == 1) + _IntersectWith(region.fBound); + + else if (fCount == 1 && region.fCount > 1) { + ClipRegion dest = region; + dest._IntersectWith(fBound); + _Adopt(dest); + + } else + _IntersectWithComplex(region); +} + + +void +ClipRegion::Include(const clipping_rect &rect) +{ + // The easy case first: if the rectangle completely contains + // ourself, the union is the rectangle itself. + if (rect.top <= fBound.top + && rect.bottom >= fBound.bottom + && rect.left <= fBound.left + && rect.right >= fBound.right) + Set(rect); + else { + const ClipRegion region(rect); + _IncludeComplex(region); + } +} + + +void +ClipRegion::Include(const BRect &rect) +{ + Include(to_clipping_rect(rect)); +} + + +void +ClipRegion::Include(const ClipRegion ®ion) +{ + if (region.fCount == 0) + return; + + if (fCount == 0) + *this = region; + + else if (region.fBound.top > fBound.bottom) + _Append(region); + + else if (fBound.top > region.fBound.bottom) + _Append(region, true); + /* + else if (regionA->bound.left > regionB->bound.right) + OrRegionNoX(*regionB, *regionA, dest); + + else if (regionB->bound.left > regionA->bound.right) + OrRegionNoX(*regionA, *regionB, dest); + */ + else if (region.fCount == 1) + Include(region.fBound); + + else if (fCount == 1) { + ClipRegion dest = region; + dest.Include(fBound); + _Adopt(dest); + } else + _IncludeComplex(region); +} + + +void +ClipRegion::Exclude(const clipping_rect &rect) +{ + const ClipRegion region(rect); + Exclude(region); +} + + +void +ClipRegion::Exclude(const BRect &rect) +{ + const ClipRegion region(rect); + Exclude(region); +} + + +void +ClipRegion::Exclude(const ClipRegion ®ion) +{ + if (fCount == 0) + return; + + if (region.fCount == 0 || !rects_intersect(fBound, region.fBound)) + *this = region; + else + _ExcludeComplex(region); +} + + +ClipRegion & +ClipRegion::operator=(const ClipRegion ®ion) +{ + const int32 size = region.fDataSize > 0 ? region.fDataSize : kInitialDataSize; + if (_Resize(size, false)) { + fBound = region.fBound; + fCount = region.fCount; + memcpy(fData, region.fData, fCount * sizeof(clipping_rect)); + } else + _Invalidate(); + + return *this; +} + + +// private methods +void +ClipRegion::_IntersectWithComplex(const ClipRegion ®ion) +{ + ClipRegion dest(*this); + + for (int32 f = 0; f < fCount; f++) { + for (int32 s = 0; s < region.fCount; s++) { + clipping_rect testRect = sect_rect(fData[f], region.fData[s]); + if (valid_rect(testRect)) + dest._AddRect(testRect); + } + } + + if (dest.fCount > 1) + dest._SortRects(); + + _Adopt(dest); +} + + +void +ClipRegion::_IntersectWith(const clipping_rect &rect) +{ + ASSERT(rects_intersect(rect, fBound)); + + // The easy case first: We already know that the region intersects, + // with the passed rect, so we check if the rect completely contains + // the region. + // If it's the case, the intersection is exactly the region itself. + if (rect.top <= fBound.top && rect.bottom >= fBound.bottom + && rect.left <= fBound.left && rect.right >= fBound.right) + return; + + // Otherwise, we add the intersections of the region's rects + // with the passed rect + ClipRegion dest; + for (int32 x = 0; x < fCount; x++) { + clipping_rect testRect = sect_rect(rect, fData[x]); + if (valid_rect(testRect)) + dest._AddRect(testRect); + } + _Adopt(dest); +} + + +void +ClipRegion::_IncludeComplex(const ClipRegion ®ion) +{ + +} + + +void +ClipRegion::_ExcludeComplex(const ClipRegion ®ion) +{ +} + + +// Helper method to swap two rects +static inline void +SwapRects(clipping_rect &rect, clipping_rect &anotherRect) +{ + clipping_rect tmpRect = rect; + rect = anotherRect; + anotherRect = tmpRect; +} + + +void +ClipRegion::_SortRects() +{ + bool again; + + if (fCount == 2) { + if (fData[0].top > fData[1].top) + SwapRects(fData[0], fData[1]); + + } else if (fCount > 2) { + do { + again = false; + for (int32 c = 1; c < fCount; c++) { + if (fData[c - 1].top > fData[c].top) { + SwapRects(fData[c - 1], fData[c]); + again = true; + } + } + } while (again); + } +} + + +void +ClipRegion::_AddRect(const clipping_rect &rect) +{ + ASSERT(fCount >= 0); + ASSERT(fDataSize >= 0); + ASSERT(valid_rect(rect)); + + // Should we just reallocate the memory and + // copy the rect ? + bool addRect = true; + + if (fCount > 0) { + // Wait! We could merge the rect with one of the + // existing rectangles, if it's adiacent. + // We just check it against the last rectangle, since + // we are keeping them sorted by their "top" coordinates. + int32 last = fCount - 1; + if (rect.left == fData[last].left && rect.right == fData[last].right + && rect.top == fData[last].bottom + 1) { + + fData[last].bottom = rect.bottom; + addRect = false; + + } else if (rect.top == fData[last].top && rect.bottom == fData[last].bottom) { + if (rect.left == fData[last].right + 1) { + + fData[last].right = rect.right; + addRect = false; + + } else if (rect.right == fData[last].left - 1) { + + fData[last].left = rect.left; + addRect = false; + } + } + } + + // We weren't lucky.... just add the rect as a new one + if (addRect) { + if (fDataSize <= fCount) + _Resize(fCount + 16); + + fData[fCount] = rect; + + fCount++; + } + + _RecalculateBounds(rect); +} + + +void +ClipRegion::_RecalculateBounds(const clipping_rect &rect) +{ + if (fCount <= 0) + return; + + if (rect.top < fBound.top) + fBound.top = rect.top; + if (rect.left < fBound.left) + fBound.left = rect.left; + if (rect.right > fBound.right) + fBound.right = rect.right; + if (rect.bottom > fBound.bottom) + fBound.bottom = rect.bottom; +} + + +void +ClipRegion::_Append(const ClipRegion ®ion, const bool &aboveThis) +{ + if (aboveThis) { + ClipRegion dest = region; + for (int32 c = 0; c < fCount; c++) + dest._AddRect(fData[c]); + _Adopt(dest); + } else { + for (int32 c = 0; c < region.fCount; c++) + _AddRect(region.fData[c]); + } +} + + +void +ClipRegion::_Append(const clipping_rect *rects, const int32 &count, const bool &aboveThis) +{ + if (aboveThis) { + ClipRegion dest; + dest.Set(rects, count); + for (int32 c = 0; c < fCount; c++) + dest._AddRect(fData[c]); + _Adopt(dest); + } else { + for (int32 c = 0; c < count; c++) + _AddRect(rects[c]); + } +} + + +void +ClipRegion::_Invalidate() +{ + fCount = 0; + fBound.left = kMaxPositive; + fBound.top = kMaxPositive; + fBound.right = kMaxNegative; + fBound.bottom = kMaxNegative; +} + + +bool +ClipRegion::_Resize(const int32 &newSize, const bool &keepOld) +{ + if (!keepOld) { + free(fData); + fData = (clipping_rect *)malloc(newSize * sizeof(clipping_rect)); + } else + fData = (clipping_rect *)realloc(fData, newSize * sizeof(clipping_rect)); + + if (fData == NULL) + return false; + + fDataSize = newSize; + + return true; +} + + +void +ClipRegion::_Adopt(ClipRegion ®ion) +{ + free(fData); + fData = region.fData; + fDataSize = region.fDataSize; + fCount = region.fCount; + fBound = region.fBound; + + region._Invalidate(); + region.fDataSize = 0; + region.fData = NULL; +} + + diff --git a/src/tests/kits/interface/NewRegion/ClipRegion.h b/src/tests/kits/interface/NewRegion/ClipRegion.h new file mode 100644 index 0000000000..eec44e5890 --- /dev/null +++ b/src/tests/kits/interface/NewRegion/ClipRegion.h @@ -0,0 +1,83 @@ +#ifndef __CLIPREGION_H +#define __CLIPREGION_H + +#include "Region.h" // for clipping_rect + +class ServerLink; + +class ClipRegion { +public: + ClipRegion(); + ClipRegion(const ClipRegion ®ion); + ClipRegion(const BRegion ®ion); + ClipRegion(const clipping_rect &rect); + ClipRegion(const BRect &rect); + ClipRegion(const clipping_rect *rects, const int32 &count); + + ~ClipRegion(); + + clipping_rect Frame() const { return fBound; } + clipping_rect RectAt(const int32 &index) const + { + if (index >= 0 && index < fCount) + return fData[index]; + clipping_rect rect = { 0, 0, -1, -1 }; + return rect; + } + + int32 CountRects() const { return fCount; } + + void Set(const clipping_rect &rect); + void Set(const BRect &rect); + void Set(const clipping_rect *rects, const int32 &count); + + bool Intersects(const clipping_rect &rect) const; + bool Intersects(const BRect &rect) const; + bool Intersects(const ClipRegion ®ion) const; + + bool Contains(const BPoint &point) const; + + void OffsetBy(const int32 &dx, const int32 &dy); + void OffsetBy(const BPoint &point); + + void Include(const clipping_rect &rect); + void Include(const BRect &rect); + void Include(const ClipRegion ®ion); + + void Exclude(const clipping_rect &rect); + void Exclude(const BRect &rect); + void Exclude(const ClipRegion ®ion); + + void IntersectWith(const clipping_rect &rect); + void IntersectWith(const BRect &rect); + void IntersectWith(const ClipRegion ®ion); + + ClipRegion &operator=(const ClipRegion ®ion); + + status_t ReadFromLink(ServerLink &link); + status_t WriteToLink(ServerLink &link); + +private: + int32 fCount; + int32 fDataSize; + clipping_rect fBound; + clipping_rect *fData; + + void _Append(const ClipRegion ®ion, const bool &aboveThis = false); + void _Append(const clipping_rect *rects, const int32 &count, const bool &aboveThis = false); + + void _IntersectWithComplex(const ClipRegion ®ion); + void _IntersectWith(const clipping_rect &rect); + void _IncludeComplex(const ClipRegion ®ion); + void _ExcludeComplex(const ClipRegion ®ion); + + void _SortRects(); + void _AddRect(const clipping_rect &rect); + void _RecalculateBounds(const clipping_rect &newRect); + + void _Invalidate(); + bool _Resize(const int32 &newSize, const bool &keepOld = true); + void _Adopt(ClipRegion ®ion); +}; + +#endif // __CLIPREGION_H diff --git a/src/tests/kits/interface/NewRegion/Region.cpp b/src/tests/kits/interface/NewRegion/Region.cpp new file mode 100644 index 0000000000..cbfa696e64 --- /dev/null +++ b/src/tests/kits/interface/NewRegion/Region.cpp @@ -0,0 +1,348 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2003-2005, Haiku, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: Region.cpp +// Author: Stefano Ceccherini (burton666@libero.it) +// Description: Region class consisting of multiple rectangles +// +//------------------------------------------------------------------------------ + +// Notes: As now, memory is always allocated and never freed (except on destruction, +// or sometimes when a copy is made). +// This let us be a bit faster since we don't do many reallocations. +// But that means that even an empty region could "waste" much space, if it contained +// many rects before being emptied. +// I.E: a region which contains 24 rects allocates more than 24 * 4 * sizeof(int32) +// = 96 * sizeof(int32) bytes. If we call MakeEmpty(), that region will contain no rects, +// but it will still keep the allocated memory. +// This shouldnt' be an issue, since usually BRegions are just used for calculations, +// and don't last so long. +// Anyway, we can change that behaviour if we want, but BeOS's BRegion seems to behave exactly +// like this. + + +#include +#include + +#include + +#include +#include + +#include +#include + + + +/*! \brief Initializes a region. The region will have no rects, + and its bound will be invalid. +*/ +BRegion::BRegion() + : + fRegion(new (nothrow) ClipRegion) +{ +} + + +/*! \brief Initializes a region to be a copy of another. + \param region The region to copy. +*/ +BRegion::BRegion(const BRegion ®ion) + : + fRegion(new (nothrow) ClipRegion(*region.fRegion)) +{ +} + + +/*! \brief Initializes a region to contain a BRect. + \param rect The BRect to set the region to. +*/ +BRegion::BRegion(const BRect rect) + : + fRegion(new (nothrow) ClipRegion(to_clipping_rect(rect))) +{ +} + + +/*! \brief Frees the allocated memory. +*/ +BRegion::~BRegion() +{ + delete fRegion; +} + + +/*! \brief Returns the bounds of the region. + \return A BRect which represents the bounds of the region. +*/ +BRect +BRegion::Frame() const +{ + return fRegion ? to_BRect(fRegion->Frame()) : BRect(); +} + + +/*! \brief Returns the bounds of the region as a clipping_rect (which has integer coordinates). + \return A clipping_rect which represents the bounds of the region. +*/ +clipping_rect +BRegion::FrameInt() const +{ + return fRegion ? fRegion->Frame() : to_clipping_rect(BRect()); +} + + +/*! \brief Returns the regions's BRect at the given index. + \param index The index (zero based) of the wanted rectangle. + \return If the given index is valid, it returns the BRect at that index, + otherwise, it returns an invalid BRect. +*/ +BRect +BRegion::RectAt(int32 index) +{ + return fRegion ? to_BRect(fRegion->RectAt(index)) : BRect(); +} + + +/*! \brief Returns the regions's clipping_rect at the given index. + \param index The index (zero based) of the wanted rectangle. + \return If the given index is valid, it returns the clipping_rect at that index, + otherwise, it returns an invalid clipping_rect. +*/ +clipping_rect +BRegion::RectAtInt(int32 index) +{ + return fRegion ? fRegion->RectAt(index) : to_clipping_rect(BRect()); +} + + +/*! \brief Counts the region rects. + \return An int32 which is the total number of rects in the region. +*/ +int32 +BRegion::CountRects() +{ + return fRegion ? fRegion->CountRects() : 0; +} + + +/*! \brief Set the region to contain just the given BRect. + \param newBounds A BRect. +*/ +void +BRegion::Set(BRect newBounds) +{ + Set(to_clipping_rect(newBounds)); +} + + +/*! \brief Set the region to contain just the given clipping_rect. + \param newBounds A clipping_rect. +*/ +void +BRegion::Set(clipping_rect newBounds) +{ + if (fRegion) + fRegion->Set(newBounds); + else + fRegion = new (nothrow) ClipRegion(newBounds); +} + + +/*! \brief Check if the region has any area in common with the given BRect. + \param rect The BRect to check the region against to. + \return \ctrue if the region has any area in common with the BRect, \cfalse if not. +*/ +bool +BRegion::Intersects(BRect rect) const +{ + return fRegion ? fRegion->Intersects(to_clipping_rect(rect)) : false; +} + + +/*! \brief Check if the region has any area in common with the given clipping_rect. + \param rect The clipping_rect to check the region against to. + \return \ctrue if the region has any area in common with the clipping_rect, \cfalse if not. +*/ +bool +BRegion::Intersects(clipping_rect rect) const +{ + return fRegion ? fRegion->Intersects(rect) : false; +} + + +/*! \brief Check if the region contains the given BPoint. + \param pt The BPoint to be checked. + \return \ctrue if the region contains the BPoint, \cfalse if not. +*/ +bool +BRegion::Contains(BPoint pt) const +{ + return fRegion ? fRegion->Contains(pt) : false; +} + + +/*! \brief Check if the region contains the given coordinates. + \param x The \cx coordinate of the point to be checked. + \param y The \cy coordinate of the point to be checked. + \return \ctrue if the region contains the point, \cfalse if not. +*/ +bool +BRegion::Contains(int32 x, int32 y) +{ + if (fRegion == NULL) + return false; + + const BPoint pt(x, y); + return fRegion->Contains(pt); +} + + +/*! \brief Prints the BRegion to stdout. +*/ +void +BRegion::PrintToStream() const +{ + if (fRegion == NULL) + return; + + Frame().PrintToStream(); + + for (int32 c = 0; c < fRegion->CountRects(); c++) { + clipping_rect rect = fRegion->RectAt(c); + printf("data = BRect(l:%ld.0, t:%ld.0, r:%ld.0, b:%ld.0)\n", + rect.left, rect.top, rect.right, rect.bottom); + } +} + + +/*! \brief Offsets all region's rects, and bounds by the given values. + \param dh The horizontal offset. + \param dv The vertical offset. +*/ +void +BRegion::OffsetBy(int32 dh, int32 dv) +{ + if (fRegion != NULL) + fRegion->OffsetBy(dh, dv); +} + + +/*! \brief Empties the region, so that it doesn't include any rect, and invalidates its bounds. +*/ +void +BRegion::MakeEmpty() +{ + clipping_rect invalid = { 0, 0, -1, -1 }; + Set(invalid); +} + + +/*! \brief Modifies the region, so that it includes the given BRect. + \param rect The BRect to be included by the region. +*/ +void +BRegion::Include(BRect rect) +{ + Include(to_clipping_rect(rect)); +} + + +/*! \brief Modifies the region, so that it includes the given clipping_rect. + \param rect The clipping_rect to be included by the region. +*/ +void +BRegion::Include(clipping_rect rect) +{ + if (fRegion != NULL) + fRegion->Include(rect); +} + + +/*! \brief Modifies the region, so that it includes the area of the given region. + \param region The region to be included. +*/ +void +BRegion::Include(const BRegion *region) +{ + if (fRegion != NULL) + fRegion->Include(*region->fRegion); +} + + +/*! \brief Modifies the region, excluding the area represented by the given BRect. + \param rect The BRect to be excluded. +*/ +void +BRegion::Exclude(BRect rect) +{ + if (fRegion) + fRegion->Exclude(to_clipping_rect(rect)); +} + + +/*! \brief Modifies the region, excluding the area represented by the given clipping_rect. + \param rect The clipping_rect to be excluded. +*/ +void +BRegion::Exclude(clipping_rect rect) +{ + if (fRegion) + fRegion->Exclude(rect); +} + + +/*! \brief Modifies the region, excluding the area contained in the given BRegion. + \param region The BRegion to be excluded. +*/ +void +BRegion::Exclude(const BRegion *region) +{ + if (fRegion) + fRegion->Exclude(*region->fRegion); +} + + +/*! \brief Modifies the region, so that it will contain just the area in common with the given BRegion. + \param region the BRegion to intersect to. +*/ +void +BRegion::IntersectWith(const BRegion *region) +{ + if (fRegion) + fRegion->IntersectWith(*region->fRegion); +} + + +/*! \brief Modifies the region to be a copy of the given BRegion. + \param region the BRegion to copy. + \return This function always returns \c *this. +*/ +BRegion & +BRegion::operator=(const BRegion ®ion) +{ + if (®ion != this) { + delete fRegion; + fRegion = new (nothrow) ClipRegion(*region.fRegion); + } + + return *this; +} diff --git a/src/tests/kits/interface/NewRegion/Region.h b/src/tests/kits/interface/NewRegion/Region.h new file mode 100644 index 0000000000..1e22b86ae2 --- /dev/null +++ b/src/tests/kits/interface/NewRegion/Region.h @@ -0,0 +1,71 @@ +/******************************************************************************* +/ +/ File: Region.h +/ +/ Description: BRegion represents an area that's composed of individual +/ rectangles. +/ +/ Copyright 1992-98, Be Incorporated, All Rights Reserved +/ +*******************************************************************************/ + +#ifndef _REGION_H +#define _REGION_H + +#include +#include + +namespace BPrivate { + class ServerLink; +}; + + +/* Integer rect used to define a cliping rectangle. All bounds are included */ +/* Moved from DirectWindow.h */ +typedef struct { + int32 left; + int32 top; + int32 right; + int32 bottom; +} clipping_rect; + + +/*----- BRegion class --------------------------------------------*/ +class ClipRegion; +class BRegion { +public: + BRegion(); + BRegion(const BRegion ®ion); + BRegion(const BRect rect); +virtual ~BRegion(); + + BRegion &operator=(const BRegion &from); + + BRect Frame() const; +clipping_rect FrameInt() const; + BRect RectAt(int32 index); +clipping_rect RectAtInt(int32 index); + int32 CountRects(); + void Set(BRect newBounds); + void Set(clipping_rect newBounds); + bool Intersects(BRect r) const; + bool Intersects(clipping_rect r) const; + bool Contains(BPoint pt) const; + bool Contains(int32 x, int32 y); + void PrintToStream() const; + void OffsetBy(int32 dh, int32 dv); + void MakeEmpty(); + void Include(BRect r); + void Include(clipping_rect r); + void Include(const BRegion*); + void Exclude(BRect r); + void Exclude(clipping_rect r); + void Exclude(const BRegion*); + void IntersectWith(const BRegion*); + +/*----- Private or reserved -----------------------------------------*/ +private: + ClipRegion *fRegion; +}; + +#endif /* _REGION_H */ diff --git a/src/tests/kits/interface/NewRegion/clipping.h b/src/tests/kits/interface/NewRegion/clipping.h new file mode 100644 index 0000000000..11a2be3002 --- /dev/null +++ b/src/tests/kits/interface/NewRegion/clipping.h @@ -0,0 +1,172 @@ +//------------------------------------------------------------------------------ +// Copyright (c) 2001-2004, Haiku, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the "Software"), +// to deal in the Software without restriction, including without limitation +// the rights to use, copy, modify, merge, publish, distribute, sublicense, +// and/or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// File Name: clipping.h +// Author: Stefano Ceccherini (burton666@libero.it) +// Description: Helper methods to manipulate clipping_rects +//------------------------------------------------------------------------------ +#ifndef __CLIPPING_H +#define __CLIPPING_H + +#include +#include + + +/* Some methods to manipulate clipping_rects. + basically you can do almost everything you do with + BRects, just that clipping_rects can only have integer + coordinates (a thing that makes these perfect for drawing + calculations). +*/ + + +// Returns the union of the given rects. +static inline clipping_rect +union_rect(const clipping_rect &r1, const clipping_rect &r2) +{ + clipping_rect rect; + + rect.left = min_c(r1.left, r2.left); + rect.top = min_c(r1.top, r2.top); + rect.right = max_c(r1.right, r2.right); + rect.bottom = max_c(r1.bottom, r2.bottom); + + return rect; +} + + +// Returns the intersection of the given rects. +// The caller should check if the returned rect is valid. If it isn't valid, +// then the two rectangles don't intersect. +static inline clipping_rect +sect_rect(const clipping_rect &r1, const clipping_rect &r2) +{ + clipping_rect rect; + + rect.left = max_c(r1.left, r2.left); + rect.top = max_c(r1.top, r2.top); + rect.right = min_c(r1.right, r2.right); + rect.bottom = min_c(r1.bottom, r2.bottom); + + return rect; +} + + +// Adds the given offsets to the given rect. +static inline void +offset_rect(clipping_rect &rect, int32 x, int32 y) +{ + rect.left += x; + rect.top += y; + rect.right += x; + rect.bottom += y; +} + + +// Converts the given clipping_rect to a BRect +static inline BRect +to_BRect(const clipping_rect &rect) +{ + return BRect((float)rect.left, (float)rect.top, (float)rect.right, (float)rect.bottom); +} + + +// Converts the given BRect to a clipping_rect. +static inline clipping_rect +to_clipping_rect(const BRect &rect) +{ + clipping_rect clipRect; + + clipRect.left = (int32)floor(rect.left); + clipRect.top = (int32)floor(rect.top); + clipRect.right = (int32)ceil(rect.right); + clipRect.bottom = (int32)ceil(rect.bottom); + + return clipRect; +} + + +// Checks if the given point lies in the given rect's area +static inline bool +point_in(const clipping_rect &rect, int32 px, int32 py) +{ + if (px >= rect.left && px <= rect.right + && py >= rect.top && py <= rect.bottom) + return true; + return false; +} + + +// Same as above, but it accepts a BPoint parameter +static inline bool +point_in(const clipping_rect &rect, const BPoint &pt) +{ + if (pt.x >= rect.left && pt.x <= rect.right + && pt.y >= rect.top && pt.y <= rect.bottom) + return true; + return false; +} + + +// Checks if the rect is valid +static inline bool +valid_rect(const clipping_rect &rect) +{ + if (rect.left <= rect.right && rect.top <= rect.bottom) + return true; + return false; +} + + +// Checks if the two rects intersect. +static inline bool +rects_intersect(const clipping_rect &rectA, const clipping_rect &rectB) +{ + // We behave like BRect::Intersects() does: + // we return false if one of the two rects is not valid + if (!valid_rect(rectA) || !valid_rect(rectB)) + return false; + + // TODO: Is there a better algorithm ? + // the one we used is faster than + // ' return valid_rect(sect_rect(rectA, rectB)); ', though. + + return !(rectA.left > rectB.right || rectA.top > rectB.bottom + || rectA.right < rectB.left || rectA.bottom < rectB.top); +} + + +// Returns the width of the given rect. +static inline int32 +rect_width(const clipping_rect &rect) +{ + return rect.right - rect.left; +} + + +// Returns the height of the given rect. +static inline int32 +rect_height(const clipping_rect &rect) +{ + return rect.bottom - rect.top; +} + +#endif // __CLIPPING_H diff --git a/src/tests/kits/interface/NewRegion/main.cpp b/src/tests/kits/interface/NewRegion/main.cpp new file mode 100644 index 0000000000..e3df876dc8 --- /dev/null +++ b/src/tests/kits/interface/NewRegion/main.cpp @@ -0,0 +1,18 @@ +#include "clipping.h" +#include "Region.h" + +#include + +int main() +{ + BRegion region(BRect(10, 10, 20, 20)); + + BRegion other(BRect(15, 15, 50, 19)); + region.IntersectWith(&other); + if (region.Intersects(other.Frame())) + printf("Okay!\n"); + + + region.PrintToStream(); +} +