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/26 00:12:17 UTC

svn commit: r758461 [30/47] - in /incubator/pivot/branches: ./ 1.1/ 1.1/charts-test/ 1.1/charts-test/src/ 1.1/charts-test/src/pivot/ 1.1/charts-test/src/pivot/charts/ 1.1/charts-test/src/pivot/charts/test/ 1.1/charts/ 1.1/charts/lib/ 1.1/charts/src/ 1....

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quadratic.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quadratic.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quadratic.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quadratic.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003 Robert Penner, all rights reserved.
+ *
+ * This work is subject to the terms in
+ * http://www.robertpenner.com/easing_terms_of_use.html.
+ *
+ * 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.effects.easing;
+
+/**
+ * Quadratic easing operation.
+ *
+ * @author Robert Penner
+ * @author gbrown
+ */
+public class Quadratic implements Easing {
+    public float easeIn(float time, float begin, float change, float duration) {
+        return change * (time /= duration) * time + begin;
+    }
+
+    public float easeOut(float time, float begin, float change, float duration) {
+        return -change * (time /= duration) * (time - 2) + begin;
+    }
+
+    public float easeInOut(float time, float begin, float change, float duration) {
+        if ((time /= duration / 2) < 1) {
+            return change / 2 * time * time + begin;
+        } else {
+            return -change / 2 * ((--time) * (time - 2) - 1) + begin;
+        }
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quartic.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quartic.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quartic.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quartic.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003 Robert Penner, all rights reserved.
+ *
+ * This work is subject to the terms in
+ * http://www.robertpenner.com/easing_terms_of_use.html.
+ *
+ * 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.effects.easing;
+
+/**
+ * Quartic easing operation.
+ *
+ * @author Robert Penner
+ * @author gbrown
+ */
+public class Quartic implements Easing {
+    public float easeIn(float time, float begin, float change, float duration) {
+        return change * (time /= duration) * time * time * time + begin;
+    }
+
+    public float easeOut(float time, float begin, float change, float duration) {
+        return -change * ((time = time / duration - 1) * time * time * time - 1) + begin;
+    }
+
+    public float easeInOut(float time, float begin, float change, float duration) {
+        if ((time /= duration / 2f) < 1) {
+            return change / 2f * time * time * time * time + begin;
+        } else {
+            return -change / 2f * ((time -= 2) * time * time * time - 2) + begin;
+        }
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quintic.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quintic.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quintic.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Quintic.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2003 Robert Penner, all rights reserved.
+ *
+ * This work is subject to the terms in
+ * http://www.robertpenner.com/easing_terms_of_use.html.
+ *
+ * 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.effects.easing;
+
+/**
+ * Quintic easing operation.
+ *
+ * @author Robert Penner
+ * @author gbrown
+ */
+public class Quintic implements Easing {
+    public float easeIn(float time, float begin, float change, float duration) {
+        return change * (time /= duration) * time * time * time * time + begin;
+    }
+
+    public float easeOut(float time, float begin, float change, float duration) {
+        return change * ((time = time / duration - 1) * time * time * time * time + 1) + begin;
+    }
+
+    public float easeInOut(float time, float begin, float change, float duration) {
+        if ((time /= duration / 2f) < 1) {
+            return change / 2f * time * time * time * time * time + begin;
+        } else {
+            return change / 2f * ((time -= 2) * time * time * time * time + 2) + begin;
+        }
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Sine.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Sine.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Sine.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/Sine.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003 Robert Penner, all rights reserved.
+ *
+ * This work is subject to the terms in
+ * http://www.robertpenner.com/easing_terms_of_use.html.
+ *
+ * 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.effects.easing;
+
+/**
+ * Easing operation based on a sine curve.
+ *
+ * @author Robert Penner
+ * @author gbrown
+ */
+public class Sine {
+    public float easeIn(float time, float begin, float change, float duration) {
+        return -change * (float)Math.cos(time / duration * (Math.PI/2)) + change + begin;
+    }
+
+    public float easeOut(float time, float begin, float change, float duration) {
+        return change * (float)Math.sin(time / duration * (Math.PI/2)) + begin;
+    }
+
+    public float easeInOut(float time, float begin, float change, float duration) {
+        return -change / 2f * (float)(Math.cos(Math.PI * time / duration) - 1) + begin;
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/package.html?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/package.html (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/easing/package.html Wed Mar 25 23:08:38 2009
@@ -0,0 +1,6 @@
+<html>
+<head></head>
+<body>
+<p>Contains "easing" operations for producing natural-looking transitions. Based on easing equations developed by <a href="http://robertpenner.com/">Robert Penner</a>.</p>
+</body>
+</html>

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/package.html?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/package.html (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/effects/package.html Wed Mar 25 23:08:38 2009
@@ -0,0 +1,6 @@
+<html>
+<head></head>
+<body>
+<p>Contains classes supporting visual effects such as blurs, reflections, and drop shadows.</p>
+</body>
+</html>

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/BufferedImageSerializer.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/BufferedImageSerializer.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/BufferedImageSerializer.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/BufferedImageSerializer.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,128 @@
+/*
+ * 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;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.imageio.ImageIO;
+
+import pivot.serialization.SerializationException;
+import pivot.serialization.Serializer;
+
+/**
+ * Implementation of the {@link Serializer} interface that reads and writes
+ * instances of {@link java.awt.image.BufferedImage}.
+ *
+ * @author tvolkert
+ */
+public class BufferedImageSerializer implements Serializer<BufferedImage> {
+    /**
+     * Supported image formats.
+     *
+     * @author tvolkert
+     */
+    public static enum Format {
+        PNG("png", "image/png"),
+        JPEG("jpeg", "image/jpeg"),
+        BMP("bmp", "image/bmp"),
+        WBMP("wbmp", "image/vnd.wap.wbmp"),
+        GIF("gif", "image/gif");
+
+        private String name;
+        private String mimeType;
+
+        private Format(String name, String mimeType) {
+            this.name = name;
+            this.mimeType = mimeType;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getMIMEType() {
+            return mimeType;
+        }
+    }
+
+    private Format outputFormat;
+
+    public BufferedImageSerializer() {
+        this(Format.PNG);
+    }
+
+    public BufferedImageSerializer(Format outputFormat) {
+        setOutputFormat(outputFormat);
+    }
+
+    /**
+     * Gets the image format that this serializer is using for output.
+     */
+    public Format getOutputFormat() {
+        return outputFormat;
+    }
+
+    /**
+     * Sets the image format that this serializer should use for output.
+     */
+    public void setOutputFormat(Format outputFormat) {
+        if (outputFormat == null) {
+            throw new IllegalArgumentException("Output format is null.");
+        }
+
+        this.outputFormat = outputFormat;
+    }
+
+    /**
+     * Reads a serialized image from an input stream.
+     *
+     * @return
+     * A <tt>BufferedImage</tt> object
+     */
+    public BufferedImage readObject(InputStream inputStream) throws IOException,
+        SerializationException {
+        if (inputStream == null) {
+            throw new IllegalArgumentException("inputStream is null.");
+        }
+
+        BufferedImage bufferedImage = ImageIO.read(inputStream);
+        return bufferedImage;
+    }
+
+
+    /**
+     * Writes a buffered image to an output stream.
+     */
+    public void writeObject(BufferedImage bufferedImage, OutputStream outputStream)
+        throws IOException, SerializationException {
+        if (bufferedImage == null) {
+            throw new IllegalArgumentException("bufferedImage is null.");
+        }
+
+        if (outputStream == null) {
+            throw new IllegalArgumentException("outputStream is null.");
+        }
+
+        ImageIO.write(bufferedImage, outputFormat.getName(), outputStream);
+    }
+
+    public String getMIMEType(BufferedImage bufferedImage) {
+        return outputFormat.getMIMEType();
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Drawing.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Drawing.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Drawing.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Drawing.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+import java.awt.Graphics2D;
+import pivot.wtk.Bounds;
+import pivot.wtk.media.drawing.Group;
+
+/**
+ * Image representing a vector drawing.
+ *
+ * @author gbrown
+ */
+public class Drawing extends Image {
+    private Group shapes = new Group();
+
+    public int getWidth() {
+        Bounds bounds = shapes.getBounds();
+        return bounds.width + bounds.x;
+    }
+
+    public int getHeight() {
+        Bounds bounds = shapes.getBounds();
+        return bounds.height + bounds.y;
+    }
+
+    public void paint(Graphics2D graphics) {
+        graphics.clipRect(0, 0, getWidth(), getHeight());
+        shapes.paint(graphics);
+    }
+
+    public Group getShapes() {
+        return shapes;
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Image.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Image.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Image.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Image.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+import java.awt.image.BufferedImage;
+import java.io.BufferedInputStream;
+import java.io.InputStream;
+import java.net.URL;
+
+import pivot.io.IOTask;
+import pivot.util.concurrent.Dispatcher;
+import pivot.util.concurrent.TaskListener;
+import pivot.util.concurrent.TaskExecutionException;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Visual;
+
+/**
+ * Abstract base class for images. An image is either a bitmapped "picture"
+ * or a vector "drawing".
+ *
+ * @author gbrown
+ */
+public abstract class Image implements Visual {
+    /**
+     * Task that executes an image load operation.
+     *
+     * @author gbrown
+     */
+    public static class LoadTask extends IOTask<Image> {
+        private URL url = null;
+
+        private static Dispatcher DEFAULT_DISPATCHER = new Dispatcher();
+
+        public LoadTask(URL url) {
+            this(url, DEFAULT_DISPATCHER);
+        }
+
+        public LoadTask(URL url, Dispatcher dispatcher) {
+            super(dispatcher);
+            this.url = url;
+        }
+
+        @Override
+        public Image execute() throws TaskExecutionException {
+            Image image = null;
+
+            try {
+                InputStream inputStream = null;
+
+                try {
+                    // NOTE We don't open the stream until the callback
+                    // executes because this is a potentially time-consuming
+                    // operation
+                    inputStream = new BufferedInputStream(url.openStream());
+
+                    // TODO Need a way to identify the type of image to load
+                    // (picture or drawing) - an argument/property may be
+                    // appropriate. If the attribute is optional, we can try to
+                    // determine the type from the file extension in the URL, or
+                    // by looking at the first few bytes of the input stream.
+
+                    BufferedImageSerializer serializer = new BufferedImageSerializer();
+                    BufferedImage bufferedImage =
+                        serializer.readObject(new MonitoredInputStream(inputStream));
+                    image = new Picture(bufferedImage);
+                } finally {
+                    if (inputStream != null) {
+                        inputStream.close();
+                    }
+                }
+            } catch(Exception exception) {
+                throw new TaskExecutionException(exception);
+            }
+
+            return image;
+        }
+    }
+
+    public Dimensions getSize() {
+        return new Dimensions(getWidth(), getHeight());
+    }
+
+    public static Image load(URL url) {
+        LoadTask loadTask = new LoadTask(url);
+
+        Image image = null;
+        try {
+            image = loadTask.execute();
+        } catch(TaskExecutionException exception) {
+            throw new RuntimeException(exception);
+        }
+
+        return image;
+    }
+
+    public static Image.LoadTask load(URL url, TaskListener<Image> loadListener) {
+        LoadTask loadTask = new LoadTask(url);
+        loadTask.execute(loadListener);
+        return loadTask;
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Picture.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Picture.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Picture.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/Picture.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,52 @@
+/*
+ * 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;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+
+/**
+ * Image representing a bitmapped picture.
+ *
+ * @author gbrown
+ */
+public class Picture extends Image {
+    private BufferedImage bufferedImage = null;
+
+    public Picture(BufferedImage bufferedImage) {
+        if (bufferedImage == null) {
+            throw new IllegalArgumentException("bufferedImage is null.");
+        }
+
+        this.bufferedImage = bufferedImage;
+    }
+
+    public int getWidth() {
+        return bufferedImage.getWidth();
+    }
+
+    public int getHeight() {
+        return bufferedImage.getHeight();
+    }
+
+    public void paint(Graphics2D graphics) {
+        graphics.drawImage(bufferedImage, 0, 0, null);
+    }
+
+    public BufferedImage getBufferedImage() {
+        return bufferedImage;
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Clone.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Clone.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Clone.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Clone.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,61 @@
+/*
+ * 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.Graphics2D;
+
+import pivot.wtk.Bounds;
+
+/**
+ * Shape representing a copy of another shape.
+ * <p>
+ * TODO Throw in setStroke() and setFill()?
+ */
+public class Clone extends Shape {
+    private Shape source = null;
+
+    public Shape getSource() {
+        return source;
+    }
+
+    public void setSource(Shape source) {
+        this.source = source;
+    }
+
+    @Override
+    public Bounds getUntransformedBounds() {
+        return (source == null) ? new Bounds(0, 0, 0, 0) : source.getUntransformedBounds();
+    }
+
+    @Override
+    public void fill(Graphics2D graphics) {
+        if (source != null) {
+            source.fill(graphics);
+        }
+    }
+
+    @Override
+    public void stroke(Graphics2D graphics) {
+        if (source != null) {
+            source.stroke(graphics);
+        }
+    }
+
+    @Override
+    public boolean contains(int x, int y) {
+        return (source == null) ? false : source.contains(x, y);
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Group.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Group.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Group.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Group.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,134 @@
+/*
+ * 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.Graphics2D;
+import java.util.Iterator;
+
+import pivot.collections.ArrayList;
+import pivot.collections.Sequence;
+import pivot.util.ImmutableIterator;
+import pivot.wtk.Bounds;
+
+/**
+ * Shape representing a collection of other shapes.
+ * <p>
+ * TODO Throw in setStroke() and setFill()?
+ */
+public class Group extends Shape implements Sequence<Shape>, Iterable<Shape> {
+    private ArrayList<Shape> shapes = new ArrayList<Shape>();
+
+    public Bounds getUntransformedBounds() {
+        // TODO
+        return null;
+    }
+
+    public void paint(Graphics2D graphics) {
+        for (Shape shape : this) {
+            Graphics2D shapeGraphics = (Graphics2D)graphics.create();
+
+            // TODO Translate to origin, then apply transform to graphics
+
+            // TODO Only paint if shape bounds intersects clip bounds
+
+            shape.paint(shapeGraphics);
+            shapeGraphics.dispose();
+        }
+    }
+
+    public void fill(Graphics2D graphics) {
+        // No-op
+    }
+
+    public void stroke(Graphics2D graphics) {
+        // No-op
+    }
+
+    public int add(Shape shape) {
+        int index = shapes.getLength();
+        insert(shape, index);
+
+        return index;
+    }
+
+    public void insert(Shape shape, int index) {
+        shapes.insert(shape, index);
+
+        // TODO Set parent
+        // TODO Update bounds
+    }
+
+    public Shape update(int index, Shape shape) {
+        Shape previousShape = shapes.update(index, shape);
+
+        // TODO Set parent
+        // TODO Update bounds
+
+        return previousShape;
+    }
+
+    public int remove(Shape shape) {
+        int index = shapes.indexOf(shape);
+
+        if (index != -1) {
+            remove(index, 1);
+        }
+
+        return index;
+    }
+
+    public Sequence<Shape> remove(int index, int count) {
+        Sequence<Shape> removed = shapes.remove(index, count);
+
+        // TODO Clear parent
+        // TODO Update bounds
+
+        return removed;
+    }
+
+    public Shape get(int index) {
+        return shapes.get(index);
+    }
+
+    public int indexOf(Shape shape) {
+        return shapes.indexOf(shape);
+    }
+
+    public int getLength() {
+        return shapes.getLength();
+    }
+
+    @Override
+    public boolean contains(int x, int y) {
+        // TODO
+        return false;
+    }
+
+    public Shape getShapeAt(int x, int y) {
+        // TODO Walk shape list from top to bottom; if shape bounds contains
+        // x, y, call contains() on the shape
+        return null;
+    }
+
+    public Shape getDescendantAt(int x, int y) {
+        // TODO Mirror behavior of Container#getDescendantAt()
+        return null;
+    }
+
+    public Iterator<Shape> iterator() {
+        return new ImmutableIterator<Shape>(shapes.iterator());
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rectangle.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rectangle.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rectangle.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rectangle.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,93 @@
+/*
+ * 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.Graphics2D;
+
+import pivot.wtk.Bounds;
+import pivot.wtk.Dimensions;
+
+/**
+ * Shape representing a rectangle.
+ *
+ * @author gbrown
+ */
+public class Rectangle extends Shape {
+    private int width = 0;
+    private int height = 0;
+
+    public int getWidth() {
+        return width;
+    }
+
+    public void setWidth(int width) {
+        if (width < 0) {
+            throw new IllegalArgumentException("width is null.");
+        }
+
+        this.width = width;
+    }
+
+    public int getHeight() {
+        return height;
+    }
+
+    public void setHeight(int height) {
+        if (height < 0) {
+            throw new IllegalArgumentException("height is null.");
+        }
+
+        this.height = height;
+    }
+
+    public Dimensions getSize() {
+        return new Dimensions(getWidth(), getHeight());
+    }
+
+    public void setSize(int width, int height) {
+        setWidth(width);
+        setHeight(height);
+    }
+
+    public void setSize(Dimensions size) {
+        if (size == null) {
+            throw new IllegalArgumentException("size is null.");
+        }
+
+        setSize(size.width, size.height);
+    }
+
+    @Override
+    public Bounds getUntransformedBounds() {
+        return new Bounds(getX(), getY(), width, height);
+    }
+
+    @Override
+    public void fill(Graphics2D graphics) {
+        graphics.fillRect(getX(), getY(), width, height);
+    }
+
+    @Override
+    public void stroke(Graphics2D graphics) {
+        graphics.drawRect(getX(), getY(), width, height);
+    }
+
+    @Override
+    public boolean contains(int x, int y) {
+        // TODO
+        return false;
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rotation.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rotation.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rotation.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Rotation.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,38 @@
+/*
+ * 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 rotation.
+ * <p>
+ * TODO Allow caller to specify angle in degrees or radians.
+ */
+public class Rotation extends Transform {
+    private float angle = 0f;
+
+    public float getAngle() {
+        return angle;
+    }
+
+    public void setAngle(float angle) {
+        this.angle = angle;
+    }
+
+    public float[][] getMatrix() {
+        // TODO
+        return null;
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Scale.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Scale.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Scale.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Scale.java Wed Mar 25 23:08:38 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/branches/1.1/wtk/src/pivot/wtk/media/drawing/Shape.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Shape.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Shape.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Shape.java Wed Mar 25 23:08:38 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/branches/1.1/wtk/src/pivot/wtk/media/drawing/Text.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Text.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Text.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Text.java Wed Mar 25 23:08:38 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/branches/1.1/wtk/src/pivot/wtk/media/drawing/Transform.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Transform.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Transform.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Transform.java Wed Mar 25 23:08:38 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/branches/1.1/wtk/src/pivot/wtk/media/drawing/Translation.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Translation.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Translation.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/Translation.java Wed Mar 25 23:08:38 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/branches/1.1/wtk/src/pivot/wtk/media/drawing/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/package.html?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/package.html (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/drawing/package.html Wed Mar 25 23:08:38 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/branches/1.1/wtk/src/pivot/wtk/media/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/package.html?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/package.html (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/media/package.html Wed Mar 25 23:08:38 2009
@@ -0,0 +1,6 @@
+<html>
+<head></head>
+<body>
+<p>Contains classes that provide multimedia support.</p>
+</body>
+</html>

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/package.html
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/package.html?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/package.html (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/package.html Wed Mar 25 23:08:38 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/branches/1.1/wtk/src/pivot/wtk/skin/BorderSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/BorderSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/BorderSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/BorderSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,414 @@
+/*
+ * 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.Platform;
+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()) {
+                graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+                    Platform.getTextAntialiasingHint());
+            }
+
+            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/branches/1.1/wtk/src/pivot/wtk/skin/ButtonSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/ButtonSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/ButtonSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/ButtonSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,138 @@
+/*
+ * 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.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 void stateChanged(Button button, Button.State previousState) {
+        repaintComponent();
+    }
+
+    // Button press events
+    public void buttonPressed(Button button) {
+        // No-op
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarButtonSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarButtonSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarButtonSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarButtonSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,393 @@
+/*
+ * 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.util.Locale;
+
+import pivot.util.CalendarDate;
+import pivot.util.Vote;
+import pivot.wtk.Button;
+import pivot.wtk.Calendar;
+import pivot.wtk.CalendarButton;
+import pivot.wtk.CalendarButtonListener;
+import pivot.wtk.CalendarButtonSelectionListener;
+import pivot.wtk.Component;
+import pivot.wtk.ComponentKeyListener;
+import pivot.wtk.ComponentMouseButtonListener;
+import pivot.wtk.Container;
+import pivot.wtk.ContainerMouseListener;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Direction;
+import pivot.wtk.Display;
+import pivot.wtk.Keyboard;
+import pivot.wtk.Mouse;
+import pivot.wtk.Point;
+import pivot.wtk.Window;
+import pivot.wtk.WindowStateListener;
+
+/**
+ * Abstract base class for calendar button skins.
+ * <p>
+ * TODO Rather than blindly closing when a mouse down is received, we could
+ * instead cache the selection state in the popup's container mouse down event
+ * and compare it to the current state in component mouse down. If different,
+ * we close the popup. This would also tie this base class less tightly to its
+ * concrete subclasses.
+ *
+ * @author gbrown
+ */
+public abstract class CalendarButtonSkin extends ButtonSkin
+    implements CalendarButtonListener, CalendarButtonSelectionListener {
+    protected Calendar calendar;
+    protected Window calendarPopup;
+
+    protected boolean pressed = false;
+
+    private ComponentMouseButtonListener calendarPopupMouseButtonListener = new ComponentMouseButtonListener() {
+        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 boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+            CalendarButton calendarButton = (CalendarButton)getComponent();
+
+            CalendarDate date = calendar.getSelectedDate();
+            calendarButton.setSelectedDate(date);
+
+            calendarPopup.close();
+            getComponent().requestFocus();
+
+            return true;
+        }
+    };
+
+    private ComponentKeyListener calendarPopupKeyListener = new ComponentKeyListener() {
+        public boolean keyTyped(Component component, char character) {
+            return false;
+        }
+
+        public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+            switch (keyCode) {
+                case Keyboard.KeyCode.ESCAPE: {
+                    calendarPopup.close();
+                    getComponent().requestFocus();
+                    break;
+                }
+
+                case Keyboard.KeyCode.TAB:
+                case Keyboard.KeyCode.ENTER: {
+                    CalendarButton calendarButton = (CalendarButton)getComponent();
+
+                    CalendarDate date = calendar.getSelectedDate();
+
+                    calendar.setSelectedDate((CalendarDate)null);
+                    calendarButton.setSelectedDate(date);
+
+                    calendarPopup.close();
+
+                    if (keyCode == Keyboard.KeyCode.TAB) {
+                        Direction direction = (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) ?
+                            Direction.BACKWARD : Direction.FORWARD;
+                        calendarButton.transferFocus(direction);
+                    } else {
+                        calendarButton.requestFocus();
+                    }
+
+                    break;
+                }
+            }
+
+            return false;
+        }
+
+        public boolean keyReleased(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+            return false;
+        }
+    };
+
+    private WindowStateListener calendarPopupWindowStateListener = new WindowStateListener() {
+        public Vote previewWindowOpen(Window window, Display display) {
+            return Vote.APPROVE;
+        }
+
+        public void windowOpenVetoed(Window window, Vote reason) {
+            // No-op
+        }
+
+        public void windowOpened(Window window) {
+            Display display = window.getDisplay();
+            display.getContainerMouseListeners().add(displayMouseListener);
+        }
+
+        public Vote previewWindowClose(Window window) {
+            return Vote.APPROVE;
+        }
+
+        public void windowCloseVetoed(Window window, Vote reason) {
+            // No-op
+        }
+
+        public void windowClosed(Window window, Display display) {
+            display.getContainerMouseListeners().remove(displayMouseListener);
+        }
+    };
+
+    private ContainerMouseListener displayMouseListener = new ContainerMouseListener() {
+        public boolean mouseMove(Container container, int x, int y) {
+            return false;
+        }
+
+        public boolean mouseDown(Container container, Mouse.Button button, int x, int y) {
+            Display display = (Display)container;
+            Component descendant = display.getDescendantAt(x, y);
+
+            if (!calendarPopup.isAncestor(descendant)
+                && descendant != CalendarButtonSkin.this.getComponent()) {
+                calendarPopup.close();
+            }
+
+            return false;
+        }
+
+        public boolean mouseUp(Container container, Mouse.Button button, int x, int y) {
+            return false;
+        }
+
+        public boolean mouseWheel(Container container, Mouse.ScrollType scrollType,
+            int scrollAmount, int wheelRotation, int x, int y) {
+            boolean consumed = false;
+
+            Display display = (Display)container;
+            Window window = (Window)display.getComponentAt(x, y);
+
+            if (window != calendarPopup) {
+                consumed = true;
+            }
+
+            return consumed;
+        }
+    };
+
+    public CalendarButtonSkin() {
+        calendar = new Calendar();
+
+        calendarPopup = new Window(true);
+        calendarPopup.getComponentMouseButtonListeners().add(calendarPopupMouseButtonListener);
+        calendarPopup.getComponentKeyListeners().add(calendarPopupKeyListener);
+        calendarPopup.getWindowStateListeners().add(calendarPopupWindowStateListener);
+    }
+
+    @Override
+    public void install(Component component) {
+        super.install(component);
+
+        CalendarButton calendarButton = (CalendarButton)component;
+        calendarButton.getCalendarButtonListeners().add(this);
+        calendarButton.getCalendarButtonSelectionListeners().add(this);
+
+        calendar.setLocale(calendarButton.getLocale());
+    }
+
+    @Override
+    public void uninstall() {
+        calendarPopup.close();
+
+        CalendarButton calendarButton = (CalendarButton)getComponent();
+        calendarButton.getCalendarButtonListeners().remove(this);
+        calendarButton.getCalendarButtonSelectionListeners().remove(this);
+
+        calendar.setLocale(Locale.getDefault());
+
+        super.uninstall();
+    }
+
+    // Component state events
+    @Override
+    public void enabledChanged(Component component) {
+        super.enabledChanged(component);
+
+        calendarPopup.close();
+        pressed = false;
+    }
+
+    @Override
+    public void focusedChanged(Component component, boolean temporary) {
+        super.focusedChanged(component, temporary);
+
+        // Close the popup if focus was transferred to a component whose
+        // window is not the popup
+        if (!component.isFocused()
+            && !calendarPopup.containsFocus()) {
+            calendarPopup.close();
+        }
+
+        pressed = false;
+    }
+
+    // Component mouse events
+    @Override
+    public void mouseOut(Component component) {
+        super.mouseOut(component);
+
+        pressed = false;
+    }
+
+    @Override
+    public boolean mouseDown(Component component, Mouse.Button button, int x, int y) {
+        boolean consumed = super.mouseDown(component, button, x, y);
+
+        pressed = true;
+        repaintComponent();
+
+        return consumed;
+    }
+
+    @Override
+    public boolean mouseUp(Component component, Mouse.Button button, int x, int y) {
+        boolean consumed = super.mouseUp(component, button, x, y);
+
+        pressed = false;
+        repaintComponent();
+
+        return consumed;
+    }
+
+    @Override
+    public boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
+        boolean consumed = super.mouseClick(component, button, x, y, count);
+
+        CalendarButton calendarButton = (CalendarButton)getComponent();
+
+        calendarButton.requestFocus();
+        calendarButton.press();
+
+        if (calendar.isShowing()) {
+            calendar.requestFocus();
+        }
+
+        return consumed;
+    }
+
+    @Override
+    public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+        boolean consumed = false;
+
+        if (keyCode == Keyboard.KeyCode.SPACE) {
+            pressed = true;
+            repaintComponent();
+            consumed = true;
+        } else {
+            consumed = super.keyPressed(component, keyCode, keyLocation);
+        }
+
+        return consumed;
+    }
+
+    @Override
+    public boolean keyReleased(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+        boolean consumed = false;
+
+        CalendarButton calendarButton = (CalendarButton)getComponent();
+
+        if (keyCode == Keyboard.KeyCode.SPACE) {
+            pressed = false;
+            repaintComponent();
+
+            calendarButton.press();
+        } else {
+            consumed = super.keyReleased(component, keyCode, keyLocation);
+        }
+
+        return consumed;
+    }
+
+    // Button events
+    @Override
+    public void buttonPressed(Button button) {
+        if (calendarPopup.isOpen()) {
+            calendarPopup.close();
+        } else {
+            CalendarButton calendarButton = (CalendarButton)button;
+
+            // Determine the popup's location and preferred size, relative
+            // to the button
+            Display display = calendarButton.getDisplay();
+
+            if (display != null) {
+                int width = getWidth();
+                int height = getHeight();
+
+                Component content = calendarPopup.getContent();
+
+                // Ensure that the popup remains within the bounds of the display
+                Point buttonLocation = calendarButton.mapPointToAncestor(display, 0, 0);
+
+                Dimensions displaySize = display.getSize();
+                Dimensions popupSize = content.getPreferredSize();
+
+                int x = buttonLocation.x;
+                if (popupSize.width > width
+                    && x + popupSize.width > displaySize.width) {
+                    x = buttonLocation.x + width - popupSize.width;
+                }
+
+                int y = buttonLocation.y + height - 1;
+                if (y + popupSize.height > displaySize.height) {
+                    if (buttonLocation.y - popupSize.height > 0) {
+                        y = buttonLocation.y - popupSize.height + 1;
+                    } else {
+                        popupSize.height = displaySize.height - y;
+                    }
+                } else {
+                    popupSize.height = -1;
+                }
+
+                calendarPopup.setLocation(x, y);
+                calendarPopup.setPreferredSize(popupSize);
+                calendarPopup.open(calendarButton.getWindow());
+
+                calendar.requestFocus();
+            }
+        }
+    }
+
+    // Calendar button events
+    public void selectedDateKeyChanged(CalendarButton calendarButton,
+        String previousSelectedDateKey) {
+        // No-op
+    }
+
+    public void localeChanged(CalendarButton calendarButton, Locale previousLocale) {
+        calendar.setLocale(calendarButton.getLocale());
+        invalidateComponent();
+    }
+
+    // Calendar button selection events
+    public void selectedDateChanged(CalendarButton calendarButton,
+        CalendarDate previousSelectedDate) {
+        // Set the selected date as the button data
+        CalendarDate date = calendarButton.getSelectedDate();
+        calendarButton.setButtonData(date);
+
+        calendar.setSelectedDate(date);
+        calendar.setYear(date.getYear());
+        calendar.setMonth(date.getMonth());
+    }
+}

Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/CalendarSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,76 @@
+/*
+ * 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.util.Locale;
+
+import pivot.util.CalendarDate;
+import pivot.wtk.Calendar;
+import pivot.wtk.CalendarListener;
+import pivot.wtk.CalendarSelectionListener;
+import pivot.wtk.Component;
+import pivot.wtk.skin.ContainerSkin;
+
+/**
+ * Abstract base class for calendar skins.
+ *
+ * @author gbrown
+ */
+public abstract class CalendarSkin extends ContainerSkin
+    implements CalendarListener, CalendarSelectionListener {
+    @Override
+    public void install(Component component) {
+        super.install(component);
+
+        Calendar calendar = (Calendar)component;
+        calendar.getCalendarListeners().add(this);
+        calendar.getCalendarSelectionListeners().add(this);
+    }
+
+    @Override
+    public void uninstall() {
+        Calendar calendar = (Calendar)getComponent();
+        calendar.getCalendarListeners().remove(this);
+        calendar.getCalendarSelectionListeners().remove(this);
+
+        super.uninstall();
+    }
+
+    // Calendar events
+
+    public void yearChanged(Calendar calendar, int previousYear) {
+        // No-op
+    }
+
+    public void monthChanged(Calendar calendar, int previousMonth) {
+        // No-op
+    }
+
+    public void selectedDateKeyChanged(Calendar calendar,
+        String previousSelectedDateKey) {
+        // No-op
+    }
+
+    public void localeChanged(Calendar calendar, Locale previousLocale) {
+        invalidateComponent();
+    }
+
+    // Calendar selection events
+
+    public void selectedDateChanged(Calendar calendar, CalendarDate previousSelectedDate) {
+        // No-op
+    }
+}