Better complex region cleanup - should be compete now... git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12772 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
816 lines
21 KiB
C++
816 lines
21 KiB
C++
//
|
|
// "$Id$"
|
|
//
|
|
// Clipping region routines for the Fast Light Tool Kit (FLTK).
|
|
//
|
|
// Copyright 2018 by Bill Spitzak and others.
|
|
//
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
// file is missing or damaged, see the license at:
|
|
//
|
|
// http://www.fltk.org/COPYING.php
|
|
//
|
|
// Please report all bugs and problems on the following page:
|
|
//
|
|
// http://www.fltk.org/str.php
|
|
//
|
|
|
|
|
|
#include "../../config_lib.h"
|
|
#include "Fl_Android_Graphics_Driver.H"
|
|
#include "Fl_Android_Application.H"
|
|
#include <FL/platform.H>
|
|
|
|
|
|
/**
|
|
* Create an empty clipping region.
|
|
*/
|
|
Fl_Rect_Region::Fl_Rect_Region() :
|
|
pLeft(0), pTop(0), pRight(0), pBottom(0)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Create a clipping region based on position and size.
|
|
* @param x, y position
|
|
* @param w, h size
|
|
*/
|
|
Fl_Rect_Region::Fl_Rect_Region(int x, int y, int w, int h) :
|
|
pLeft(x), pTop(y), pRight(x+w), pBottom(y+h)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Clone a clipping rectangle.
|
|
*/
|
|
Fl_Rect_Region::Fl_Rect_Region(const Fl_Rect_Region &r) :
|
|
pLeft(r.pLeft), pTop(r.pTop),
|
|
pRight(r.pRight), pBottom(r.pBottom)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Clone a clipping rectangle.
|
|
* The pointer can be NULL if an empty rectangle is needed.
|
|
*/
|
|
Fl_Rect_Region::Fl_Rect_Region(enum Type what)
|
|
{
|
|
if (what==INFINITE) {
|
|
pLeft = pTop = INT_MIN;
|
|
pRight = pBottom = INT_MAX;
|
|
} else {
|
|
pLeft = pTop = pRight = pBottom = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* If the rectangle has no width or height, it's considered empty.
|
|
* @return true, if everything will be clipped and there is nothing to draw
|
|
*/
|
|
bool Fl_Rect_Region::is_empty() const
|
|
{
|
|
return (pRight<=pLeft || pBottom<=pTop);
|
|
}
|
|
|
|
/**
|
|
* Return true, if the rectangle is of unlimited size and nothing should be clipped.
|
|
* @return treu, if there is no clipping
|
|
*/
|
|
bool Fl_Rect_Region::is_infinite() const
|
|
{
|
|
return (pLeft==INT_MIN);
|
|
}
|
|
|
|
/**
|
|
* Set an empty clipping rect.
|
|
*/
|
|
void Fl_Rect_Region::set_empty()
|
|
{
|
|
pLeft = pTop = pRight = pBottom = 0;
|
|
}
|
|
|
|
/**
|
|
* Set a clipping rect using position and size
|
|
* @param x, y position
|
|
* @param w, h size
|
|
*/
|
|
void Fl_Rect_Region::set(int x, int y, int w, int h)
|
|
{
|
|
pLeft = x;
|
|
pTop = y;
|
|
pRight = x+w;
|
|
pBottom = y+h;
|
|
}
|
|
|
|
/**
|
|
* Set a rectangle using the coordinates of two points, top left and bottom right.
|
|
* @param l, t left and top coordinate
|
|
* @param r, b right and bottom coordinate
|
|
*/
|
|
void Fl_Rect_Region::set_ltrb(int l, int t, int r, int b)
|
|
{
|
|
pLeft = l;
|
|
pTop = t;
|
|
pRight = r;
|
|
pBottom = b;
|
|
}
|
|
|
|
/**
|
|
* Copy the corrdinates from another rect.
|
|
* @param r source rectangle
|
|
*/
|
|
void Fl_Rect_Region::set(const Fl_Rect_Region &r)
|
|
{
|
|
pLeft = r.pLeft;
|
|
pTop = r.pTop;
|
|
pRight = r.pRight;
|
|
pBottom = r.pBottom;
|
|
}
|
|
|
|
/**
|
|
* Set this rect to be the intersecting area between the original rect and another rect.
|
|
* @param r another rectangular region
|
|
* @return EMPTY, if rectangles are not intersecting, SAME if this and rect are
|
|
* equal, LESS if the new rect is smaller than the original rect
|
|
*/
|
|
int Fl_Rect_Region::intersect_with(const Fl_Rect_Region &r)
|
|
{
|
|
if (is_empty()) {
|
|
return EMPTY;
|
|
}
|
|
if (r.is_empty()) {
|
|
set_empty();
|
|
return EMPTY;
|
|
}
|
|
bool same = true;
|
|
if ( pLeft != r.pLeft ) {
|
|
same = false;
|
|
if ( r.pLeft > pLeft ) pLeft = r.pLeft;
|
|
}
|
|
if ( pTop != r.pTop ) {
|
|
same = false;
|
|
if ( r.pTop > pTop ) pTop = r.pTop;
|
|
}
|
|
if ( pRight != r.pRight ) {
|
|
same = false;
|
|
if ( r.pRight < pRight ) pRight = r.pRight;
|
|
}
|
|
if ( pBottom != r.pBottom ) {
|
|
same = false;
|
|
if ( r.pBottom < pBottom ) pBottom = r.pBottom;
|
|
}
|
|
if (same)
|
|
return SAME;
|
|
if (is_empty())
|
|
return EMPTY;
|
|
return LESS;
|
|
}
|
|
|
|
/**
|
|
* Use rectangle as a bounding box and add the outline of another rect.
|
|
*/
|
|
void Fl_Rect_Region::add_to_bbox(const Fl_Rect_Region &r)
|
|
{
|
|
if (is_empty()) return;
|
|
if (r.pLeft<pLeft) pLeft = r.pLeft;
|
|
if (r.pTop<pTop) pTop = r.pTop;
|
|
if (r.pRight>pRight) pRight = r.pRight;
|
|
if (r.pBottom>pBottom) pBottom = r.pBottom;
|
|
}
|
|
|
|
/**
|
|
* Print the coordinates of the rect to the log.
|
|
* @param label some text that is logged with this message.
|
|
*/
|
|
void Fl_Rect_Region::print(const char *label) const
|
|
{
|
|
Fl_Android_Application::log_i("---> Fl_Rect_Region: %s", label);
|
|
Fl_Android_Application::log_i("Rect l:%d t:%d r:%d b:%d", left(), top(), right(), bottom());
|
|
}
|
|
|
|
// =============================================================================
|
|
|
|
/**
|
|
* Create an empty complex region.
|
|
*/
|
|
Fl_Complex_Region::Fl_Complex_Region() :
|
|
Fl_Rect_Region()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Create a complex region with the same bounds as the give rect.
|
|
* @param r region size
|
|
*/
|
|
Fl_Complex_Region::Fl_Complex_Region(const Fl_Rect_Region &r) :
|
|
Fl_Rect_Region(r)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Delete this region, all subregions recursively, and all following regions.
|
|
*/
|
|
Fl_Complex_Region::~Fl_Complex_Region()
|
|
{
|
|
delete_all_subregions();
|
|
}
|
|
|
|
/**
|
|
* Delete all subregions of this region.
|
|
* The pSubregion pointer should always be seen as a list of subregions, rather
|
|
* than a single region and some pNext pointer. So everything we do, we should
|
|
* probably do for every object in that list.
|
|
*
|
|
* Also note, that the top level region never has pNext pointing to anything.
|
|
*/
|
|
void Fl_Complex_Region::delete_all_subregions()
|
|
{
|
|
// Do NOT delete the chain in pNext! The caller has to that job.
|
|
// A top-level coplex region has pNext always set to NULL, and it does
|
|
// delete all subregions chained via the subregion pNext.
|
|
while (pSubregion) {
|
|
Fl_Complex_Region *rgn = pSubregion;
|
|
pSubregion = rgn->pNext;
|
|
delete rgn; rgn = 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Print the entire content of this region recursively.
|
|
*/
|
|
void Fl_Complex_Region::print(const char *label) const
|
|
{
|
|
Fl_Android_Application::log_i("---> Fl_Complex_Region: %s", label);
|
|
print_data(0);
|
|
}
|
|
|
|
/*
|
|
* Print the rectangular data only.
|
|
*/
|
|
void Fl_Complex_Region::print_data(int indent) const
|
|
{
|
|
static const char *space = " ";
|
|
if (pSubregion) {
|
|
Fl_Android_Application::log_i("%sBBox l:%d t:%d r:%d b:%d", space+16-indent, left(), top(), right(), bottom());
|
|
pSubregion->print_data(indent+1);
|
|
} else {
|
|
Fl_Android_Application::log_i("%sRect l:%d t:%d r:%d b:%d", space+16-indent, left(), top(), right(), bottom());
|
|
}
|
|
if (pNext) {
|
|
pNext->print_data(indent);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Replace this region with a rectangle.
|
|
* @param r the source rectangle
|
|
*/
|
|
void Fl_Complex_Region::set(const Fl_Rect_Region &r)
|
|
{
|
|
Fl_Rect_Region::set(r);
|
|
delete_all_subregions();
|
|
}
|
|
|
|
/**
|
|
* Replace this region with a copy of another region.
|
|
* This operation can be expensive for very complex regions.
|
|
* @param r the source region
|
|
*/
|
|
void Fl_Complex_Region::set(const Fl_Complex_Region &r)
|
|
{
|
|
Fl_Rect_Region::set((const Fl_Rect_Region&)r);
|
|
delete_all_subregions();
|
|
|
|
Fl_Complex_Region *srcRgn = r.pSubregion;
|
|
if (srcRgn) {
|
|
// copy first subregion
|
|
Fl_Complex_Region *dstRgn = pSubregion = new Fl_Complex_Region();
|
|
pSubregion->set(*srcRgn);
|
|
// copy rest of list
|
|
while (srcRgn) {
|
|
dstRgn->pNext = new Fl_Complex_Region();
|
|
dstRgn = dstRgn->next();
|
|
dstRgn->set(*srcRgn);
|
|
srcRgn = srcRgn->next();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set this region to the intersection of the original region and some rect.
|
|
* @param r intersect with this rectangle
|
|
* @return EMPTY, SAME, LESS
|
|
*/
|
|
int Fl_Complex_Region::intersect_with(const Fl_Rect_Region &r)
|
|
{
|
|
if (pSubregion) {
|
|
Fl_Complex_Region *rgn = pSubregion;
|
|
while (rgn) {
|
|
rgn->intersect_with(r);
|
|
rgn = rgn->next();
|
|
}
|
|
compress();
|
|
} else {
|
|
Fl_Rect_Region::intersect_with(r);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Subtract a rectangular region from this region.
|
|
* @param r the rect that we want removed
|
|
* @return currently 0, but could return something meaningful
|
|
*/
|
|
int Fl_Complex_Region::subtract(const Fl_Rect_Region &r)
|
|
{
|
|
if (pSubregion) {
|
|
Fl_Complex_Region *rgn = pSubregion;
|
|
while (rgn) {
|
|
rgn->subtract(r);
|
|
rgn = rgn->next();
|
|
}
|
|
compress();
|
|
} else {
|
|
// Check if we overlap at all
|
|
Fl_Rect_Region s(r);
|
|
int intersects = s.intersect_with(*this);
|
|
switch (intersects) {
|
|
case EMPTY:
|
|
// nothing to do
|
|
break;
|
|
case SAME:
|
|
set_empty(); // Will be deleted by compress()
|
|
break;
|
|
case LESS:
|
|
// split this rect into 1, 2, 3, or 4 new ones
|
|
subtract_smaller_region(s);
|
|
break;
|
|
default:
|
|
Fl_Android_Application::log_e("Invalid case in %s:%d", __FUNCTION__, __LINE__);
|
|
break;
|
|
}
|
|
if (pSubregion) compress(); // because intersecting this may have created subregions
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Compress the subregion of this region if possible and update the bounding
|
|
* box of this region.
|
|
*
|
|
* Does not recurse down the tree!
|
|
*/
|
|
void Fl_Complex_Region::compress()
|
|
{
|
|
// Can't compress anything that does not have a subregion
|
|
if (!pSubregion) return;
|
|
|
|
// remove all empty regions, because the really don't add anything (literally)
|
|
print("Compress");
|
|
Fl_Complex_Region *rgn = pSubregion;
|
|
while (rgn && rgn->is_empty()) {
|
|
pSubregion = rgn->next();
|
|
delete rgn; rgn = pSubregion;
|
|
}
|
|
if (!pSubregion) return;
|
|
|
|
rgn = pSubregion;
|
|
while (rgn) {
|
|
while (rgn->pNext && rgn->pNext->is_empty()) {
|
|
Fl_Complex_Region *nextNext = rgn->pNext->pNext;
|
|
delete rgn->pNext; rgn->pNext = nextNext;
|
|
}
|
|
rgn = rgn->next();
|
|
}
|
|
|
|
// find rectangles that can be merged into a single new rectangle
|
|
// (Too much work for much too little benefit)
|
|
|
|
// if there is only a single subregion left, merge it into this region
|
|
if (pSubregion->pNext==nullptr) {
|
|
set((Fl_Rect_Region&)*pSubregion); // deletes subregion for us
|
|
}
|
|
if (!pSubregion) return;
|
|
|
|
// finally, update the boudning box
|
|
Fl_Rect_Region::set((Fl_Rect_Region&)*pSubregion);
|
|
for (rgn=pSubregion->pNext; rgn; rgn=rgn->pNext) {
|
|
add_to_bbox(*rgn);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Subtract a smaller rect from a larger rect, potentially creating four new rectangles.
|
|
* This assumes that the calling region is NOT complex.
|
|
* @param r subtract the area of this rectangle; r must fit within ``this``.
|
|
* @return currently 0, but this may change
|
|
*/
|
|
int Fl_Complex_Region::subtract_smaller_region(const Fl_Rect_Region &r)
|
|
{
|
|
// subtract a smaller rect from a larger rect and create subrects as needed
|
|
// if there is only one single coordinate different, we can reuse this container
|
|
if (left()==r.left() && top()==r.top() && right()==r.right() && bottom()==r.bottom()) {
|
|
// this should not happen
|
|
set_empty();
|
|
} else if (left()!=r.left() && top()==r.top() && right()==r.right() && bottom()==r.bottom()) {
|
|
pRight = r.left();
|
|
} else if (left()==r.left() && top()!=r.top() && right()==r.right() && bottom()==r.bottom()) {
|
|
pBottom = r.top();
|
|
} else if (left()==r.left() && top()==r.top() && right()!=r.right() && bottom()==r.bottom()) {
|
|
pLeft = r.right();
|
|
} else if (left()==r.left() && top()==r.top() && right()==r.right() && bottom()!=r.bottom()) {
|
|
pTop = r.bottom();
|
|
} else {
|
|
// create multiple regions
|
|
if (pTop!=r.top()) {
|
|
Fl_Complex_Region *s = add_subregion();
|
|
s->set_ltrb(pLeft, pTop, pRight, r.top());
|
|
}
|
|
if (pBottom!=r.bottom()) {
|
|
Fl_Complex_Region *s = add_subregion();
|
|
s->set_ltrb(pLeft, r.bottom(), pRight, pBottom);
|
|
}
|
|
if (pLeft!=r.left()) {
|
|
Fl_Complex_Region *s = add_subregion();
|
|
s->set_ltrb(pLeft, r.top(), r.left(), r.bottom());
|
|
}
|
|
if (pRight!=r.right()) {
|
|
Fl_Complex_Region *s = add_subregion();
|
|
s->set_ltrb(r.right(), r.top(), pRight, r.bottom());
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Add an empty subregion to the current region.
|
|
* @return a pointer to the newly created region.
|
|
*/
|
|
Fl_Complex_Region *Fl_Complex_Region::add_subregion()
|
|
{
|
|
Fl_Complex_Region *r = new Fl_Complex_Region();
|
|
r->pParent = this;
|
|
r->pNext = pSubregion;
|
|
pSubregion = r;
|
|
return r;
|
|
}
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Returns an interator object for loops that traverse the entire region tree.
|
|
* C++11 interface to range-based loops.
|
|
* @return Iterator pointing to the first element.
|
|
*/
|
|
Fl_Complex_Region::Iterator Fl_Complex_Region::begin()
|
|
{
|
|
return Iterator(this);
|
|
}
|
|
|
|
/**
|
|
* Returns an interator object to mark the end of travesing the tree.
|
|
* C++11 interface to range-based loops.
|
|
* @return
|
|
*/
|
|
Fl_Complex_Region::Iterator Fl_Complex_Region::end()
|
|
{
|
|
return Iterator(nullptr);
|
|
}
|
|
|
|
/**
|
|
* Create an iterator to walk the entire tree.
|
|
* @param r Iterate through this region, r must not have a parent().
|
|
*/
|
|
Fl_Complex_Region::Iterator::Iterator(Fl_Complex_Region *r) :
|
|
pRegion(r)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Compare two iterators.
|
|
* C++11 needs this to find the end of a for loop.
|
|
* @param other
|
|
* @return
|
|
*/
|
|
bool Fl_Complex_Region::Iterator::operator!=(const Iterator &other) const
|
|
{
|
|
return pRegion != other.pRegion;
|
|
}
|
|
|
|
/**
|
|
* Set the iterator to the next object in the tree, down first.
|
|
* C++11 needs this to iterate in a for loop.
|
|
* @return
|
|
*/
|
|
const Fl_Complex_Region::Iterator &Fl_Complex_Region::Iterator::operator++()
|
|
{
|
|
if (pRegion->subregion()) {
|
|
pRegion = pRegion->subregion();
|
|
} else if (pRegion->next()) {
|
|
pRegion = pRegion->next();
|
|
} else {
|
|
pRegion = pRegion->parent();
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Return the current object while iterating through the tree.
|
|
* @return
|
|
*/
|
|
Fl_Complex_Region *Fl_Complex_Region::Iterator::operator*() const
|
|
{
|
|
return pRegion;
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Use this to iterate through a region, hitting only nodes that intersect with this rect.
|
|
* @param r find all parts of the region that intersect with this rect.
|
|
* @return an object that can be used in range-based for loops in C++11.
|
|
*/
|
|
Fl_Complex_Region::Overlapping Fl_Complex_Region::overlapping(const Fl_Rect_Region &r)
|
|
{
|
|
return Overlapping(this, r);
|
|
}
|
|
|
|
/**
|
|
* A helper object for iterating through a region, finding only overlapping rects.
|
|
* @param rgn
|
|
* @param rect
|
|
*/
|
|
Fl_Complex_Region::Overlapping::Overlapping(Fl_Complex_Region *rgn,
|
|
const Fl_Rect_Region &rect) :
|
|
pRegion(rgn),
|
|
pOriginalRect(rect),
|
|
pClippedRect(rect)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Return an itertor for the first clipping rectangle inside the region.
|
|
* @return
|
|
*/
|
|
Fl_Complex_Region::Overlapping::OverlappingIterator Fl_Complex_Region::Overlapping::begin()
|
|
{
|
|
find_intersecting();
|
|
return OverlappingIterator(this);
|
|
}
|
|
|
|
/**
|
|
* Return an iterator for the end of forward iteration.
|
|
* @return
|
|
*/
|
|
Fl_Complex_Region::Overlapping::OverlappingIterator Fl_Complex_Region::Overlapping::end()
|
|
{
|
|
return OverlappingIterator(nullptr);
|
|
}
|
|
|
|
/**
|
|
* Return the result of intersecting the original rect with this iterator.
|
|
* @return
|
|
*/
|
|
Fl_Rect_Region &Fl_Complex_Region::Overlapping::clipped_rect()
|
|
{
|
|
return pClippedRect;
|
|
}
|
|
|
|
/**
|
|
* Store the intersection in pClippedRect and return true if there was an intersection.
|
|
* @return
|
|
*/
|
|
bool Fl_Complex_Region::Overlapping::intersects()
|
|
{
|
|
return (pClippedRect.intersect_with(*pRegion) != EMPTY);
|
|
}
|
|
|
|
/**
|
|
* Find the next element in the tree that actually intersects with the initial rect.
|
|
* Starting the search at the current object, NOT the next object.
|
|
* @return
|
|
*/
|
|
bool Fl_Complex_Region::Overlapping::find_intersecting()
|
|
{
|
|
for (;;) {
|
|
if (!pRegion) return false;
|
|
pClippedRect.set(pOriginalRect);
|
|
if (intersects()) {
|
|
if (!pRegion->subregion()) {
|
|
return true;
|
|
} else {
|
|
pRegion = pRegion->subregion();
|
|
}
|
|
} else {
|
|
find_next();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Find the next object in the tree, complex, simple, intersecting or not.
|
|
* @return
|
|
*/
|
|
bool Fl_Complex_Region::Overlapping::find_next()
|
|
{
|
|
if (pRegion->subregion()) {
|
|
pRegion = pRegion->subregion();
|
|
} else if (pRegion->next()) {
|
|
pRegion = pRegion->next();
|
|
} else {
|
|
pRegion = pRegion->parent(); // can be NULL
|
|
}
|
|
return (pRegion != nullptr);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
/**
|
|
* Create the actual iterator for finding true clipping rects.
|
|
* @see Fl_Complex_Region::Overlapping
|
|
* @param ov
|
|
*/
|
|
Fl_Complex_Region::Overlapping::OverlappingIterator::OverlappingIterator(
|
|
Overlapping *ov) :
|
|
pOv(ov)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Compare two iterator.
|
|
* This is used by C++11 range0based for loops to find the end of the range.
|
|
* @param other
|
|
* @return
|
|
*/
|
|
bool Fl_Complex_Region::Overlapping::OverlappingIterator::operator!=(
|
|
const OverlappingIterator &other) const
|
|
{
|
|
auto thisRegion = pOv ? pOv->pRegion : nullptr;
|
|
auto otherRegion = other.pOv ? other.pOv->pRegion : nullptr;
|
|
return thisRegion != otherRegion;
|
|
}
|
|
|
|
/**
|
|
* Wrapper to find and set the next intersecting rectangle.
|
|
* @see Fl_Complex_Region::Overlapping::find_intersecting
|
|
* @see Fl_Complex_Region::Overlapping::find_next
|
|
* @return
|
|
*/
|
|
const Fl_Complex_Region::Overlapping::OverlappingIterator &
|
|
Fl_Complex_Region::Overlapping::OverlappingIterator::operator++()
|
|
{
|
|
pOv->find_next();
|
|
if (pOv->pRegion)
|
|
pOv->find_intersecting();
|
|
return *this;
|
|
}
|
|
|
|
/**
|
|
* Return the Fl_Complex_Region::Overlapping state for this iterator.
|
|
* This gives the user access to the current rectangular fragment of
|
|
* the clipping region.
|
|
* @return
|
|
*/
|
|
Fl_Complex_Region::Overlapping *
|
|
Fl_Complex_Region::Overlapping::OverlappingIterator::operator*() const
|
|
{
|
|
return pOv;
|
|
}
|
|
|
|
// =============================================================================
|
|
|
|
|
|
void Fl_Android_Graphics_Driver::restore_clip()
|
|
{
|
|
fl_clip_state_number++;
|
|
|
|
// find the current user clipping rectangle
|
|
Fl_Region b = rstack[rstackptr]; // Fl_Region is a pointer to Fl_Rect_Region
|
|
if (b) {
|
|
if (b->is_empty()) {
|
|
// if this is an empty region, the intersection is always empty as well
|
|
pClippingRegion.set_empty();
|
|
} else {
|
|
// if there is a region, copy the full window region
|
|
pClippingRegion.set(pDesktopWindowRegion);
|
|
if (!b->is_infinite()) {
|
|
// if the rect has dimensions, calculate the intersection
|
|
pClippingRegion.intersect_with(*b);
|
|
}
|
|
}
|
|
} else {
|
|
// no rect? Just copy the window region
|
|
pClippingRegion.set(pDesktopWindowRegion);
|
|
}
|
|
}
|
|
|
|
|
|
void Fl_Android_Graphics_Driver::clip_region(Fl_Region r)
|
|
{
|
|
Fl_Region oldr = rstack[rstackptr];
|
|
if (oldr)
|
|
::free(oldr);
|
|
rstack[rstackptr] = r;
|
|
restore_clip();
|
|
}
|
|
|
|
|
|
Fl_Region Fl_Android_Graphics_Driver::clip_region()
|
|
{
|
|
return rstack[rstackptr];
|
|
}
|
|
|
|
|
|
void Fl_Android_Graphics_Driver::push_clip(int x, int y, int w, int h)
|
|
{
|
|
Fl_Region r;
|
|
if (w > 0 && h > 0) {
|
|
r = new Fl_Rect_Region(x, y, w, h);
|
|
Fl_Region current = rstack[rstackptr];
|
|
if (current) {
|
|
r->intersect_with(*current);
|
|
}
|
|
} else { // make empty clip region:
|
|
r = new Fl_Rect_Region();
|
|
}
|
|
if (rstackptr < region_stack_max) rstack[++rstackptr] = r;
|
|
else Fl::warning("Fl_Android_Graphics_Driver::push_clip: clip stack overflow!\n");
|
|
restore_clip();
|
|
}
|
|
|
|
|
|
void Fl_Android_Graphics_Driver::push_no_clip()
|
|
{
|
|
if (rstackptr < region_stack_max) rstack[++rstackptr] = 0;
|
|
else Fl::warning("Fl_Android_Graphics_Driver::push_no_clip: clip stack overflow!\n");
|
|
restore_clip();
|
|
}
|
|
|
|
|
|
void Fl_Android_Graphics_Driver::pop_clip()
|
|
{
|
|
if (rstackptr > 0) {
|
|
Fl_Region oldr = rstack[rstackptr--];
|
|
if (oldr)
|
|
::free(oldr);
|
|
} else Fl::warning("Fl_Android_Graphics_Driver::pop_clip: clip stack underflow!\n");
|
|
restore_clip();
|
|
}
|
|
|
|
/*
|
|
Intersects the rectangle with the current clip region and returns the
|
|
bounding box of the result.
|
|
|
|
Returns non-zero if the resulting rectangle is different to the original.
|
|
This can be used to limit the necessary drawing to a rectangle.
|
|
\p W and \p H are set to zero if the rectangle is completely outside the region.
|
|
\param[in] x,y,w,h position and size of rectangle
|
|
\param[out] X,Y,W,H position and size of resulting bounding box.
|
|
\returns Non-zero if the resulting rectangle is different to the original.
|
|
*/
|
|
int Fl_Android_Graphics_Driver::clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H)
|
|
{
|
|
Fl_Region r = rstack[rstackptr];
|
|
if (r) {
|
|
Fl_Rect_Region a(x, y, w, h);
|
|
int ret = a.intersect_with(*r);
|
|
X = a.x();
|
|
Y = a.y();
|
|
W = a.w();
|
|
H = a.h();
|
|
return (ret!=Fl_Rect_Region::SAME);
|
|
} else {
|
|
X = x; Y = y; W = w; H = h;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Does the rectangle intersect the current clip region?
|
|
\param[in] x,y,w,h position and size of rectangle
|
|
\returns non-zero if any of the rectangle intersects the current clip
|
|
region. If this returns 0 you don't have to draw the object.
|
|
|
|
\note
|
|
Under X this returns 2 if the rectangle is partially clipped,
|
|
and 1 if it is entirely inside the clip region.
|
|
*/
|
|
int Fl_Android_Graphics_Driver::not_clipped(int x, int y, int w, int h)
|
|
{
|
|
if (w <= 0 || h <= 0) return 0;
|
|
Fl_Region r = rstack[rstackptr];
|
|
if (r) {
|
|
Fl_Rect_Region a(x, y, w, h); // return 0 for empty, 1 for same, 2 if intersecting
|
|
return a.intersect_with(*r);
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// End of "$Id$".
|
|
//
|