/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2000-2012 SuperWaba Ltda. *
* All Rights Reserved *
* *
* This library and virtual machine is distributed in the hope that it will *
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 *
* A copy of this license is located in file license.txt at the root of this *
* SDK or can be downloaded here: *
* http://www.gnu.org/licenses/lgpl-3.0.txt *
* *
*********************************************************************************/
package totalcross.ui;
/* A container that checks if the sibling is within the visible area before calling paint on it.
*
* Used internally.
*/
public class ClippedContainer extends Container
{
public boolean verticalOnly;
protected int bagClipX0,bagClipXf,bagClipY0,bagClipYf;
private int lastMid;
private int findOneVisible(int y0, int yf, int ini, int end)
{
int i,mid;
for (i = 0;end-i > 1 ;)
{
mid = i + (end-i)/2;
Control c = (Control)tabOrder.items[mid];
if (c.y > yf)
end = mid;
else
if (y0 > c.y+c.height)
i = mid;
else
return mid;
}
return 0;
}
protected void computeClipRect()
{
bagClipY0 = -this.y;
bagClipYf = bagClipY0 + parent.height;
bagClipX0 = -this.x;
bagClipXf = bagClipX0 + parent.width;
}
public void paintChildren()
{
computeClipRect();
Window pw = getParentWindow();
if (pw == Window.topMost) pw = null; // no need to check if we're already at the top
if (verticalOnly)
{
Object[] items = tabOrder.items;
int n = tabOrder.size(),i,first,painted=0;
// check if the mid container of the last search is still visible, and restart the search using it
if (lastMid != -1 && lastMid < n && ((Control)items[lastMid]).isVisibleAndInside(bagClipY0,bagClipYf))
first = lastMid;
else // not visible, binary search again
first = findOneVisible(bagClipY0, bagClipYf, 0, n);
// found the first (or second) visible, go back to find the really first visible
while (first > 0 && ((Control)items[first-1]).isVisibleAndInside(bagClipY0,bagClipYf)) // find the first visible
first--;
// now go forward until no other is visible
for (i = first; i < n; i++)
{
Control child = (Control)items[i];
if (painted++ > 0 && !child.isVisibleAndInside(bagClipY0,bagClipYf))
break;
if (pw == null || !child.isObscured(pw))
{
child.onPaint(child.getGraphics());
if (child.asContainer != null)
child.asContainer.paintChildren();
}
}
lastMid = (first+i)/2;
}
else
{
for (Control child = children; child != null; child = child.next)
if (child.isVisibleAndInside(bagClipX0,bagClipY0,bagClipXf,bagClipYf) && (pw == null || !child.isObscured(pw)))
{
if (child.asContainer != null && child.asContainer.offscreen != null)
getGraphics().drawImage(child.asContainer.offscreen,child.x,child.y);
else
{
child.onPaint(child.getGraphics());
if (child.asContainer != null)
child.asContainer.paintChildren();
}
}
}
}
}