FileDocCategorySizeDatePackage
CLayer.javaAPI DocphoneME MR2 API (J2ME)31628Wed May 02 18:00:20 BST 2007com.sun.midp.chameleon

CLayer

public class CLayer extends Object
This class represents a "layer". A layer is an element used to comprise a higher-level "window" (see CWindow.java). A layer has several properties such as its visibility, whether it accepts input, its size, etc. A layer also has content, such as its background and its foreground.

Fields Summary
private boolean
dirty
Flag indicating this layer is in need of repainting.
protected int[]
dirtyBounds
Array holding a bounding rectangle of an area needing repainting.
protected int[]
boundsCopy
Copy of the layer bounds needed to unlock the layers for painting
protected int[]
dirtyBoundsCopy
Copy of the dirty bounds needed to unlock the layers for painting
protected boolean
transparent
Flag indicating if this layer has a transparent background or not.
protected boolean
visible
Flag indicating the current visibility state of this layer.
protected boolean
supportsInput
Flag indicating the ability of this layer to support key/pen input.
protected boolean
opaque
Flag indicating this layer is either completely opaque, or not. By default, a layer is not opaque, and thus requires the background and any layers below it to be painted in addition to itself. However, if a layer is opaque, it does not require anything it is obscuring to be painted, just itself. All layers are opaque by default.
protected int
bgColor
If this layer has a filled color background, the 0xrrggbbaa value of that color
protected Image[]
bgImage
The image to use as a background for this layer if this layer is not transparent and does not use a fill color.
protected boolean
tileBG
If this layer is not transparent and uses a background image, a flag indicating if that image should be tiled or otherwise centered.
protected CWindow
owner
The window which owns this layer. If this layer has not been added to a window or it has been removed from a window, the owner will be null.
public int[]
bounds
An array holding the bounds of this layer. The indices are as follows: 0 = layer's 'x' coordinate 1 = layer's 'y' coordinate 2 = layer's width 3 = layer's height The 'x' and 'y' coordinates are in the coordinate space of the window which contains this layer.
public static final int
X
Constant used to reference the '0' index of the bounds array
public static final int
Y
Constant used to reference the '1' index of the bounds array
public static final int
W
Constant used to reference the '2' index of the bounds array
public static final int
H
Constant used to reference the '3' index of the bounds array
int
graphicsColor
When in the paint() routine, graphicsColor will be set to the default graphics color. This is a convenience variable for subclasses to easily modify and then reset the graphics color.
Font
graphicsFont
When in the paint() routine, graphicsFont will be set to the default graphics Font. This is a convenience variable for subclasses to easily modify and then reset the graphics font.
Constructors Summary
public CLayer()
Construct a default, transparent layer. As a result, the 'transparent' value will be set to true.

    
                         
      
        this((Image)null, -1);
    
public CLayer(Image bgImage, int bgColor)
Construct a layer with the given background image if it is not null or with a background fill color. The color should be in the 0xaarrggbb format. If the bgColor is invalid and bgImage is null, this layer will be transparent and equal to the no-argument constructor.

param
bgImage The background image to use for this layer.
param
bgColor The color (0xaarrggbb) to use as the background fill

        if (bgImage != null) {
            this.bgImage = new Image[] { bgImage };
            this.tileBG = true;
            transparent = false;
        } else {
            transparent = (bgColor < 0);
        }
        this.bgColor = bgColor;
        initialize();
    
public CLayer(Image[] bgImages, int bgColor)
Construct a layer with the given background images (if not null) or with a background fill color and border. The background images should be a 9 element array, creating a 9-piece image background. The color should be in the 0xaarrggbb format. If the bgColor is invalid and bgImages are null, this layer will be transparent and equal to the no-argument constructor.

param
bgImages The background image to use for this layer.
param
bgColor The color (0xaarrggbb) to use as the background fill

        if (bgImages != null) {
            this.bgImage = new Image[bgImages.length];
            System.arraycopy(bgImages, 0, this.bgImage, 0, bgImages.length);
            this.tileBG = false;
            transparent = false;
        } else {
            transparent = (bgColor < 0);
        }
        this.bgColor = bgColor;
        initialize();
    
