You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by tv...@apache.org on 2009/03/16 17:36:28 UTC

svn commit: r754936 [25/38] - in /incubator/pivot/tags/v1.0.1: ./ charts-test/ charts-test/src/ charts-test/src/pivot/ charts-test/src/pivot/charts/ charts-test/src/pivot/charts/test/ charts/ charts/lib/ charts/src/ charts/src/pivot/ charts/src/pivot/c...

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Scale.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Scale.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Scale.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Scale.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.media.drawing;
+
+/**
+ * Transform representing a scale.
+ *
+ * @author gbrown
+ */
+public class Scale extends Transform {
+    private float x = 0;
+    private float y = 0;
+
+    public float getX() {
+        return x;
+    }
+
+    public void setX(float x) {
+        this.x = x;
+    }
+
+    public float getY() {
+        return y;
+    }
+
+    public void setY(float y) {
+        this.y = y;
+    }
+
+    public float[][] getMatrix() {
+        // TODO
+        return null;
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Shape.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Shape.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Shape.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Shape.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.media.drawing;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.util.Iterator;
+
+import pivot.collections.Sequence;
+import pivot.wtk.Bounds;
+import pivot.wtk.Point;
+
+/**
+ * Abstract base class for shapes.
+ *
+ * @author gbrown
+ */
+public abstract class Shape {
+    public static final class TransformSequence extends Transform
+        implements Sequence<Transform>, Iterable<Transform> {
+        public float[][] getMatrix() {
+            // TODO
+            return null;
+        }
+
+        public int add(Transform item) {
+            // TODO Auto-generated method stub
+            return 0;
+        }
+
+        public void insert(Transform item, int index) {
+            // TODO Auto-generated method stub
+
+        }
+
+        public Transform update(int index, Transform item) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        public int remove(Transform item) {
+            // TODO Auto-generated method stub
+            return 0;
+        }
+
+        public Sequence<Transform> remove(int index, int count) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        public Transform get(int index) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+        public int indexOf(Transform item) {
+            // TODO Auto-generated method stub
+            return 0;
+        }
+
+        public int getLength() {
+            // TODO Auto-generated method stub
+            return 0;
+        }
+
+        public Iterator<Transform> iterator() {
+            // TODO
+            return null;
+        }
+    }
+
+    private Group parent = null;
+
+    private int x = 0;
+    private int y = 0;
+
+    private Paint fill = null;
+    private Paint stroke = Color.BLACK;
+    private int strokeThickness = 1;
+
+    private TransformSequence transform = new TransformSequence();
+
+    public Group getParent() {
+        return parent;
+    }
+
+    protected void setParent(Group parent) {
+        this.parent = parent;
+    }
+
+    public int getX() {
+        return x;
+    }
+
+    public void setX(int x) {
+        this.x = x;
+    }
+
+    public int getY() {
+        return y;
+    }
+
+    public void setY(int y) {
+        this.y = y;
+    }
+
+    public Point getOrigin() {
+        return new Point(x, y);
+    }
+
+    public void setOrigin(int x, int y) {
+        setX(x);
+        setY(y);
+    }
+
+    public void setOrigin(Point origin) {
+        if (origin == null) {
+            throw new IllegalArgumentException("origin is null.");
+        }
+
+        setOrigin(origin.x, origin.y);
+    }
+
+    public Paint getFill() {
+        return fill;
+    }
+
+    public void setFill(Paint fill) {
+        this.fill = fill;
+    }
+
+    public void setFill(String fill) {
+        if (fill == null) {
+            throw new IllegalArgumentException("fill is null.");
+        }
+
+        // TODO Support an encoding for gradient paints
+
+        setFill(Color.decode(fill));
+    }
+
+    public Paint getStroke() {
+        return stroke;
+    }
+
+    public void setStroke(Paint stroke) {
+        this.stroke = stroke;
+    }
+
+    public void setStroke(String stroke) {
+        if (stroke == null) {
+            throw new IllegalArgumentException("stroke is null.");
+        }
+
+        // TODO Support an encoding for gradient paints
+
+        setStroke(Color.decode(stroke));
+    }
+
+    public Bounds getBounds() {
+        // TODO Transform untransformed bounds
+        return null;
+    }
+
+    public abstract Bounds getUntransformedBounds();
+
+    public TransformSequence getTransform() {
+        return transform;
+    }
+
+    public void paint(Graphics2D graphics) {
+        if (fill != null) {
+            graphics.setPaint(fill);
+            fill(graphics);
+        }
+
+        if (stroke != null) {
+            graphics.setPaint(stroke);
+            graphics.setStroke(new BasicStroke(strokeThickness));
+            stroke(graphics);
+        }
+    }
+
+    public abstract void fill(Graphics2D graphics);
+    public abstract void stroke(Graphics2D graphics);
+
+    public abstract boolean contains(int x, int y);
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Text.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Text.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Text.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Text.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.media.drawing;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+
+import pivot.wtk.Bounds;
+
+/**
+ * Shape representing a block of text.
+ * <p>
+ * TODO We may need to specify a font here - otherwise, we won't be able to
+ * calculate the bounds.
+ */
+public class Text extends Shape {
+    private String text = null;
+    private Font font = null;
+    private int wrapWidth = -1;
+
+    public String getText() {
+        return text;
+    }
+
+    public void setText(String text) {
+        this.text = text;
+    }
+
+    public Font getFont() {
+        return font;
+    }
+
+    public void setFont(Font font) {
+        // TODO We may need to throw if null
+        this.font = font;
+    }
+
+    public int getWrapWidth() {
+        return wrapWidth;
+    }
+
+    public void setWrapWidth(int wrapWidth) {
+        if (wrapWidth < -1) {
+            throw new IllegalArgumentException(wrapWidth
+                + " is not a valid value for wrap width.");
+        }
+
+        this.wrapWidth = wrapWidth;
+    }
+
+    @Override
+    public Bounds getUntransformedBounds() {
+        // TODO Apply font as needed
+        // TODO Wrap text as needed
+
+        return null;
+    }
+
+    @Override
+    public void fill(Graphics2D graphics) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void stroke(Graphics2D graphics) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public boolean contains(int x, int y) {
+        // TODO
+        return false;
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Transform.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Transform.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Transform.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Transform.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.media.drawing;
+
+import pivot.wtk.Point;
+
+/**
+ * Abstract base class for transforms.
+ *
+ * @author gbrown
+ */
+public abstract class Transform {
+    public Point transform(int x, int y) {
+        // TODO
+        return null;
+    }
+
+    public Point transform(Point point) {
+        if (point == null) {
+            throw new IllegalArgumentException("point is null.");
+        }
+
+        return transform(point.x, point.y);
+    }
+
+    public abstract float[][] getMatrix();
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Translation.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Translation.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Translation.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/Translation.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.media.drawing;
+
+/**
+ * Transform representing a translation.
+ *
+ * @author gbrown
+ */
+public class Translation extends Transform {
+    private int x = 0;
+    private int y = 0;
+
+    public int getX() {
+        return x;
+    }
+
+    public void setX(int x) {
+        this.x = x;
+    }
+
+    public int getY() {
+        return y;
+    }
+
+    public void setY(int y) {
+        this.y = y;
+    }
+
+    public float[][] getMatrix() {
+        // TODO
+        return null;
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/package.html?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/package.html (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/drawing/package.html Mon Mar 16 16:36:10 2009
@@ -0,0 +1,8 @@
+<html>
+<head></head>
+<body>
+<p>Contains classes used to construct vector-based drawings.</p>
+<p>IMPORTANT This package contains preliminary code to support a future feature
+and is currently non-functional.</p>
+</body>
+</html>

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/package.html?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/package.html (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/media/package.html Mon Mar 16 16:36:10 2009
@@ -0,0 +1,6 @@
+<html>
+<head></head>
+<body>
+<p>Contains classes to enable multimedia support in Pivot applications.</p>
+</body>
+</html>

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/package.html?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/package.html (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/package.html Mon Mar 16 16:36:10 2009
@@ -0,0 +1,6 @@
+<html>
+<head></head>
+<body>
+<p>Contains classes that define the structure and behavior of WTK user interface components.</p>
+</body>
+</html>

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/BorderSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/BorderSkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/BorderSkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/BorderSkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.font.FontRenderContext;
+import java.awt.font.LineMetrics;
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+
+import pivot.collections.Dictionary;
+import pivot.wtk.Border;
+import pivot.wtk.BorderListener;
+import pivot.wtk.Component;
+import pivot.wtk.CornerRadii;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Insets;
+import pivot.wtk.Theme;
+
+/**
+ * Border skin.
+ * <p>
+ * TODO Draw title.
+ *
+ * @author gbrown
+ */
+public class BorderSkin extends ContainerSkin
+    implements BorderListener {
+    private FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
+
+    private Font font;
+    private Color color;
+    private Color titleColor;
+    private int thickness;
+    private Insets padding;
+    private CornerRadii cornerRadii;
+
+    public BorderSkin() {
+        Theme theme = Theme.getTheme();
+        setBackgroundColor(Color.WHITE);
+
+        font = theme.getFont().deriveFont(Font.BOLD);
+        color = Color.BLACK;
+        titleColor = Color.BLACK;
+        thickness = 1;
+        padding = new Insets(2);
+        cornerRadii = new CornerRadii(0);
+    }
+
+    @Override
+    public void install(Component component) {
+        super.install(component);
+
+        Border border = (Border)component;
+        border.getBorderListeners().add(this);
+    }
+
+    @Override
+    public void uninstall() {
+        Border border = (Border)getComponent();
+        border.getBorderListeners().remove(this);
+
+        super.uninstall();
+    }
+
+    @Override
+    public int getPreferredWidth(int height) {
+        int preferredWidth = 0;
+
+        Border border = (Border)getComponent();
+        int topThickness = thickness;
+
+        String title = border.getTitle();
+        if (title != null
+            && title.length() > 0) {
+            Rectangle2D headingBounds = font.getStringBounds(title, fontRenderContext);
+            preferredWidth = (int)Math.ceil(headingBounds.getWidth());
+
+            LineMetrics lm = font.getLineMetrics(title, fontRenderContext);
+            topThickness = Math.max((int)Math.ceil(lm.getAscent() + lm.getDescent()
+                + lm.getLeading()), topThickness);
+        }
+
+        Component content = border.getContent();
+        if (content != null
+            && content.isDisplayable()) {
+            if (height != -1) {
+                height = Math.max(height - (topThickness + thickness) -
+                    padding.top - padding.bottom, 0);
+            }
+
+            preferredWidth = content.getPreferredWidth(height);
+        }
+
+        preferredWidth += (padding.left + padding.right) + (thickness * 2);
+
+        return preferredWidth;
+    }
+
+    @Override
+    public int getPreferredHeight(int width) {
+        int preferredHeight = 0;
+
+        Border border = (Border)getComponent();
+        int topThickness = thickness;
+
+        String title = border.getTitle();
+        if (title != null
+            && title.length() > 0) {
+            LineMetrics lm = font.getLineMetrics(title, fontRenderContext);
+            topThickness = Math.max((int)Math.ceil(lm.getAscent() + lm.getDescent()
+                + lm.getLeading()), topThickness);
+        }
+
+        Component content = border.getContent();
+        if (content != null
+            && content.isDisplayable()) {
+            if (width != -1) {
+                width = Math.max(width - (thickness * 2)
+                    - padding.left - padding.right, 0);
+            }
+
+            preferredHeight = content.getPreferredHeight(width);
+        }
+
+        preferredHeight += (padding.top + padding.bottom) + (topThickness + thickness);
+
+        return preferredHeight;
+    }
+
+    @Override
+    public Dimensions getPreferredSize() {
+        // TODO Optimize
+        return new Dimensions(getPreferredWidth(-1), getPreferredHeight(-1));
+    }
+
+    public void layout() {
+        int width = getWidth();
+        int height = getHeight();
+
+        Border border = (Border)getComponent();
+        int topThickness = thickness;
+
+        String title = border.getTitle();
+        if (title != null
+            && title.length() > 0) {
+            LineMetrics lm = font.getLineMetrics(title, fontRenderContext);
+            topThickness = Math.max((int)Math.ceil(lm.getAscent() + lm.getDescent()
+                + lm.getLeading()), topThickness);
+        }
+
+        Component content = border.getContent();
+        if (content != null) {
+            if (content.isDisplayable()) {
+                content.setVisible(true);
+
+                content.setLocation(padding.left + thickness,
+                    padding.top + topThickness);
+
+                int contentWidth = Math.max(width - (padding.left + padding.right
+                    + (thickness * 2)), 0);
+                int contentHeight = Math.max(height - (padding.top + padding.bottom
+                    + (topThickness + thickness)), 0);
+
+                content.setSize(contentWidth, contentHeight);
+            } else {
+                content.setVisible(false);
+            }
+        }
+    }
+
+    @Override
+    public void paint(Graphics2D graphics) {
+        Border border = (Border)getComponent();
+        int topThickness = thickness;
+        float titleAscent = 0;
+
+        String title = border.getTitle();
+        if (title != null
+            && title.length() > 0) {
+            LineMetrics lm = font.getLineMetrics(title, fontRenderContext);
+            titleAscent = lm.getAscent();
+            topThickness = Math.max((int)Math.ceil(titleAscent
+                + lm.getDescent() + lm.getLeading()), topThickness);
+        }
+
+        // TODO Java2D doesn't support variable corner radii; we'll need to
+        // "fake" this by drawing multiple arcs
+        int cornerRadius = cornerRadii.topLeft;
+
+        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+            RenderingHints.VALUE_ANTIALIAS_ON);
+
+        int x = thickness / 2;
+        int y = topThickness / 2;
+        int width = Math.max(getWidth() - thickness, 0);
+        int height = Math.max(getHeight() - (int)Math.ceil((topThickness + thickness) * 0.5), 0);
+
+        // Draw the background
+        Color backgroundColor = getBackgroundColor();
+        if (backgroundColor != null) {
+            graphics.setPaint(backgroundColor);
+            graphics.fillRoundRect(x, y, width, height, cornerRadius, cornerRadius);
+        }
+
+        // Draw the title
+        if (title != null) {
+            if (fontRenderContext.isAntiAliased()) {
+                // TODO Use VALUE_TEXT_ANTIALIAS_LCD_HRGB when JDK 1.6 is
+                // available on OSX?
+                graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+                    RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+            }
+
+            if (fontRenderContext.usesFractionalMetrics()) {
+                graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+                    RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+            }
+
+            // Note that we add one pixel to the string bounds for spacing
+            Rectangle2D titleBounds = font.getStringBounds(title, fontRenderContext);
+            titleBounds = new Rectangle2D.Double((double)(padding.left + thickness),
+                (topThickness - titleBounds.getHeight()) / 2,
+                    titleBounds.getWidth() + 1, titleBounds.getHeight());
+
+            graphics.setFont(font);
+            graphics.setPaint(titleColor);
+            graphics.drawString(title, (int)titleBounds.getX(),
+                (int)(titleBounds.getY() + titleAscent));
+
+            Area titleClip = new Area(graphics.getClip());
+            titleClip.subtract(new Area(titleBounds));
+            graphics.clip(titleClip);
+        }
+
+        // Draw the border
+        if (thickness > 0) {
+            graphics.setPaint(color);
+            graphics.setStroke(new BasicStroke(thickness));
+            graphics.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius);
+        }
+    }
+
+    public Font getFont() {
+        return font;
+    }
+
+    public void setFont(Font font) {
+        if (font == null) {
+            throw new IllegalArgumentException("font is null.");
+        }
+
+        this.font = font;
+        invalidateComponent();
+    }
+
+    public final void setFont(String font) {
+        if (font == null) {
+            throw new IllegalArgumentException("font is null.");
+        }
+
+        setFont(Font.decode(font));
+    }
+
+    public Color getColor() {
+        return color;
+    }
+
+    public void setColor(Color color) {
+        if (color == null) {
+            throw new IllegalArgumentException("color is null.");
+        }
+
+        this.color = color;
+        repaintComponent();
+    }
+
+    public final void setColor(String color) {
+        if (color == null) {
+            throw new IllegalArgumentException("color is null.");
+        }
+
+        setColor(decodeColor(color));
+    }
+
+    public Color getTitleColor() {
+        return titleColor;
+    }
+
+    public void setTitleColor(Color titleColor) {
+        if (titleColor == null) {
+            throw new IllegalArgumentException("titleColor is null.");
+        }
+
+        this.titleColor = titleColor;
+        repaintComponent();
+    }
+
+    public final void setTitleColor(String titleColor) {
+        if (titleColor == null) {
+            throw new IllegalArgumentException("titleColor is null.");
+        }
+
+        setTitleColor(decodeColor(titleColor));
+    }
+
+    public int getThickness() {
+        return thickness;
+    }
+
+    public void setThickness(int thickness) {
+        this.thickness = thickness;
+        repaintComponent();
+    }
+
+    public void setThickness(Number thickness) {
+        if (thickness == null) {
+            throw new IllegalArgumentException("thickness is null.");
+        }
+
+        setThickness(thickness.intValue());
+    }
+
+    public Insets getPadding() {
+        return padding;
+    }
+
+    public void setPadding(Insets padding) {
+        if (padding == null) {
+            throw new IllegalArgumentException("padding is null.");
+        }
+
+        this.padding = padding;
+        invalidateComponent();
+    }
+
+    public final void setPadding(Dictionary<String, ?> padding) {
+        if (padding == null) {
+            throw new IllegalArgumentException("padding is null.");
+        }
+
+        setPadding(new Insets(padding));
+    }
+
+    public final void setPadding(int padding) {
+        setPadding(new Insets(padding));
+    }
+
+    public void setPadding(Number padding) {
+        if (padding == null) {
+            throw new IllegalArgumentException("padding is null.");
+        }
+
+        setPadding(padding.intValue());
+    }
+
+    public CornerRadii getCornerRadii() {
+        return cornerRadii;
+    }
+
+    public void setCornerRadii(CornerRadii cornerRadii) {
+        if (cornerRadii == null) {
+            throw new IllegalArgumentException("cornerRadii is null.");
+        }
+
+        this.cornerRadii = cornerRadii;
+        repaintComponent();
+    }
+
+    public final void setCornerRadii(Dictionary<String, ?> cornerRadii) {
+        if (cornerRadii == null) {
+            throw new IllegalArgumentException("cornerRadii is null.");
+        }
+
+        setCornerRadii(new CornerRadii(cornerRadii));
+    }
+
+    public final void setCornerRadii(int cornerRadii) {
+        setCornerRadii(new CornerRadii(cornerRadii));
+    }
+
+    public void setCornerRadii(Number cornerRadii) {
+        if (cornerRadii == null) {
+            throw new IllegalArgumentException("cornerRadii is null.");
+        }
+
+        setCornerRadii(cornerRadii.intValue());
+    }
+
+    // Border events
+    public void titleChanged(Border border, String previousTitle) {
+        invalidateComponent();
+    }
+
+    public void contentChanged(Border border, Component previousContent) {
+        invalidateComponent();
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ButtonSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ButtonSkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ButtonSkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ButtonSkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import pivot.util.Vote;
+import pivot.wtk.Action;
+import pivot.wtk.Button;
+import pivot.wtk.ButtonListener;
+import pivot.wtk.ButtonPressListener;
+import pivot.wtk.ButtonStateListener;
+import pivot.wtk.Component;
+import pivot.wtk.Cursor;
+
+/**
+ * Abstract base class for button skins.
+ *
+ * @author gbrown
+ */
+public abstract class ButtonSkin extends ComponentSkin
+    implements ButtonListener, ButtonStateListener, ButtonPressListener {
+    protected boolean highlighted = false;
+
+    @Override
+    public void install(Component component) {
+        super.install(component);
+
+        Button button = (Button)component;
+        button.getButtonListeners().add(this);
+        button.getButtonStateListeners().add(this);
+        button.getButtonPressListeners().add(this);
+
+        button.setCursor(Cursor.HAND);
+    }
+
+    @Override
+    public void uninstall() {
+        Button button = (Button)getComponent();
+        button.getButtonListeners().remove(this);
+        button.getButtonStateListeners().remove(this);
+        button.getButtonPressListeners().remove(this);
+
+        button.setCursor(Cursor.DEFAULT);
+
+        super.uninstall();
+    }
+
+    public void layout() {
+        // No-op
+    }
+
+    // Component state events
+    @Override
+    public void enabledChanged(Component component) {
+        super.enabledChanged(component);
+
+        highlighted = false;
+        repaintComponent();
+    }
+
+    @Override
+    public void focusedChanged(Component component, boolean temporary) {
+        super.focusedChanged(component, temporary);
+
+        repaintComponent();
+    }
+
+    // Component mouse events
+    @Override
+    public void mouseOver(Component component) {
+        super.mouseOver(component);
+
+        highlighted = true;
+        repaintComponent();
+    }
+
+    @Override
+    public void mouseOut(Component component) {
+        super.mouseOut(component);
+
+        highlighted = false;
+        repaintComponent();
+    }
+
+    // Button events
+    public void buttonDataChanged(Button button, Object previousButtonData) {
+        invalidateComponent();
+    }
+
+    public void dataRendererChanged(Button button, Button.DataRenderer previousDataRenderer) {
+        invalidateComponent();
+    }
+
+    public void actionChanged(Button button, Action previousAction) {
+        // No-op
+    }
+
+    public void toggleButtonChanged(Button button) {
+        // No-op
+    }
+
+    public void triStateChanged(Button button) {
+        // No-op
+    }
+
+    public void groupChanged(Button button, Button.Group previousGroup) {
+        // No-op
+    }
+
+    public void selectedKeyChanged(Button button, String previousSelectedKey) {
+        // No-op
+    }
+
+    public void stateKeyChanged(Button button, String previousStateKey) {
+        // No-op
+    }
+
+    // Button state events
+    public Vote previewStateChange(Button button, Button.State state) {
+        return Vote.APPROVE;
+    }
+
+    public void stateChangeVetoed(Button button, Vote reason) {
+        // No-op
+    }
+
+    public void stateChangeVetoed(Button button) {
+        // No-op
+    }
+
+    public void stateChanged(Button button, Button.State previousState) {
+        repaintComponent();
+    }
+
+    // Button press events
+    public void buttonPressed(Button button) {
+        // No-op
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CardPaneSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CardPaneSkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CardPaneSkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CardPaneSkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import pivot.wtk.CardPane;
+import pivot.wtk.CardPaneListener;
+import pivot.wtk.Component;
+import pivot.wtk.Dimensions;
+
+/**
+ * Card pane skin.
+ *
+ * @author gbrown
+ */
+public class CardPaneSkin extends ContainerSkin implements CardPaneListener {
+    public void install(Component component) {
+        super.install(component);
+
+        CardPane cardPane = (CardPane)component;
+        cardPane.getCardPaneListeners().add(this);
+    }
+
+    public void uninstall() {
+        CardPane cardPane = (CardPane)getComponent();
+        cardPane.getCardPaneListeners().remove(this);
+
+        super.uninstall();
+    }
+
+    public int getPreferredWidth(int height) {
+        int preferredWidth = 0;
+        CardPane cardPane = (CardPane)getComponent();
+
+        for (Component component : cardPane) {
+            preferredWidth = Math.max(preferredWidth,
+                component.getPreferredWidth(height));
+        }
+
+        return preferredWidth;
+    }
+
+    public int getPreferredHeight(int width) {
+        int preferredHeight = 0;
+        CardPane cardPane = (CardPane)getComponent();
+
+        for (Component component : cardPane) {
+            preferredHeight = Math.max(preferredHeight,
+                component.getPreferredHeight(width));
+        }
+
+        return preferredHeight;
+    }
+
+    public Dimensions getPreferredSize() {
+        int preferredWidth = 0;
+        int preferredHeight = 0;
+
+        CardPane cardPane = (CardPane)getComponent();
+
+        for (Component component : cardPane) {
+            Dimensions preferredCardSize = component.getPreferredSize();
+
+            preferredWidth = Math.max(preferredWidth,
+                preferredCardSize.width);
+
+            preferredHeight = Math.max(preferredHeight,
+                preferredCardSize.height);
+        }
+
+        return new Dimensions(preferredWidth, preferredHeight);
+    }
+
+    public void layout() {
+        // Hide all cards but the selected card; set the size of the selected
+        // card to match the size of the card pane
+        CardPane cardPane = (CardPane)getComponent();
+        int selectedIndex = cardPane.getSelectedIndex();
+
+        for (int i = 0, n = cardPane.getLength(); i < n; i++) {
+            Component component = cardPane.get(i);
+            if (i == selectedIndex) {
+                component.setVisible(true);
+                component.setSize(getWidth(), getHeight());
+            } else {
+                component.setVisible(false);
+            }
+        }
+    }
+
+    public void selectedIndexChanged(CardPane cardPane, int previousSelectedIndex) {
+        invalidateComponent();
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CheckboxSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CheckboxSkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CheckboxSkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/CheckboxSkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import pivot.wtk.Checkbox;
+import pivot.wtk.Component;
+import pivot.wtk.Keyboard;
+import pivot.wtk.Mouse;
+
+/**
+ * Abstract base class for checkbox skins.
+ *
+ * @author gbrown
+ */
+public abstract class CheckboxSkin extends ButtonSkin {
+    @Override
+    public void mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+        Checkbox checkbox = (Checkbox)getComponent();
+
+        checkbox.requestFocus();
+        checkbox.press();
+    }
+
+    @Override
+    public boolean keyReleased(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+        boolean consumed = false;
+
+        Checkbox checkbox = (Checkbox)getComponent();
+
+        if (keyCode == Keyboard.KeyCode.SPACE) {
+            checkbox.press();
+        } else {
+            consumed = super.keyReleased(component, keyCode, keyLocation);
+        }
+
+        return consumed;
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ComponentSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ComponentSkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ComponentSkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ComponentSkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import java.awt.Color;
+
+import pivot.util.Vote;
+import pivot.wtk.ApplicationContext;
+import pivot.wtk.Component;
+import pivot.wtk.ComponentKeyListener;
+import pivot.wtk.ComponentLayoutListener;
+import pivot.wtk.ComponentListener;
+import pivot.wtk.ComponentMouseButtonListener;
+import pivot.wtk.ComponentMouseListener;
+import pivot.wtk.ComponentMouseWheelListener;
+import pivot.wtk.ComponentStateListener;
+import pivot.wtk.Container;
+import pivot.wtk.Cursor;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Direction;
+import pivot.wtk.Keyboard;
+import pivot.wtk.Mouse;
+import pivot.wtk.Bounds;
+import pivot.wtk.Skin;
+import pivot.wtk.Tooltip;
+
+/**
+ * Abstract base class for component skins.
+ *
+ * @author gbrown
+ */
+public abstract class ComponentSkin implements Skin, ComponentListener,
+    ComponentLayoutListener, ComponentStateListener, ComponentMouseListener,
+    ComponentMouseButtonListener, ComponentMouseWheelListener,
+    ComponentKeyListener {
+    private class ShowTooltipCallback implements Runnable {
+        public void run() {
+            Component component = getComponent();
+            String tooltipText = component.getTooltipText();
+
+            // The tooltip text may have been cleared while the timeout was
+            // outstanding; if so, don't display the tooltip
+            if (tooltipText != null) {
+                // TODO Re-use a static tooltip?
+                Tooltip tooltip = new Tooltip(tooltipText);
+
+                // TODO Ensure that the tooltip stays on screen
+                tooltip.setLocation(Mouse.getX() + 16, Mouse.getY());
+                tooltip.open(component.getWindow());
+            }
+        }
+    }
+
+    private Component component = null;
+
+    private int width = 0;
+    private int height = 0;
+
+    private ShowTooltipCallback showTooltipCallback = new ShowTooltipCallback();
+    private int showTooltipTimeoutID = -1;
+
+    public static final int SHOW_TOOLTIP_TIMEOUT = 1000;
+
+    public int getWidth() {
+        return width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public void setSize(int width, int height) {
+        this.width = width;
+        this.height = height;
+    }
+
+    public Dimensions getPreferredSize() {
+        return new Dimensions(getPreferredWidth(-1), getPreferredHeight(-1));
+    }
+
+    public void install(Component component) {
+        assert(this.component == null) : "Skin is already installed on a component.";
+
+        component.getComponentListeners().add(this);
+        component.getComponentLayoutListeners().add(this);
+        component.getComponentStateListeners().add(this);
+        component.getComponentMouseListeners().add(this);
+        component.getComponentMouseButtonListeners().add(this);
+        component.getComponentMouseWheelListeners().add(this);
+        component.getComponentKeyListeners().add(this);
+
+        this.component = component;
+    }
+
+    public void uninstall() {
+        component.getComponentListeners().remove(this);
+        component.getComponentLayoutListeners().remove(this);
+        component.getComponentStateListeners().remove(this);
+        component.getComponentMouseListeners().remove(this);
+        component.getComponentMouseButtonListeners().remove(this);
+        component.getComponentMouseWheelListeners().remove(this);
+        component.getComponentKeyListeners().remove(this);
+
+        component = null;
+    }
+
+    public Component getComponent() {
+        return component;
+    }
+
+    /**
+     * By default, components are focusable.
+     */
+    public boolean isFocusable() {
+        return true;
+    }
+
+    // Component events
+    public void parentChanged(Component component, Container previousParent) {
+        // No-op
+    }
+
+    public void sizeChanged(Component component, int previousWidth, int previousHeight) {
+        // No-op
+    }
+
+    public void locationChanged(Component component, int previousX, int previousY) {
+        // No-op
+    }
+
+    public void visibleChanged(Component component) {
+        // No-op
+    }
+
+    public void styleUpdated(Component component, String styleKey, Object previousValue) {
+        // No-op
+    }
+
+    public void cursorChanged(Component component, Cursor previousCursor) {
+        // No-op
+    }
+
+    public void tooltipTextChanged(Component component, String previousTooltipText) {
+        // TODO Handle change here instead of in ShowTooltipCallback?
+    }
+
+    // Component layout events
+    public void preferredSizeChanged(Component component,
+        int previousPreferredWidth, int previousPreferredHeight) {
+        // No-op
+    }
+
+    public void displayableChanged(Component component) {
+        // No-op
+    }
+
+    // Component state events
+    public Vote previewEnabledChange(Component component) {
+        return Vote.APPROVE;
+    }
+
+    public void enabledChangeVetoed(Component component, Vote reason) {
+        // No-op
+    }
+
+    public void enabledChangeVetoed(Component component) {
+        // No-op
+    }
+
+    public void enabledChanged(Component component) {
+        // No-op
+    }
+
+    public Vote previewFocusedChange(Component component, boolean temporary) {
+        return Vote.APPROVE;
+    }
+
+    public void focusedChangeVetoed(Component component, Vote reason) {
+        // No-op
+    }
+
+    public void focusedChangeVetoed(Component component) {
+        // No-op
+    }
+
+    public void focusedChanged(Component component, boolean temporary) {
+        // Ensure that the component is visible if it is in a viewport
+        if (component.isFocused()
+            && !temporary) {
+            component.scrollAreaToVisible(0, 0, getWidth(), getHeight());
+        }
+    }
+
+    // Component mouse events
+    public boolean mouseMove(Component component, int x, int y) {
+        ApplicationContext.clearTimeout(showTooltipTimeoutID);
+
+        if (getComponent().getTooltipText() != null) {
+            showTooltipTimeoutID = ApplicationContext.setTimeout(showTooltipCallback,
+                SHOW_TOOLTIP_TIMEOUT);
+        }
+
+        return false;
+    }
+
+    public void mouseOver(Component component) {
+    }
+
+    public void mouseOut(Component component) {
+        ApplicationContext.clearTimeout(showTooltipTimeoutID);
+    }
+
+    // Component mouse button events
+    public boolean mouseDown(Component component, Mouse.Button button, int x, int y) {
+        return false;
+    }
+
+    public boolean mouseUp(Component component, Mouse.Button button, int x, int y) {
+        return false;
+    }
+
+    public void mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+    }
+
+    // Component mouse wheel events
+    public boolean mouseWheel(Component component, Mouse.ScrollType scrollType, int scrollAmount,
+        int wheelRotation, int x, int y) {
+        return false;
+    }
+
+    // Component key events
+    public void keyTyped(Component component, char character) {
+    }
+
+    public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+        boolean consumed = false;
+
+        if (keyCode == Keyboard.KeyCode.TAB
+            && getComponent().isFocused()) {
+            Direction direction = (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) ?
+                Direction.BACKWARD : Direction.FORWARD;
+
+            Component previousFocusedComponent = Component.getFocusedComponent();
+            previousFocusedComponent.transferFocus(direction);
+
+            Component focusedComponent = Component.getFocusedComponent();
+
+            consumed = (previousFocusedComponent != focusedComponent);
+        }
+
+        return consumed;
+    }
+
+    public boolean keyReleased(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+        return false;
+    }
+
+    // Utility methods
+    protected void invalidateComponent() {
+        if (component != null) {
+            component.invalidate();
+            component.repaint();
+        }
+    }
+
+    protected void repaintComponent() {
+        if (component != null) {
+            component.repaint();
+        }
+    }
+
+    protected void repaintComponent(Bounds area) {
+        assert (area != null) : "area is null.";
+
+        if (component != null) {
+            component.repaint(area.x, area.y, area.width, area.height);
+        }
+    }
+
+    protected void repaintComponent(int x, int y, int width, int height) {
+        if (component != null) {
+            component.repaint(x, y, width, height);
+        }
+    }
+
+    public static Color decodeColor(String name) throws NumberFormatException {
+        int numericIndex = 0;
+        if (name.startsWith("0x")
+            || name.startsWith("0X")) {
+            numericIndex += 2;
+        } else if (name.startsWith("#")) {
+            numericIndex++;
+        }
+
+        int rgb = Integer.decode(name);
+
+        Color color;
+
+        if (((rgb >> 24) & 0xff) > 0
+            || name.length() - numericIndex > 6) {
+            // Extract the alpha channel
+            float red = ((rgb >> 16) & 0xff) / 255f;
+            float green = ((rgb >> 8) & 0xff) / 255f;
+            float blue = (rgb & 0xff) / 255f;
+            float alpha = ((rgb >> 24) & 0xff) / 255f;
+
+            color = new Color(red, green, blue, alpha);
+        } else {
+            color = new Color((rgb >> 16) & 0xff, (rgb >> 8) & 0xff, rgb & 0xff);
+        }
+
+        return color;
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ContainerSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ContainerSkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ContainerSkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/ContainerSkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+
+import pivot.collections.Sequence;
+import pivot.wtk.Component;
+import pivot.wtk.Container;
+import pivot.wtk.ContainerListener;
+import pivot.wtk.Direction;
+import pivot.wtk.FocusTraversalPolicy;
+
+/**
+ * Abstract base class for container skins.
+ *
+ * @author gbrown
+ */
+public abstract class ContainerSkin extends ComponentSkin
+    implements ContainerListener {
+    /**
+     * Focus traversal policy that determines traversal order based on the order
+     * of components in the container's component sequence.
+     *
+     * @author gbrown
+     */
+    public static class IndexFocusTraversalPolicy implements FocusTraversalPolicy {
+        private boolean wrap;
+
+        public IndexFocusTraversalPolicy() {
+            this(false);
+        }
+
+        public IndexFocusTraversalPolicy(boolean wrap) {
+            this.wrap = wrap;
+        }
+
+        public Component getNextComponent(Container container, Component component, Direction direction) {
+            if (container == null) {
+                throw new IllegalArgumentException("container is null.");
+            }
+
+            if (direction == null) {
+                throw new IllegalArgumentException("direction is null.");
+            }
+
+            Component nextComponent = null;
+
+            int n = container.getLength();
+            if (n > 0) {
+                switch (direction) {
+                    case FORWARD: {
+                        if (component == null) {
+                            // Return the first component in the sequence
+                            nextComponent = container.get(0);
+                        } else {
+                            // Return the next component in the sequence
+                            int index = container.indexOf(component);
+                            if (index == -1) {
+                                throw new IllegalArgumentException();
+                            }
+
+                            if (index < n - 1) {
+                                nextComponent = container.get(index + 1);
+                            } else {
+                                if (wrap
+                                    && container.containsFocus()) {
+                                    nextComponent = container.get(0);
+                                }
+                            }
+                        }
+
+                        break;
+                    }
+
+                    case BACKWARD: {
+                        if (component == null) {
+                            // Return the last component in the sequence
+                            nextComponent = container.get(n - 1);
+                        } else {
+                            // Return the previous component in the sequence
+                            int index = container.indexOf(component);
+                            if (index == -1) {
+                                throw new IllegalArgumentException();
+                            }
+
+                            if (index > 0) {
+                                nextComponent = container.get(index - 1);
+                            } else {
+                                if (wrap
+                                    && container.containsFocus()) {
+                                    nextComponent = container.get(n - 1);
+                                }
+                            }
+                        }
+
+                        break;
+                    }
+                }
+            }
+
+            return nextComponent;
+        }
+    }
+
+    private Paint backgroundPaint = null;
+
+    @Override
+    public void install(Component component) {
+        super.install(component);
+
+        Container container = (Container)component;
+
+        // Add this as a container listener
+        container.getContainerListeners().add(this);
+
+        // Set the focus traversal policy
+        container.setFocusTraversalPolicy(new IndexFocusTraversalPolicy());
+    }
+
+    public void uninstall() {
+        Container container = (Container)getComponent();
+
+        // Remove this as a container listener
+        container.getContainerListeners().remove(this);
+
+        // Clear the focus traversal policy
+        container.setFocusTraversalPolicy(null);
+
+        super.uninstall();
+    }
+
+    public int getPreferredWidth(int height) {
+        return 0;
+    }
+
+    public int getPreferredHeight(int width) {
+        return 0;
+    }
+
+    public void paint(Graphics2D graphics) {
+        if (backgroundPaint != null) {
+            graphics.setPaint(backgroundPaint);
+            graphics.fillRect(0, 0, getWidth(), getHeight());
+        }
+    }
+
+    /**
+     * @return
+     * <tt>false</tt>; containers are not focusable.
+     */
+    @Override
+    public final boolean isFocusable() {
+        return false;
+    }
+
+    public Paint getBackgroundPaint() {
+        return backgroundPaint;
+    }
+
+    public void setBackgroundPaint(Paint backgroundPaint) {
+        this.backgroundPaint = backgroundPaint;
+        repaintComponent();
+    }
+
+    public Color getBackgroundColor() {
+        if (backgroundPaint != null
+            && !(backgroundPaint instanceof Color)) {
+            throw new IllegalStateException("Background paint is not a Color.");
+        }
+        return (Color)backgroundPaint;
+    }
+
+    public void setBackgroundColor(Color backgroundColor) {
+        setBackgroundPaint(backgroundColor);
+    }
+
+    public final void setBackgroundColor(String backgroundColor) {
+        if (backgroundColor == null) {
+            throw new IllegalArgumentException("backgroundColor is null");
+        }
+
+        setBackgroundColor(decodeColor(backgroundColor));
+    }
+
+    // Container events
+    public void componentInserted(Container container, int index) {
+    }
+
+    public void componentsRemoved(Container container, int index, Sequence<Component> removed) {
+    }
+
+    public void contextKeyChanged(Container container, String previousContextKey) {
+        // No-op
+    }
+
+    public void focusTraversalPolicyChanged(Container container,
+        FocusTraversalPolicy previousFocusTraversalPolicy) {
+        // No-op
+    }
+}

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/DisplaySkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/DisplaySkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/DisplaySkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/DisplaySkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import java.awt.Color;
+import pivot.wtk.Component;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Display;
+import pivot.wtk.Window;
+
+/**
+ * Display skin.
+ *
+ * @author gbrown
+ */
+public class DisplaySkin extends ContainerSkin {
+    // Style properties
+    private boolean activeWindowFollowsMouse = false;
+
+    public DisplaySkin() {
+        super();
+        setBackgroundColor(Color.LIGHT_GRAY);
+    }
+
+    @Override
+    public void install(Component component) {
+        if (!(component instanceof Display)) {
+            throw new IllegalArgumentException("DisplaySkin can only be installed on instances of Display.");
+        }
+
+        super.install(component);
+    }
+
+    public void layout() {
+        Display display = (Display)getComponent();
+
+        // Set all components to their preferred sizes
+        for (Component component : display) {
+            Window window = (Window)component;
+
+            if (window.isDisplayable()) {
+                boolean maximized = window.isMaximized();
+
+                if (maximized) {
+                    window.setLocation(0, 0);
+                    window.setSize(display.getSize());
+                } else {
+                    Dimensions preferredSize = window.getPreferredSize();
+                    int preferredWidth = preferredSize.width;
+                    int preferredHeight = preferredSize.height;
+
+                    if (window.getWidth() != preferredWidth
+                        || window.getHeight() != preferredHeight) {
+                        window.setSize(preferredWidth, preferredHeight);
+                    }
+                }
+
+                window.setVisible(true);
+            } else {
+                window.setVisible(false);
+            }
+        }
+    }
+
+    public boolean getActiveWindowFollowsMouse() {
+        return activeWindowFollowsMouse;
+    }
+
+    public void setActiveWindowFollowsMouse(boolean activeWindowFollowsMouse) {
+        this.activeWindowFollowsMouse = activeWindowFollowsMouse;
+    }
+
+    @Override
+    public boolean mouseMove(Component component, int x, int y) {
+        boolean consumed = super.mouseMove(component, x, y);
+
+        if (activeWindowFollowsMouse) {
+            Display display = (Display)getComponent();
+
+            Window window = (Window)display.getComponentAt(x, y);
+            if (window != null
+                && window.isEnabled()
+                && !window.isAuxilliary()) {
+                Window.setActiveWindow(window);
+            }
+        }
+
+        return consumed;
+    }
+}
+

Added: incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/FlowPaneSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/FlowPaneSkin.java?rev=754936&view=auto
==============================================================================
--- incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/FlowPaneSkin.java (added)
+++ incubator/pivot/tags/v1.0.1/wtk/src/pivot/wtk/skin/FlowPaneSkin.java Mon Mar 16 16:36:10 2009
@@ -0,0 +1,568 @@
+/*
+ * Copyright (c) 2008 VMware, Inc.
+ *
+ * Licensed 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package pivot.wtk.skin;
+
+import pivot.collections.Dictionary;
+import pivot.wtk.Component;
+import pivot.wtk.Dimensions;
+import pivot.wtk.FlowPane;
+import pivot.wtk.FlowPaneListener;
+import pivot.wtk.HorizontalAlignment;
+import pivot.wtk.Insets;
+import pivot.wtk.Orientation;
+import pivot.wtk.VerticalAlignment;
+
+/**
+ * Flow pane skin.
+ *
+ * @author gbrown
+ */
+public class FlowPaneSkin extends ContainerSkin
+    implements FlowPaneListener {
+    private HorizontalAlignment horizontalAlignment = HorizontalAlignment.LEFT;
+    private VerticalAlignment verticalAlignment = VerticalAlignment.TOP;
+    private Insets padding = new Insets(0);
+    private int spacing = 4;
+
+    public int getPreferredWidth(int height) {
+        int preferredWidth = 0;
+
+        // Include padding in constraint
+        if (height != -1) {
+            height = Math.max(height - (padding.top + padding.bottom), 0);
+        }
+
+        FlowPane flowPane = (FlowPane)getComponent();
+        int n = flowPane.getLength();
+
+        Orientation orientation = flowPane.getOrientation();
+        if (orientation == Orientation.HORIZONTAL) {
+            // Preferred width is the sum of the preferred widths of all
+            // components, plus spacing
+            int displayableComponentCount = 0;
+
+            for (int i = 0; i < n; i++) {
+                Component component = flowPane.get(i);
+
+                if (component.isDisplayable()) {
+                    preferredWidth += component.getPreferredWidth(height);
+                    displayableComponentCount++;
+                }
+            }
+
+            if (displayableComponentCount > 1) {
+                preferredWidth += spacing * (displayableComponentCount - 1);
+            }
+        } else {
+            // Preferred width is the maximum preferred width of all components
+            int maxComponentWidth = 0;
+
+            // Determine the fixed and total preferred heights, if necessary
+            int totalSpacing = 0;
+            int totalPreferredHeight = 0;
+
+            if (horizontalAlignment == HorizontalAlignment.JUSTIFY
+                && height != -1) {
+                int displayableComponentCount = 0;
+                for (int i = 0; i < n; i++) {
+                    Component component = flowPane.get(i);
+
+                    if (component.isDisplayable()) {
+                        totalPreferredHeight += component.getPreferredHeight(-1);
+                        displayableComponentCount++;
+                    }
+                }
+
+                if (displayableComponentCount > 1) {
+                    totalSpacing = spacing * (displayableComponentCount - 1);
+                }
+            }
+
+            for (int i = 0; i < n; i++) {
+                Component component = flowPane.get(i);
+
+                if (component.isDisplayable()) {
+                    int componentHeight = -1;
+
+                    if (verticalAlignment == VerticalAlignment.JUSTIFY
+                        && height != -1) {
+                        int preferredHeight = component.getPreferredHeight(-1);
+
+                        if (height > totalSpacing
+                            && preferredHeight > totalSpacing) {
+                            double heightScale = (double)preferredHeight
+                                / (double)totalPreferredHeight;
+
+                            componentHeight = (int)Math.round((double)(height
+                                - totalSpacing) * heightScale);
+                        } else {
+                            componentHeight = 0;
+                        }
+                    }
+
+                    maxComponentWidth = Math.max(maxComponentWidth,
+                        component.getPreferredWidth(componentHeight));
+                }
+            }
+
+            preferredWidth += maxComponentWidth;
+        }
+
+        // Include left and right padding values
+        preferredWidth += padding.left + padding.right;
+
+        return preferredWidth;
+    }
+
+    public int getPreferredHeight(int width) {
+        int preferredHeight = 0;
+
+        // Include padding in constraint
+        if (width != -1) {
+            width = Math.max(width - (padding.left + padding.right), 0);
+        }
+
+        FlowPane flowPane = (FlowPane)getComponent();
+        int n = flowPane.getLength();
+
+        Orientation orientation = flowPane.getOrientation();
+        if (orientation == Orientation.VERTICAL) {
+            // Preferred height is the sum of the preferred heights of all
+            // components, plus padding and spacing
+            int displayableComponentCount = 0;
+
+            for (int i = 0; i < n; i++) {
+                Component component = flowPane.get(i);
+
+                if (component.isDisplayable()) {
+                    preferredHeight += component.getPreferredHeight(width);
+                    displayableComponentCount++;
+                }
+            }
+
+            if (displayableComponentCount > 1) {
+                preferredHeight += spacing * (displayableComponentCount - 1);
+            }
+        } else {
+            // Preferred height is the maximum preferred height of all
+            // components, plus padding
+            int maxComponentHeight = 0;
+
+            // Determine the fixed and total preferred widths, if necessary
+            int totalSpacing = 0;
+            int totalPreferredWidth = 0;
+
+            if (horizontalAlignment == HorizontalAlignment.JUSTIFY
+                && width != -1) {
+                int displayableComponentCount = 0;
+
+                for (int i = 0; i < n; i++) {
+                    Component component = flowPane.get(i);
+
+                    if (component.isDisplayable()) {
+                        totalPreferredWidth += component.getPreferredWidth(-1);
+                        displayableComponentCount++;
+                    }
+                }
+
+                if (displayableComponentCount > 1) {
+                    totalSpacing = spacing * (displayableComponentCount - 1);
+                }
+            }
+
+            for (int i = 0; i < n; i++) {
+                Component component = flowPane.get(i);
+
+                if (component.isDisplayable()) {
+                    int componentWidth = -1;
+
+                    if (horizontalAlignment == HorizontalAlignment.JUSTIFY
+                        && width != -1) {
+                        int preferredWidth = component.getPreferredWidth(-1);
+
+                        if (width > totalSpacing
+                            && preferredWidth > totalSpacing) {
+                            double widthScale = (double)preferredWidth
+                                / (double)totalPreferredWidth;
+
+                            componentWidth = (int)Math.round((double)(width
+                                - totalSpacing) * widthScale);
+                        }
+                    }
+
+                    maxComponentHeight = Math.max(maxComponentHeight,
+                        component.getPreferredHeight(componentWidth));
+                }
+            }
+
+            preferredHeight += maxComponentHeight;
+        }
+
+        // Include top and bottom padding values
+        preferredHeight += padding.top + padding.bottom;
+
+        return preferredHeight;
+    }
+
+    public Dimensions getPreferredSize() {
+        // TODO Optimize by performing calculations here?
+        return new Dimensions(getPreferredWidth(-1), getPreferredHeight(-1));
+    }
+
+    public void layout() {
+        FlowPane flowPane = (FlowPane)getComponent();
+        int n = flowPane.getLength();
+
+        int width = getWidth();
+        int height = getHeight();
+
+        Orientation orientation = flowPane.getOrientation();
+        if (orientation == Orientation.HORIZONTAL) {
+            int preferredWidth = getPreferredWidth(height);
+
+            // Determine the fixed width (used in scaling components
+            // when justified horizontally)
+            int fixedWidth = 0;
+            if (horizontalAlignment == HorizontalAlignment.JUSTIFY) {
+                fixedWidth = padding.left + padding.right;
+
+                int displayableComponentCount = 0;
+
+                for (int i = 0; i < n; i++) {
+                    Component component = flowPane.get(i);
+
+                    if (component.isDisplayable()) {
+                        displayableComponentCount++;
+                    }
+                }
+
+                if (displayableComponentCount > 1) {
+                    fixedWidth += spacing * (displayableComponentCount - 1);
+                }
+            }
+
+            // Determine the starting x-coordinate
+            int componentX = 0;
+
+            switch (horizontalAlignment) {
+                case CENTER: {
+                    componentX = (int)Math.round((double)(width - preferredWidth) / 2);
+                    break;
+                }
+
+                case RIGHT: {
+                    componentX = width - preferredWidth;
+                    break;
+                }
+            }
+
+            componentX += padding.left;
+
+            // Lay out the components
+            for (int i = 0; i < n; i++) {
+                Component component = flowPane.get(i);
+
+                if (component.isDisplayable()) {
+                    int componentWidth = 0;
+                    int componentHeight = 0;
+                    int componentY = 0;
+
+                    // If the contents are horizontally justified, scale the
+                    // component's width to match the available space
+                    if (horizontalAlignment == HorizontalAlignment.JUSTIFY) {
+                        if (width > fixedWidth
+                            && preferredWidth > fixedWidth) {
+                            double widthScale = ((double)(width - fixedWidth)
+                                / (double)(preferredWidth - fixedWidth));
+
+                            componentWidth = (int)Math.max(Math.round((double)component.getPreferredWidth(-1)
+                                * widthScale), 0);
+
+                            if (verticalAlignment == VerticalAlignment.JUSTIFY) {
+                                componentY = padding.top;
+                                componentHeight = Math.max(height - (padding.top
+                                    + padding.bottom), 0);
+                            } else {
+                                componentHeight = component.getPreferredHeight(componentWidth);
+                            }
+                        }
+                    } else {
+                        if (verticalAlignment == VerticalAlignment.JUSTIFY) {
+                            componentY = padding.top;
+                            componentHeight = Math.max(height - (padding.top
+                                + padding.bottom), 0);
+                            componentWidth = component.getPreferredWidth(componentHeight);
+                        } else {
+                            Dimensions preferredComponentSize = component.getPreferredSize();
+                            componentWidth = preferredComponentSize.width;
+                            componentHeight = preferredComponentSize.height;
+                        }
+                    }
+
+                    switch (verticalAlignment) {
+                        case TOP: {
+                            componentY = padding.top;
+                            break;
+                        }
+
+                        case CENTER: {
+                            componentY = (int)Math.round((double)(height - componentHeight) / 2);
+                            break;
+                        }
+
+                        case BOTTOM: {
+                            componentY = height - padding.bottom
+                                - componentHeight;
+                            break;
+                        }
+                    }
+
+                    // Set the component's size and position
+                    component.setSize(componentWidth, componentHeight);
+                    component.setLocation(componentX, componentY);
+
+                    // Ensure that the component is visible
+                    component.setVisible(true);
+
+                    // Increment the x-coordinate
+                    componentX += componentWidth + spacing;
+                } else {
+                    // Hide the component
+                    component.setVisible(false);
+                }
+            }
+        } else {
+            int preferredHeight = getPreferredHeight(width);
+
+            // Determine the fixed height (used in scaling components
+            // when justified vertically)
+            int fixedHeight = 0;
+            if (verticalAlignment == VerticalAlignment.JUSTIFY) {
+                fixedHeight = padding.top + padding.bottom;
+
+                int displayableComponentCount = 0;
+
+                for (int i = 0; i < n; i++) {
+                    Component component = flowPane.get(i);
+
+                    if (component.isDisplayable()) {
+                        displayableComponentCount++;
+                    }
+                }
+
+                if (displayableComponentCount > 1) {
+                    fixedHeight += spacing * (displayableComponentCount - 1);
+                }
+            }
+
+            // Determine the starting y-coordinate
+            int componentY = 0;
+
+            switch (verticalAlignment) {
+                case CENTER: {
+                    componentY = (int)Math.round((double)(height - preferredHeight) / 2);
+                    break;
+                }
+
+                case BOTTOM: {
+                    componentY = height - preferredHeight;
+                    break;
+                }
+            }
+
+            componentY += padding.top;
+
+            // Lay out the components
+            for (int i = 0; i < n; i++) {
+                Component component = flowPane.get(i);
+
+                if (component.isDisplayable()) {
+                    int componentWidth = 0;
+                    int componentHeight = 0;
+                    int componentX = 0;
+
+                    if (horizontalAlignment == HorizontalAlignment.JUSTIFY) {
+                        componentX = padding.left;
+                        componentWidth = Math.max(width - (padding.left
+                            + padding.right), 0);
+                        componentHeight = component.getPreferredHeight(componentWidth);
+                    } else {
+                    }
+
+                    // If the contents are vertically justified, scale the
+                    // component's height to match the available space
+                    if (verticalAlignment == VerticalAlignment.JUSTIFY) {
+                        if (height > fixedHeight
+                            && preferredHeight > fixedHeight) {
+                            double heightScale = (double)(height - fixedHeight)
+                                / (double)(preferredHeight - fixedHeight);
+
+                            componentHeight = (int)Math.max(Math.round((double)component.getPreferredHeight(-1)
+                                * heightScale), 0);
+
+                            if (horizontalAlignment == HorizontalAlignment.JUSTIFY) {
+                                componentX = padding.left;
+                                componentWidth = Math.max(width - (padding.left
+                                    + padding.right), 0);
+                            } else {
+                                componentWidth = component.getPreferredWidth(componentHeight);
+                            }
+                        }
+                    } else {
+                        if (horizontalAlignment == HorizontalAlignment.JUSTIFY) {
+                            componentX = padding.left;
+                            componentWidth = Math.max(width - (padding.left
+                                + padding.right), 0);
+                            componentHeight = component.getPreferredHeight(componentWidth);
+                        } else {
+                            Dimensions preferredComponentSize = component.getPreferredSize();
+                            componentWidth = preferredComponentSize.width;
+                            componentHeight = preferredComponentSize.height;
+                        }
+                    }
+
+                    switch (horizontalAlignment) {
+                        case LEFT: {
+                            componentX = padding.left;
+                            break;
+                        }
+
+                        case CENTER: {
+                            componentX = (int)Math.round((double)(width - componentWidth) / 2);
+                            break;
+                        }
+
+                        case RIGHT: {
+                            componentX = width - padding.right
+                                - componentWidth;
+                            break;
+                        }
+                    }
+
+                    // Set the component's size and position
+                    component.setSize(componentWidth, componentHeight);
+                    component.setLocation(componentX, componentY);
+
+                    // Ensure that the component is visible
+                    component.setVisible(true);
+
+                    // Increment the y-coordinate
+                    componentY += componentHeight + spacing;
+                } else {
+                    // Hide the component
+                    component.setVisible(false);
+                }
+            }
+        }
+    }
+
+    public HorizontalAlignment getHorizontalAlignment() {
+        return horizontalAlignment;
+    }
+
+    public void setHorizontalAlignment(HorizontalAlignment horizontalAlignment) {
+        if (horizontalAlignment == null) {
+            throw new IllegalArgumentException("horizontalAlignment is null.");
+        }
+
+        this.horizontalAlignment = horizontalAlignment;
+        invalidateComponent();
+    }
+
+    public final void setHorizontalAlignment(String horizontalAlignment) {
+        if (horizontalAlignment == null) {
+            throw new IllegalArgumentException("horizontalAlignment is null.");
+        }
+
+        setHorizontalAlignment(HorizontalAlignment.decode(horizontalAlignment));
+    }
+
+    public VerticalAlignment getVerticalAlignment() {
+        return verticalAlignment;
+    }
+
+    public void setVerticalAlignment(VerticalAlignment verticalAlignment) {
+        if (verticalAlignment == null) {
+            throw new IllegalArgumentException("verticalAlignment is null.");
+        }
+
+        this.verticalAlignment = verticalAlignment;
+        invalidateComponent();
+    }
+
+    public final void setVerticalAlignment(String verticalAlignment) {
+        if (verticalAlignment == null) {
+            throw new IllegalArgumentException("verticalAlignment is null.");
+        }
+
+        setVerticalAlignment(VerticalAlignment.decode(verticalAlignment));
+    }
+
+    public Insets getPadding() {
+        return padding;
+    }
+
+    public void setPadding(Insets padding) {
+        if (padding == null) {
+            throw new IllegalArgumentException("padding is null.");
+        }
+
+        this.padding = padding;
+        invalidateComponent();
+    }
+
+    public final void setPadding(Dictionary<String, ?> padding) {
+        if (padding == null) {
+            throw new IllegalArgumentException("padding is null.");
+        }
+
+        setPadding(new Insets(padding));
+    }
+
+    public final void setPadding(int padding) {
+        setPadding(new Insets(padding));
+    }
+
+    public final void setPadding(Number padding) {
+        if (padding == null) {
+            throw new IllegalArgumentException("padding is null.");
+        }
+
+        setPadding(padding.intValue());
+    }
+
+    public int getSpacing() {
+        return spacing;
+    }
+
+    public void setSpacing(int spacing) {
+        this.spacing = spacing;
+        invalidateComponent();
+    }
+
+    public final void setSpacing(Number spacing) {
+        if (spacing == null) {
+            throw new IllegalArgumentException("spacing is null.");
+        }
+
+        setSpacing(spacing.intValue());
+    }
+
+    // Flow pane events
+    public void orientationChanged(FlowPane flowPane) {
+        invalidateComponent();
+    }
+}