Methods Summary
public voidaddDirtyRegion()
Add this layer's entire area to be marked for repaint. Any pending dirty regions will be cleared and the entire layer will be painted on the next repaint.

        if (CGraphicsQ.DEBUG) {
            System.err.println("Layer " + layerID() + ":");
            System.err.println("\tMarking entire layer dirty");
        }
        cleanDirtyRegions();
        setDirty();
    
public booleanaddDirtyRegion(int x, int y, int w, int h)
Add an area to be marked for repaint to this layer. This could be needed for a variety of reasons, such as this layer being obscured by another layer or window element. The new region should be in the coordinate space of this layer.

param
x the x coordinate of the region
param
y the y coordinate of the region
param
w the width of the region
param
h the height of the region
return
true if dirty region of the layer was changed, false otherwise

        if (CGraphicsQ.DEBUG) {
            System.err.println("Layer " + this + ":");
            System.err.println("\tAdd dirty: " + x + ", "
                + y + ", " + w + ", " + h);
        }

        // The whole layer is dirty already
        if (isDirty() && isEmptyDirtyRegions()) {
            if (CGraphicsQ.DEBUG) {
                System.err.println(
                    "\tWhole layer is dirty already");
            }
            return false;
        }

        // Cache layer bounds
        int bw = bounds[W];
        int bh = bounds[H];
        int x2 = x + w;
        int y2 = y + h;

        // Dirty region can be outside of the layer
        if (x >= bw || y >= bh || x2 <= 0 || y2 <=0) {
            if (CGraphicsQ.DEBUG) {
                System.err.println(
                    "\tAdded region is outside of the layer");
            }
            return false;
        }

        boolean res = false;
        int dx, dy, dx2, dy2;
        if (isEmptyDirtyRegions()) {
            dx = x; dy = y;
            dx2 = x2; dy2 = y2;
        } else {
            dx = dirtyBounds[X];
            dy = dirtyBounds[Y];
            dx2 = dx + dirtyBounds[W];
            dy2 = dy + dirtyBounds[H];
            if (dx2 < x2) dx2 = x2;
            if (dy2 < y2) dy2 = y2;
            if (x < dx) dx = x;
            if (y < dy) dy = y;
        }

        // Lastly, we carefully restrict the dirty region
        // to be within the bounds of this layer
        if (dx < 0) dx = 0;
        if (dy < 0) dy = 0;
        if (dx2 > bw) dx2 = bw;
        if (dy2 > bh) dy2 = bh;

        // Update changed dirty region
        int dw = dx2 - dx;
        int dh = dy2 - dy;
        if (dirtyBounds[W] != dw || dirtyBounds[H] != dh) {
            if (dw == bw && dh == bh) {
                // The entire layer is dirty now
                cleanDirtyRegions();

                if (CGraphicsQ.DEBUG) {
                    System.err.println(
                        "\tThe entire layer became dirty");
                }
            } else {
                dirtyBounds[X] = dx;
                dirtyBounds[Y] = dy;
                dirtyBounds[W] = dw;
                dirtyBounds[H] = dh;

                if (CGraphicsQ.DEBUG) {
                    System.err.println(
                        "\tCurrent dirty: " + dirtyBounds[X] + ", "
                        + dirtyBounds[Y] + ", " + dirtyBounds[W] + ", "
                        + dirtyBounds[H]);
                }
            }
            res = true;
            setDirty();
        }

        return res;
    
public voidaddNotify()
Called by CWindow to notify the layer that is has been added to the active stack. By default this method do nothing. This method could be re-implemented by particular layer to do some specific action as soon as it's added to the stack

protected voidcleanDirty()
Clean any dirty regions of the layer and mark layer as not dirty.

        dirty = false;
        cleanDirtyRegions();
    
protected voidcleanDirtyRegions()
Clean any dirty regions of the layer.

        dirtyBounds[X] = dirtyBounds[Y]
            = dirtyBounds[W] = dirtyBounds[H] = -1;
    
public booleancontainsPoint(int x, int y)
Utility method to determine if the given point lies within the bounds of this layer. The point should be in the coordinate space of this layer's containing CWindow.

param
x the "x" coordinate of the point
param
y the "y" coordinate of the point
return
true if the coordinate lies in the bounds of this layer

        return (visible &&
                x >= bounds[X] && x <= (bounds[X] + bounds[W]) &&
                y >= bounds[Y] && y <= (bounds[Y] + bounds[H]));
    
voidcopyLayerBounds()
Copy bounds of the layer to use them on dirty layers painting when the layers are not locked for changes from other threads

        if (dirtyBounds[X] == -1) {
            // Whole layer is dirty
            dirtyBoundsCopy[X] = 0;
            dirtyBoundsCopy[Y] = 0;
            dirtyBoundsCopy[W] = bounds[W];
            dirtyBoundsCopy[H] = bounds[H];
        } else {
            System.arraycopy(
                dirtyBounds, 0, dirtyBoundsCopy, 0, 4);
        }
        System.arraycopy(
            bounds, 0, boundsCopy, 0, 4);
    
public int[]getBounds()
Return the bounds of this layer (in the coordinate space of its parent Window). Returns a 4 element array, containing the x, y, width, and height representing this layer's bounding rectangle

return
this layer's bounding rectangle in the coordinate space of its parent window

        return bounds;
    
public booleanhandlePoint(int x, int y)
Utility method to determine if this layer wanna handle the given point. By default the layer handles the point if it lies within the bounds of this layer. The point should be in the coordinate space of this layer's containing CWindow.

param
x the "x" coordinate of the point
param
y the "y" coordinate of the point
return
true if the coordinate lies in the bounds of this layer

        return containsPoint(x, y);
    
protected voidinitialize()
Finish initialization of this CLayer. This can be extended by subclasses. The dimensions of the CLayer are stored in its bounds[]. The 'x' and 'y' coordinates are in the coordinate space of the window which contains this layer. By default, a layer is located at the origin and is as large as the screen size. The X and Y coordinates represent the upper left position of this CLayer in the containing CWindow's coordinate space.

        bounds = new int[4];
        bounds[X] = 0;
        bounds[Y] = 0;
        bounds[W] = ScreenSkin.WIDTH;
        bounds[H] = ScreenSkin.HEIGHT;
        
        dirtyBounds = new int[4];
        dirtyBoundsCopy = new int[4];
        boundsCopy = new int[4];
        cleanDirtyRegions();
        
        // IMPL_NOTE : center the background image by default
    
public booleanisDirty()
Returns true if this layer is in need of repainting.

return
true if this layer is marked as 'dirty' and needs repainting.

        return this.dirty;
    
protected booleanisEmptyDirtyRegions()
Determines whether dirty regions are empty.

return
true if dirty regions are not set, false otherwise

        return dirtyBounds[X] == -1;
    
public booleanisOpaque()
Determine if this layer is opaque

return
true if this layer does not have any transparent or translucent areas

        return opaque;
    
public booleanisVisible()
Determine the current visibility of this layer. Note that this state only pertains to the layer's visibility status within its containing window. The window itself may or may not be actually visible on the physical display.

return
true if this layer is currently visible in a window

        return visible;
    
public booleankeyInput(int type, int code)
Handle key input from a keypad. Parameters describe the type of key event and the platform-specific code for the key. (Codes are translated using the lcdui.Canvas)

param
type the type of key event
param
code the numeric code assigned to the key
return

        return false;
    
protected java.lang.StringlayerID()
A String identifier used by subclasses (for debug purposes)

return
abbreviated class name of the layer instance

        int i;
        String res = getClass().getName();
        if (res != null && (i = res.lastIndexOf('.")) > -1) {
            res = res.substring(i+1);
        }
        return res + "@" +
            Integer.toHexString(hashCode());
    
public booleanmethodInput(java.lang.String str)
Handle input from some type of device-dependent input method. This could be input from something such as T9, or a phonebook lookup, etc.

param
str the text to handle as direct input
return

        return false;
    
public voidpaint(Graphics g)
Paint this layer. This method should not generally be overridden by subclasses. This method carefully stores the clip, translation, and color before calling into subclasses. The graphics region will be translated such that it is in this layer's coordinate space (0,0 is the top left corner of this layer). The paintBackground() method will be called first, then the paintBody() method. The graphics will then carefully be put back into its original state before returning. Subclasses should override the paintBody() method and do not generally need to do any translates or bother to undo any changes made to the Graphics object.

param
g The graphics object to use to paint this layer.

        try {            
            // We first reset our dirty flag
            this.dirty = false;
            
            graphicsColor = g.getColor();
            graphicsFont = g.getFont();
            
            // Paint the background
            if (!transparent) {
                paintBackground(g);
            }
            
            // Just in case subclasses modified these values,
            // return them to standard
            g.setColor(graphicsColor);
            g.setFont(graphicsFont);
            
            // Paint the body
            paintBody(g);
            
            // Just in case subclasses modified these values,
            // return them to standard
            g.setColor(graphicsColor);
            g.setFont(graphicsFont);
            
            // We reset our dirty bounds region
            cleanDirtyRegions();
            
        } catch (Throwable t) {
            t.printStackTrace();
        }
    
protected voidpaintBackground(Graphics g)
Paint the background of this layer. This method will automatically handle a transparent layer, a layer with a background color (and/or border color), and a layer with a background image (either centered or tiled). Subclasses may override this method if they require a more advanced background (note that the transparent value should be set to false in order for the paintBackground() method to be called), but subclasses must be careful to reset any modifications made to the Graphics object before returning.

param
g The Graphics object to use to paint the background.

        
        if (bgImage == null) {
            // background is null, just fill using the fill color
            g.setColor(bgColor);
            g.fillRect(g.getClipX(), g.getClipY(), 
                       g.getClipWidth(), g.getClipHeight());
        } else {
            if (bgImage.length == 1) {
                CGraphicsUtil.paintBackground(g, bgImage[0], tileBG, bgColor, 
                                              bounds[W], bounds[H]);
            } else if (bgImage.length == 9) {
                CGraphicsUtil.draw9pcsBackground(g, 0, 0, 
                                             bounds[W], bounds[H],
                                             bgImage);
            
            } else if (bgImage.length == 3) {
                CGraphicsUtil.draw3pcsBackground(g, 0, 0, bounds[W], bgImage);
            }
        }
    
protected voidpaintBody(Graphics g)
Paint the body or content of this layer. This method should be overridden by subclasses. Note that the Graphics object will already be translated into this layer's coordinate space. Subclasses do not need to reset any changes made to the Graphics object as the CLayer paint() routine will do that automatically.

param
g The Graphics object to use to paint the content of this layer

    
public booleanpointerInput(int type, int x, int y)
Handle input from a pen tap. Parameters describe the type of pen event and the x,y location in the layer at which the event occurred. Important: the x,y location of the pen tap will already be translated into the coordinate space of the layer.

param
type the type of pen event
param
x the x coordinate of the event
param
y the y coordinate of the event
return

        return false;
    
public voidrelocateNotify(int[] oldBounds)
Called by CWindow to notify the layer that is has been moved to another location. By default this method do nothing. This method could be re-implemented by particular layer to do some specific action as soon as it's moved

param
oldBounds original bounds of this layer before it has been moved

public voidremoveNotify(CWindow owner)
Called by CWindow to notify the layer that is has been removed from the active stack. By default this method do nothing. This method could be re-implemented by particular layer to do some specific action as soon as it's removed from the stack

param
owner an instance of CWindow this layer has been removed from

public voidrequestRepaint()
Request a repaint for the entire contents of this layer.

        requestRepaint(0, 0, bounds[W], bounds[H]);
    
public voidrequestRepaint(int x, int y, int w, int h)
Request a repaint for a specific region of this layer.

param
x The 'x' coordinate of the upper left corner of the repaint region
param
y The 'y' coordinate of the upper right corner of the repaint region
param
w The width of the repaint region
param
h The height of the repaint region

        addDirtyRegion(x, y, w, h);
        if (owner != null && visible) {
            // We request a repaint of our parent window after translating
            // the origin into the coordinate space of the window.
            owner.requestRepaint();
        }
    
public voidsetBackground(Image bgImage, boolean tileBG, int bgColor)
Establish a background. This method will evaluate the parameters and create a background which is appropriate. If the image is non-null, the image will be used to create the background. If the image is null, the values for the colors will be used and the background will be painted in fill color instead. If the image is null, and the background color is a negative value, this layer will become transparent and no background will be painted.

param
bgImage the image to use for the background tile (or null)
param
tileBG If true, then tile the background image as necessary to fill a larger screen. If false, treat the image as fullsize.
param
bgColor if the image is null, use this color as a background fill color

        if (bgImage != null) {
            this.bgImage = new Image[] { bgImage };
            this.tileBG = tileBG;
            transparent = false;
        } else {
            this.bgImage = null;
            transparent = (bgColor < 0);
        }
        this.bgColor = bgColor;
        addDirtyRegion();
    
public voidsetBackground(Image[] bgImages, int bgColor)
Establish a background. This method will evaluate the parameters and create a background which is appropriate. If the images are non-null, the images will be used to create a 9-piece background. If the images are null, the value for the color will be used and the background will be painted in fill color instead. If the images are null, and the background color is a negative value, this layer will become transparent and no background will be painted.

param
bgImages an array containing a 9-piece image set to be used as the background for this layer
param
bgColor if the images are null, use this color as a background fill color

        if (bgImages != null) {
            this.bgImage = new Image[bgImages.length];
            System.arraycopy(bgImages, 0, this.bgImage, 0, bgImages.length);
            this.tileBG = false;
            transparent = false;
        } else {
            this.bgImage = null;
            transparent = (bgColor < 0);
        }
        this.bgColor = bgColor;
        addDirtyRegion();            
    
public voidsetBounds(int x, int y, int w, int h)
Establish the bounds of this layer. The coordinate space for the 'x' and 'y' anchor will be interpreted in that of the window which contains this layer.

param
x The 'x' coordinate of this layer's origin
param
y The 'y' coordinate of this layer's origin
param
w The width of this layer
param
h The height of this layer

        if (bounds == null) {
            bounds = new int[4];
        }
        bounds[X] = x;
        bounds[Y] = y;
        bounds[W] = w;
        bounds[H] = h;
    
protected voidsetDirty()
Mark this layer as being dirty. By default, this will also mark the containing window (if there is one) as being dirty as well.

        setDirtyButNotNotifyOwner();
        if (owner != null) {
            owner.setDirty();
        }
    
protected voidsetDirtyButNotNotifyOwner()
Mark this layer as being dirty but don't mark the containing window.

        this.dirty = true;
    
public voidsetOpaque(boolean opaque)
Set the opacity flag for this layer. True means that this layer does not have any transparent or translucent areas

param
opaque a flag indicating the layer's opacity

        this.opaque = opaque;
    
public voidsetSupportsInput(boolean support)
Toggle the ability of this layer to receive input.

param
support If true, this layer will receive user input events (as long as the layer is also visible)

        this.supportsInput = support;
    
public voidsetVisible(boolean visible)
Toggle the visibility state of this layer within its containing window.

param
visible If true, this layer will be painted as part of its containing window, as well as receive events if it supports input.

        this.visible = visible;
        addDirtyRegion();
    
booleansubDirtyRegion(int x, int y, int w, int h)
Subtract a layer area not needed for repaint of this layer. It could be needed for a variety of reasons, such as layer being overlapped with opague higher layer or window element. The subtracted region should be in the coordinate space of this layer.

param
x the x coordinate of the region
param
y the y coordinate of the region
param
w the width of the region
param
h the height of the region
return
true if dirty region of the layer was changed, false otherwise

        if (!isDirty()) {
            return false;
        }

        if (CGraphicsQ.DEBUG) {
            System.err.println("Layer " + this + ":");
            System.err.println("\tSub dirty: " + x + ", "
                + y + ", " + w + ", " + h);
        }

        int x2 = x + w;
        int y2 = y + h;
        boolean res = false;
        int dx, dy, dx2, dy2;
        if (isEmptyDirtyRegions()) {
            dx = 0; dy = 0;
            dx2 = bounds[W];
            dy2 = bounds[H];
        } else {
            dx = dirtyBounds[X];
            dy = dirtyBounds[Y];
            dx2 = dx + dirtyBounds[W];
            dy2 = dy + dirtyBounds[H];
        }

        // Subtracted region can be outside of the dirty area
        if (x >= dx2 || y >= dy2 || x2 <= dx || y2 <=dy) {
            if (CGraphicsQ.DEBUG) {
                System.err.println(
                    "\tSubtracted region is outside of dirty area");
            }
            return false;
        }

        boolean insideVert = (y <= dy && y2 >= dy2);
        boolean insideHorz = (x <= dx && x2 >= dx2);

        if (insideVert) {
            if (dx >= x && dx < x2) dx = x2;
            else if (dx2 > x && dx2 <= x2) dx2 = x;
        } else if (insideHorz) {
            if (dy >= y && dy < y2) dy = y2;
            else if (dy2 > y && dy2 <= y2) dy2 = y;
        } else {
            // We can subtract only such a regions that result
            // of subtraction is a rectangular area
            if (CGraphicsQ.DEBUG) {
                System.err.println(
                    "\tSubtraction can't be done");
            }
            return false;

        }

        // Result of subtraction can be an empty dirty region
        if (dx >= dx2 || dy >= dy2) {
            cleanDirty();
            res = true;

            if (CGraphicsQ.DEBUG) {
                System.err.println(
                    "\tThe layer is no more dirty");
            }

        } else if (dirtyBounds[W] != dx2 - dx ||
                dirtyBounds[H] != dy2 - dy) {
            // Update changed dirty region
            dirtyBounds[X] = dx;
            dirtyBounds[Y] = dy;
            dirtyBounds[W] = dx2 - dx;
            dirtyBounds[H] = dy2 - dy;
            res = true;

            if (CGraphicsQ.DEBUG) {
                System.err.println(
                    "\tCurrent dirty: " + dirtyBounds[X] + ", "
                    + dirtyBounds[Y] + ", " + dirtyBounds[W] + ", "
                    + dirtyBounds[H]);
            }
        } else {
            if (CGraphicsQ.DEBUG) {
                System.err.println(
                    "\tDirty area has not been changed");
            }
        }

        return res;
    
public booleansupportsInput()
Determine if this layer supports input, such as key and pen events.

return
true if this layer supports handling input events

        return supportsInput;
    
public java.lang.StringtoString()
Get the layer details including its bound and dirty region information

return
String with layer details

        String res = layerID() + " [" +
            bounds[X] + ", " + bounds[Y] + ", " +
            bounds[W] + ", " + bounds[H] + "]";

        if (isDirty()) {
            res += ", dirty";
            if (!isEmptyDirtyRegions()) {
                res += " (" +
                    dirtyBounds[X] + ", " + dirtyBounds[Y] + ", " +
                    dirtyBounds[W] + ", " + dirtyBounds[H] + ")";
            }
        }
        res += ", opaque: " + (opaque ? 1 : 0);
        res += ", visible: " + (visible ? 1 : 0);
        res += ", transparent: " + (transparent ? 1 : 0);
        return res;
    
public voidupdate(com.sun.midp.chameleon.CLayer[] mainLayers)

        if (visible) {
            addDirtyRegion();
        }