You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pivot.apache.org by gb...@apache.org on 2011/01/10 00:19:29 UTC
svn commit: r1057053 [8/12] - in /pivot/branches/3.x: ./ core/ core/src/
core/src/org/ core/src/org/apache/ core/src/org/apache/pivot/
core/src/org/apache/pivot/beans/ core/src/org/apache/pivot/bxml/
core/src/org/apache/pivot/csv/ core/src/org/apache/p...
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/Font.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/Font.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/Font.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/Font.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+import java.util.Map;
+
+import org.apache.pivot.beans.BeanAdapter;
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.json.JSONSerializer;
+
+/**
+ * Class representing a font.
+ */
+public class Font {
+ /**
+ * Class representing font metric information.
+ */
+ public static class Metrics {
+ public final float ascent;
+ public final float descent;
+ public final float leading;
+
+ public Metrics(float ascent, float descent, float leading) {
+ this.ascent = ascent;
+ this.descent = descent;
+ this.leading = leading;
+ }
+ }
+
+ public final String name;
+ public final int size;
+ public final boolean bold;
+ public final boolean italic;
+
+ private Object nativeFont = null;
+
+ public static final String NAME_KEY = "name";
+ public static final String SIZE_KEY = "size";
+ public static final String BOLD_KEY = "bold";
+ public static final String ITALIC_KEY = "italic";
+
+ public Font(String name, int size) {
+ this(name, size, false, false);
+ }
+
+ public Font(String name, int size, boolean bold, boolean italic) {
+ this.name = name;
+ this.size = size;
+ this.bold = bold;
+ this.italic = italic;
+ }
+
+ protected Object getNativeFont() {
+ if (nativeFont == null) {
+ nativeFont = Platform.getPlatform().getNativeFont(this);
+ }
+
+ return nativeFont;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean equals = false;
+
+ if (object instanceof Font) {
+ Font font = (Font)object;
+ equals = (name.equals(font.name)
+ && size == font.size
+ && bold == font.bold
+ && italic == font.italic);
+ }
+
+ return equals;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode() ^ size
+ + (bold ? 0x10 : 0x00)
+ + (italic ? 0x01 : 0x00);
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + " [" + name + " " + size
+ + (bold ? " bold" : "")
+ + (italic ? " italic" : "")
+ + "]";
+ }
+
+ public static Font decode(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+
+ Map<String, ?> map;
+ try {
+ map = JSONSerializer.parseMap(value);
+ } catch (SerializationException exception) {
+ throw new IllegalArgumentException(exception);
+ }
+
+ Font font = Platform.getPlatform().getDefaultFont();
+
+ String name = font.name;
+ if (map.containsKey(NAME_KEY)) {
+ name = BeanAdapter.get(map, NAME_KEY);
+ }
+
+ int size = font.size;
+ if (map.containsKey(SIZE_KEY)) {
+ Object sizeValue = BeanAdapter.get(map, SIZE_KEY);
+
+ if (sizeValue instanceof String) {
+ size = decodeSize(font, (String)sizeValue);
+ } else {
+ size = ((Number)sizeValue).intValue();
+ }
+ }
+
+ boolean bold = font.bold;
+ if (map.containsKey(BOLD_KEY)) {
+ bold = BeanAdapter.get(map, BOLD_KEY);
+ }
+
+ boolean italic = font.italic;
+ if (map.containsKey(ITALIC_KEY)) {
+ italic = BeanAdapter.get(map, ITALIC_KEY);
+ }
+
+ return new Font(name, size, bold, italic);
+ }
+
+ private static int decodeSize(Font font, String value) {
+ int size;
+
+ if (value.endsWith("%")) {
+ value = value.substring(0, value.length() - 1);
+ float percentage = Float.parseFloat(value) / 100f;
+ size = Math.round(font.size * percentage);
+ } else {
+ throw new IllegalArgumentException(value + " is not a valid font size.");
+ }
+
+ return size;
+ }
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/Graphics.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/Graphics.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/Graphics.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/Graphics.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+import org.apache.pivot.scene.media.Raster;
+
+/**
+ * Interface representing a drawing surface.
+ */
+public abstract class Graphics {
+ /**
+ * Enumeration representing a compositing operation.
+ */
+ public enum CompositeOperation {
+ SOURCE_ATOP,
+ SOURCE_IN,
+ SOURCE_OUT,
+ SOURCE_OVER,
+ DESTINATION_ATOP,
+ DESTINATION_IN,
+ DESTINATION_OUT,
+ DESTINATION_OVER,
+ CLEAR,
+ XOR
+ }
+
+ // Clipping
+ public void clip(Bounds bounds) {
+ clip(bounds.x, bounds.y, bounds.width, bounds.height);
+ }
+
+ public abstract void clip(int x, int y, int width, int height);
+ public abstract Bounds getClipBounds();
+
+ // Compositing
+ public abstract float getAlpha();
+ public abstract void setAlpha(float alpha);
+
+ public abstract CompositeOperation getCompositeOperation();
+ public abstract void setCompositeOperation(CompositeOperation compositeOperation);
+
+ // Anti-aliasing
+ public abstract boolean isAntiAliased();
+ public abstract void setAntiAliased(boolean antiAliased);
+
+ // Primitive drawing/filling
+ public abstract Stroke getStroke();
+ public abstract void setStroke(Stroke stroke);
+
+ public abstract Paint getPaint();
+ public abstract void setPaint(Paint paint);
+
+ public abstract void drawLine(float x1, float y1, float x2, float y2);
+
+ public abstract void drawRectangle(float x, float y, float width, float height, float cornerRadius);
+ public abstract void drawArc(float x, float y, float width, float height, float start, float extent);
+ public abstract void drawEllipse(float x, float y, float width, float height);
+ public abstract void drawPath(PathGeometry pathGeometry);
+
+ public abstract void fillRectangle(float x, float y, float width, float height, float cornerRadius);
+ public abstract void fillArc(float x, float y, float width, float height, float start, float extent);
+ public abstract void fillEllipse(float x, float y, float width, float height);
+ public abstract void fillPath(PathGeometry pathGeometry);
+
+ // Raster drawing
+ public void drawRaster(Raster raster, int x, int y) {
+ drawRaster(raster, x, y, raster.getWidth(), raster.getHeight());
+ }
+
+ public abstract void drawRaster(Raster raster, int x, int y, int width, int height);
+
+ // Blitting
+ public abstract void copyArea(int x, int y, int width, int height, int dx, int dy);
+
+ // Text
+ public abstract Font getFont();
+ public abstract void setFont(Font font);
+
+ public void drawText(CharSequence text, float x, float y) {
+ drawText(text, 0, text.length(), x, y);
+ }
+
+ public abstract void drawText(CharSequence text, int start, int length, float x, float y);
+
+ // Transformations
+ public void translate(float dx, float dy) {
+ // TODO
+ }
+
+ public void rotate(float theta) {
+ // TODO
+ }
+
+ public void rotate(float theta, float x, float y) {
+ // TODO
+ }
+
+ public void scale(float sx, float sy) {
+ // TODO
+ }
+
+ public void transform(Transform transform) {
+ transform(transform.m11, transform.m12, transform.m21, transform.m22, transform.dx, transform.dy);
+ }
+
+ public abstract void transform(float m11, float m12, float m21, float m22, float dx, float dy);
+ public abstract Transform getCurrentTransform();
+
+ // Creation/disposal
+ public abstract Graphics create();
+ public abstract void dispose();
+
+ public abstract Object getNativeGraphics();
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/Group.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/Group.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/Group.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/Group.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,1234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.pivot.bxml.DefaultProperty;
+import org.apache.pivot.scene.effect.Decorator;
+import org.apache.pivot.util.ListenerList;
+import org.apache.pivot.util.ObservableList;
+import org.apache.pivot.util.ObservableListAdapter;
+
+/**
+ * Container for a group of nodes. A group is primarily responsible for
+ * laying out its child nodes.
+ */
+@DefaultProperty("nodes")
+public class Group extends Node {
+ private class NodeList extends ObservableListAdapter<Node> {
+ public NodeList() {
+ super(new ArrayList<Node>());
+ }
+
+ @Override
+ public void add(int index, Node node) {
+ addNode(node);
+ invalidate();
+
+ super.add(node);
+ }
+
+ @Override
+ public boolean addAll(int index, Collection<? extends Node> nodes) {
+ for (Node node : nodes) {
+ addNode(node);
+ }
+
+ invalidate();
+
+ return super.addAll(index, nodes);
+ }
+
+ private void addNode(Node node) {
+ if (node == null) {
+ throw new IllegalArgumentException();
+ }
+
+ if (node.getGroup() != null) {
+ throw new IllegalArgumentException();
+ }
+
+ node.setGroup(Group.this);
+ repaint(node.getDecoratedBounds());
+ }
+
+ @Override
+ public Node remove(int index) {
+ removeNode(get(index));
+ invalidate();
+
+ return super.remove(index);
+ }
+
+ @Override
+ protected void removeRange(int fromIndex, int toIndex) {
+ for (int i = fromIndex; i < toIndex; i++) {
+ removeNode(get(i));
+ }
+
+ invalidate();
+
+ super.removeRange(fromIndex, toIndex);
+ }
+
+ private void removeNode(Node node) {
+ node.setGroup(null);
+ repaint(node.getDecoratedBounds());
+ }
+
+ @Override
+ public Node set(int index, Node node) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<Node> setAll(int index, Collection<? extends Node> nodes) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ private static class GroupListenerList extends ListenerList<GroupListener>
+ implements GroupListener {
+ @Override
+ public void preferredSizeChanged(Group group, int previousPreferredWidth,
+ int previousPreferredHeight) {
+ for (GroupListener listener : listeners()) {
+ listener.preferredSizeChanged(group, previousPreferredWidth, previousPreferredHeight);
+ }
+ }
+
+ @Override
+ public void widthLimitsChanged(Group group, int previousMinimumWidth,
+ int previousMaximumWidth) {
+ for (GroupListener listener : listeners()) {
+ listener.widthLimitsChanged(group, previousMinimumWidth, previousMaximumWidth);
+ }
+ }
+
+ @Override
+ public void heightLimitsChanged(Group group, int previousMinimumHeight,
+ int previousMaximumHeight) {
+ for (GroupListener listener : listeners()) {
+ listener.heightLimitsChanged(group, previousMinimumHeight, previousMaximumHeight);
+ }
+ }
+
+ @Override
+ public void layoutChanged(Group group, Layout previousLayout) {
+ for (GroupListener listener : listeners()) {
+ listener.layoutChanged(group, previousLayout);
+ }
+ }
+
+ @Override
+ public void focusTraversalPolicyChanged(Group group,
+ FocusTraversalPolicy previousFocusTraversalPolicy) {
+ for (GroupListener listener : listeners()) {
+ listener.focusTraversalPolicyChanged(group, previousFocusTraversalPolicy);
+ }
+ }
+ }
+
+ private static class GroupMouseListenerList extends ListenerList<GroupMouseListener>
+ implements GroupMouseListener {
+ @Override
+ public boolean mouseMoved(Group group, int x, int y, boolean captured) {
+ for (GroupMouseListener listener : listeners()) {
+ listener.mouseMoved(group, x, y, captured);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean mousePressed(Group group, Mouse.Button button, int x, int y) {
+ for (GroupMouseListener listener : listeners()) {
+ listener.mousePressed(group, button, x, y);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean mouseReleased(Group group, Mouse.Button button, int x, int y) {
+ for (GroupMouseListener listener : listeners()) {
+ listener.mouseReleased(group, button, x, y);
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean mouseWheelScrolled(Group group, Mouse.ScrollType scrollType,
+ int scrollAmount, int wheelRotation, int x, int y) {
+ for (GroupMouseListener listener : listeners()) {
+ listener.mouseWheelScrolled(group, scrollType, scrollAmount, wheelRotation, x, y);
+ }
+
+ return false;
+ }
+ }
+
+ private ObservableList<Node> nodes = new NodeList();
+
+ private Layout layout = null;
+ private FocusTraversalPolicy focusTraversalPolicy = null;
+
+ // Preferred width and height values explicitly set by the user
+ private int preferredWidth = -1;
+ private int preferredHeight = -1;
+
+ // Bounds on preferred size
+ private int minimumWidth = 0;
+ private int maximumWidth = Integer.MAX_VALUE;
+ private int minimumHeight = 0;
+ private int maximumHeight = Integer.MAX_VALUE;
+
+ // Calculated preferred size value
+ private Dimensions preferredSize = null;
+
+ // Calculated baseline for current size
+ private int baseline = -1;
+
+ private Node mouseOverNode = null;
+ private boolean mouseDown = false;
+ private Node mouseDownNode = null;
+ private long mouseDownTime = 0;
+ private int mouseClickCount = 0;
+ private boolean mouseClickConsumed = false;
+
+ // Listener lists
+ private GroupListenerList groupListeners = new GroupListenerList();
+ private GroupMouseListenerList groupMouseListeners = new GroupMouseListenerList();
+
+ public Group() {
+ this(null);
+ }
+
+ public Group(Layout layout) {
+ setLayout(layout);
+ }
+
+ /**
+ * Returns the list of this group's child nodes.
+ */
+ public ObservableList<Node> getNodes() {
+ return nodes;
+ }
+
+ @Override
+ protected void setGroup(Group group) {
+ // If this group is being removed from the node hierarchy
+ // and contains the focused node, clear the focus
+ if (group == null
+ && containsFocus()) {
+ clearFocus();
+ }
+
+ super.setGroup(group);
+ }
+
+ public Node getNodeAt(int x, int y) {
+ Node node = null;
+
+ int i = nodes.size() - 1;
+ while (i >= 0) {
+ node = nodes.get(i);
+ if (node.isVisible()) {
+ Bounds bounds = node.getBounds();
+ if (bounds.contains(x, y)) {
+ break;
+ }
+ }
+
+ i--;
+ }
+
+ if (i < 0) {
+ node = null;
+ }
+
+ return node;
+ }
+
+ public Node getDescendantAt(int x, int y) {
+ Node descendant = getNodeAt(x, y);
+
+ if (descendant instanceof Group) {
+ Group group = (Group)descendant;
+ descendant = group.getDescendantAt(x - group.getX(), y - group.getY());
+ }
+
+ if (descendant == null) {
+ descendant = this;
+ }
+
+ return descendant;
+ }
+
+ /**
+ * Tests if this group is an ancestor of a given node. A group
+ * is considered to be its own ancestor.
+ *
+ * @param node
+ * The node to test.
+ *
+ * @return
+ * <tt>true</tt> if this group is an ancestor of <tt>node</tt>;
+ * <tt>false</tt> otherwise.
+ */
+ public boolean isAncestor(Node node) {
+ boolean ancestor = false;
+
+ while (node != null) {
+ if (node == this) {
+ ancestor = true;
+ break;
+ }
+
+ node = node.getGroup();
+ }
+
+ return ancestor;
+ }
+
+ @Override
+ public void setVisible(boolean visible) {
+ if (!visible
+ && containsFocus()) {
+ clearFocus();
+ }
+
+ super.setVisible(visible);
+ }
+
+ /**
+ * Returns the layout the group uses to arrange its children.
+ */
+ public Layout getLayout() {
+ return layout;
+ }
+
+ /**
+ * Sets the layout the group uses to arrange its children.
+ *
+ * @param layout
+ * The layout the group will use to arrange its children, or <tt>null</tt>
+ * for no layout.
+ */
+ public void setLayout(Layout layout) {
+ Layout previousLayout = this.layout;
+ if (previousLayout != layout) {
+ this.layout = layout;
+ invalidate();
+
+ groupListeners.layoutChanged(this, previousLayout);
+ }
+ }
+
+ @Override
+ public Extents getExtents() {
+ int minimumX = 0;
+ int maximumX = 0;
+ int minimumY = 0;
+ int maximumY = 0;
+
+ for (int i = 0, n = nodes.size(); i < n; i++) {
+ Node node = nodes.get(i);
+
+ if (node.isVisible()) {
+ Extents extents = node.getExtents();
+
+ minimumX = Math.min(extents.minimumX, minimumX);
+ maximumX = Math.max(extents.maximumX, maximumX);
+ minimumY = Math.min(extents.minimumY, minimumY);
+ maximumY = Math.max(extents.maximumY, maximumY);
+ }
+ }
+
+ return new Extents(minimumX, maximumX, minimumY, maximumY);
+ }
+
+ @Override
+ public boolean contains(int x, int y) {
+ // TODO Find node at x, y and call contains() on it
+
+ // TODO What should we return here? Does a group always contain the point
+ // if it is within the extents? IMPORTANT - we may need to cache extents
+ // in this class, since we may need to use it here.
+
+ // TODO How does contains() affect mouse notifications?
+
+ return false;
+ }
+
+ @Override
+ public boolean isFocusable() {
+ return false;
+ }
+
+ /**
+ * Returns the group's unconstrained preferred width.
+ */
+ public int getPreferredWidth() {
+ return getPreferredWidth(-1);
+ }
+
+ /**
+ * Returnsgrouponent's constrained preferred width.
+ *
+ * @param height
+ * The height value by which the preferred width should be constrained, or
+ * <tt>-1</tt> for no constraint.
+ *
+ * @return
+ * The constrained preferred width.
+ */
+ @Override
+ public int getPreferredWidth(int height) {
+ int preferredWidth;
+
+ if (this.preferredWidth == -1) {
+ if (height == -1) {
+ preferredWidth = getPreferredSize().width;
+ } else {
+ if (preferredSize != null
+ && preferredSize.height == height) {
+ preferredWidth = preferredSize.width;
+ } else {
+ preferredWidth = (layout == null) ? 0 : layout.getPreferredWidth(this, height);
+
+ Limits widthLimits = getWidthLimits();
+ preferredWidth = widthLimits.constrain(preferredWidth);
+ }
+ }
+ } else {
+ preferredWidth = this.preferredWidth;
+ }
+
+ return preferredWidth;
+ }
+
+ /**
+ * Sets the group's preferred width.
+ *
+ * @param preferredWidth
+ * The preferred width value, or <tt>-1</tt> to use the default
+ * value determined by the skin.
+ */
+ public void setPreferredWidth(int preferredWidth) {
+ setPreferredSize(preferredWidth, preferredHeight);
+ }
+
+ /**
+ * Returns a flag indicating whether the preferred width was explicitly
+ * set by the caller or is the default value determined by the skin.
+ *
+ * @return
+ * <tt>true</tt> if the preferred width was explicitly set; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isPreferredWidthSet() {
+ return (preferredWidth != -1);
+ }
+
+ /**
+ * Returns the group's unconstrained preferred height.
+ */
+ public int getPreferredHeight() {
+ return getPreferredHeight(-1);
+ }
+
+ /**
+ * Returns the group's constrained preferred height.
+ *
+ * @param width
+ * The width value by which the preferred height should be constrained, or
+ * <tt>-1</tt> for no constraint.
+ *
+ * @return
+ * The constrained preferred height.
+ */
+ @Override
+ public int getPreferredHeight(int width) {
+ int preferredHeight;
+
+ if (this.preferredHeight == -1) {
+ if (width == -1) {
+ preferredHeight = getPreferredSize().height;
+ } else {
+ if (preferredSize != null
+ && preferredSize.width == width) {
+ preferredHeight = preferredSize.height;
+ } else {
+ preferredHeight = (layout == null) ? 0 : layout.getPreferredHeight(this, width);
+
+ Limits heightLimits = getHeightLimits();
+ preferredHeight = heightLimits.constrain(preferredHeight);
+ }
+ }
+ } else {
+ preferredHeight = this.preferredHeight;
+ }
+
+ return preferredHeight;
+ }
+
+ /**
+ * Sets the group's preferred height.
+ *
+ * @param preferredHeight
+ * The preferred height value, or <tt>-1</tt> to use the default
+ * value determined by the skin.
+ */
+ public void setPreferredHeight(int preferredHeight) {
+ setPreferredSize(preferredWidth, preferredHeight);
+ }
+
+ /**
+ * Returns a flag indicating whether the preferred height was explicitly
+ * set by the caller or is the default value determined by the skin.
+ *
+ * @return
+ * <tt>true</tt> if the preferred height was explicitly set; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isPreferredHeightSet() {
+ return (preferredHeight != -1);
+ }
+
+ /**
+ * Gets the group's unconstrained preferred size.
+ */
+ public Dimensions getPreferredSize() {
+ if (preferredSize == null) {
+ if (layout == null) {
+ preferredSize = new Dimensions(0, 0);
+ } else {
+ Dimensions preferredSize;
+
+ if (preferredWidth == -1
+ && preferredHeight == -1) {
+ preferredSize = new Dimensions(layout.getPreferredWidth(this, preferredHeight),
+ layout.getPreferredHeight(this, preferredWidth));
+ } else if (preferredWidth == -1) {
+ preferredSize = new Dimensions(layout.getPreferredWidth(this, preferredHeight),
+ preferredHeight);
+ } else if (preferredHeight == -1) {
+ preferredSize = new Dimensions(preferredWidth, layout.getPreferredHeight(this,
+ preferredWidth));
+ } else {
+ preferredSize = new Dimensions(preferredWidth, preferredHeight);
+ }
+
+ Limits widthLimits = getWidthLimits();
+ Limits heightLimits = getHeightLimits();
+
+ int preferredWidth = widthLimits.constrain(preferredSize.width);
+ int preferredHeight = heightLimits.constrain(preferredSize.height);
+
+ if (preferredSize.width > preferredWidth) {
+ preferredHeight = heightLimits.constrain(layout.getPreferredHeight(this, preferredWidth));
+ }
+
+ if (preferredSize.height > preferredHeight) {
+ preferredWidth = widthLimits.constrain(layout.getPreferredWidth(this, preferredHeight));
+ }
+
+ this.preferredSize = new Dimensions(preferredWidth, preferredHeight);
+ }
+ }
+
+ return preferredSize;
+ }
+
+ public final void setPreferredSize(Dimensions preferredSize) {
+ if (preferredSize == null) {
+ throw new IllegalArgumentException("preferredSize is null.");
+ }
+
+ setPreferredSize(preferredSize.width, preferredSize.height);
+ }
+
+ /**
+ * Sets the group's preferred size.
+ *
+ * @param preferredWidth
+ * The preferred width value, or <tt>-1</tt> to use the default
+ * value determined by the skin.
+ *
+ * @param preferredHeight
+ * The preferred height value, or <tt>-1</tt> to use the default
+ * value determined by the skin.
+ */
+ public void setPreferredSize(int preferredWidth, int preferredHeight) {
+ if (preferredWidth < -1) {
+ throw new IllegalArgumentException(preferredWidth
+ + " is not a valid value for preferredWidth.");
+ }
+
+ if (preferredHeight < -1) {
+ throw new IllegalArgumentException(preferredHeight
+ + " is not a valid value for preferredHeight.");
+ }
+
+ int previousPreferredWidth = this.preferredWidth;
+ int previousPreferredHeight = this.preferredHeight;
+
+ if (previousPreferredWidth != preferredWidth
+ || previousPreferredHeight != preferredHeight) {
+ this.preferredWidth = preferredWidth;
+ this.preferredHeight = preferredHeight;
+
+ invalidate();
+
+ groupListeners.preferredSizeChanged(this, previousPreferredWidth,
+ previousPreferredHeight);
+ }
+ }
+
+ /**
+ * Returns a flag indicating whether the preferred size was explicitly
+ * set by the caller or is the default value determined by the skin.
+ *
+ * @return
+ * <tt>true</tt> if the preferred size was explicitly set; <tt>false</tt>,
+ * otherwise.
+ */
+ public boolean isPreferredSizeSet() {
+ return isPreferredWidthSet()
+ && isPreferredHeightSet();
+ }
+
+ /**
+ * Returns the minimum width of this group.
+ */
+ public int getMinimumWidth() {
+ return minimumWidth;
+ }
+
+ /**
+ * Sets the minimum width of this group.
+ *
+ * @param minimumWidth
+ */
+ public void setMinimumWidth(int minimumWidth) {
+ setWidthLimits(minimumWidth, getMaximumWidth());
+ }
+
+ /**
+ * Returns the maximum width of this group.
+ */
+ public int getMaximumWidth() {
+ return maximumWidth;
+ }
+
+ /**
+ * Sets the maximum width of this group.
+ *
+ * @param maximumWidth
+ */
+ public void setMaximumWidth(int maximumWidth) {
+ setWidthLimits(getMinimumWidth(), maximumWidth);
+ }
+
+ /**
+ * Returns the width limits for this group.
+ */
+ public Limits getWidthLimits() {
+ return new Limits(minimumWidth, maximumWidth);
+ }
+
+ /**
+ * Sets the width limits for this group.
+ *
+ * @param minimumWidth
+ * @param maximumWidth
+ */
+ public void setWidthLimits(int minimumWidth, int maximumWidth) {
+ int previousMinimumWidth = this.minimumWidth;
+ int previousMaximumWidth = this.maximumWidth;
+
+ if (previousMinimumWidth != minimumWidth
+ || previousMaximumWidth != maximumWidth) {
+ if (minimumWidth < 0) {
+ throw new IllegalArgumentException("minimumWidth is negative.");
+ }
+
+ if (minimumWidth > maximumWidth) {
+ throw new IllegalArgumentException("minimumWidth is greater than maximumWidth.");
+ }
+
+ this.minimumWidth = minimumWidth;
+ this.maximumWidth = maximumWidth;
+
+ invalidate();
+
+ groupListeners.widthLimitsChanged(this, previousMinimumWidth, previousMaximumWidth);
+ }
+ }
+
+ /**
+ * Sets the width limits for this group.
+ *
+ * @param widthLimits
+ */
+ public final void setWidthLimits(Limits widthLimits) {
+ if (widthLimits == null) {
+ throw new IllegalArgumentException("widthLimits is null.");
+ }
+
+ setWidthLimits(widthLimits.minimum, widthLimits.maximum);
+ }
+
+ /**
+ * Returns the minimum height of this group.
+ */
+ public int getMinimumHeight() {
+ return minimumHeight;
+ }
+
+ /**
+ * Sets the minimum height of this group.
+ *
+ * @param minimumHeight
+ */
+ public void setMinimumHeight(int minimumHeight) {
+ setHeightLimits(minimumHeight, getMaximumHeight());
+ }
+
+ /**
+ * Returns the maximum height of this group.
+ */
+ public int getMaximumHeight() {
+ return maximumHeight;
+ }
+
+ /**
+ * Sets the maximum height of this group.
+ *
+ * @param maximumHeight
+ */
+ public void setMaximumHeight(int maximumHeight) {
+ setHeightLimits(getMinimumHeight(), maximumHeight);
+ }
+
+ /**
+ * Returns the height limits for this group.
+ */
+ public Limits getHeightLimits() {
+ return new Limits(minimumHeight, maximumHeight);
+ }
+
+ /**
+ * Sets the height limits for this group.
+ *
+ * @param minimumHeight
+ * @param maximumHeight
+ */
+ public void setHeightLimits(int minimumHeight, int maximumHeight) {
+ int previousMinimumHeight = this.minimumHeight;
+ int previousMaximumHeight = this.maximumHeight;
+
+ if (previousMinimumHeight != minimumHeight
+ || previousMaximumHeight != maximumHeight) {
+ if (minimumHeight < 0) {
+ throw new IllegalArgumentException("minimumHeight is negative.");
+ }
+
+ if (minimumHeight > maximumHeight) {
+ throw new IllegalArgumentException("minimumHeight is greater than maximumHeight.");
+ }
+
+ this.minimumHeight = minimumHeight;
+ this.maximumHeight = maximumHeight;
+
+ invalidate();
+
+ groupListeners.heightLimitsChanged(this, previousMinimumHeight, previousMaximumHeight);
+ }
+ }
+
+ /**
+ * Sets the height limits for this group.
+ *
+ * @param heightLimits
+ */
+ public final void setHeightLimits(Limits heightLimits) {
+ if (heightLimits == null) {
+ throw new IllegalArgumentException("heightLimits is null.");
+ }
+
+ setHeightLimits(heightLimits.minimum, heightLimits.maximum);
+ }
+
+ @Override
+ public int getBaseline(int width, int height) {
+ return (layout == null) ? -1 : layout.getBaseline(this, width, height);
+ }
+
+ /**
+ * Returns the group's baseline.
+ *
+ * @return
+ * The baseline relative to the origin of this group, or <tt>-1</tt> if
+ * this group does not have a baseline.
+ */
+ public int getBaseline() {
+ if (baseline == -1) {
+ baseline = getBaseline(getWidth(), getHeight());
+ }
+
+ return baseline;
+ }
+
+ // ----------------------------------------
+
+ @Override
+ public void layout() {
+ if (layout != null) {
+ layout.layout(this);
+ }
+
+ for (int i = 0, n = nodes.size(); i < n; i++) {
+ Node node = nodes.get(i);
+ node.validate();
+ }
+ }
+
+ @Override
+ public void invalidate() {
+ // Clear the preferred size and baseline
+ preferredSize = null;
+ baseline = -1;
+
+ super.invalidate();
+ }
+
+ @Override
+ public void paint(Graphics graphics) {
+ Bounds clipBounds = graphics.getClipBounds();
+
+ for (int i = 0, n = nodes.size(); i < n; i++) {
+ Node node = nodes.get(i);
+
+ // Only paint nodes that are visible and intersect the
+ // current clip rectangle
+ if (node.isVisible()
+ && node.getDecoratedBounds().intersects(clipBounds)) {
+ paintNode(graphics, node);
+ }
+ }
+ }
+
+ private void paintNode(Graphics graphics, Node node) {
+ // TODO Transform graphics before passing to node, etc.
+
+ Bounds nodeBounds = node.getBounds();
+
+ // Create a copy of the current graphics context and
+ // translate to the node's coordinate system
+ Graphics decoratedGraphics = graphics.create();
+ decoratedGraphics.translate(nodeBounds.x, nodeBounds.y);
+
+ // Prepare the decorators
+ List<Decorator> decorators = node.getDecorators();
+ int n = decorators.size();
+
+ for (int j = n - 1; j >= 0; j--) {
+ Decorator decorator = decorators.get(j);
+ decoratedGraphics = decorator.prepare(node, decoratedGraphics);
+ }
+
+ // Paint the node
+ Graphics nodeGraphics = decoratedGraphics.create();
+ if (node.getClip()) {
+ nodeGraphics.clip(0, 0, nodeBounds.width, nodeBounds.height);
+ }
+
+ node.paint(nodeGraphics);
+ nodeGraphics.dispose();
+
+ // Update the decorators
+ for (int j = 0; j < n; j++) {
+ Decorator decorator = decorators.get(j);
+ decorator.update();
+ }
+ }
+
+ /**
+ * Requests that focus be given to this group. If this group is not
+ * focusable, this requests that focus be set to the first focusable
+ * descendant in this group.
+ *
+ * @return
+ * The node that got the focus, or <tt>null</tt> if the focus request
+ * was denied
+ */
+ @Override
+ public boolean requestFocus() {
+ boolean focused = false;
+
+ if (isFocusable()) {
+ focused = super.requestFocus();
+ } else {
+ if (focusTraversalPolicy != null) {
+ Node first = focusTraversalPolicy.getNextNode(this, null, FocusTraversalDirection.FORWARD);
+
+ Node node = first;
+ while (node != null
+ && !node.requestFocus()) {
+ node = focusTraversalPolicy.getNextNode(this, node, FocusTraversalDirection.FORWARD);
+
+ // Ensure that we don't get into an infinite loop
+ if (node == first) {
+ break;
+ }
+ }
+
+ focused = (node != null);
+ }
+ }
+
+ return focused;
+ }
+
+ /**
+ * Transfers focus to the next focusable node.
+ *
+ * @param node
+ * The node from which focus will be transferred.
+ *
+ * @param direction
+ * The direction in which to transfer focus.
+ */
+ public Node transferFocus(Node node, FocusTraversalDirection direction) {
+ if (focusTraversalPolicy == null) {
+ // The group has no traversal policy; move up a level
+ node = transferFocus(direction);
+ } else {
+ do {
+ node = focusTraversalPolicy.getNextNode(this, node, direction);
+
+ if (node != null) {
+ if (node.isFocusable()) {
+ node.requestFocus();
+ } else {
+ if (node instanceof Group) {
+ Group group = (Group)node;
+ node = group.transferFocus(null, direction);
+ }
+ }
+ }
+ } while (node != null
+ && !node.isFocused());
+
+ if (node == null) {
+ // We are at the end of the traversal
+ node = transferFocus(direction);
+ }
+ }
+
+ return node;
+ }
+
+ /**
+ * Returns this group's focus traversal policy.
+ */
+ public FocusTraversalPolicy getFocusTraversalPolicy() {
+ return this.focusTraversalPolicy;
+ }
+
+ /**
+ * Sets this group's focus traversal policy.
+ *
+ * @param focusTraversalPolicy
+ * The focus traversal policy to use with this group.
+ */
+ public void setFocusTraversalPolicy(FocusTraversalPolicy focusTraversalPolicy) {
+ FocusTraversalPolicy previousFocusTraversalPolicy = this.focusTraversalPolicy;
+
+ if (previousFocusTraversalPolicy != focusTraversalPolicy) {
+ this.focusTraversalPolicy = focusTraversalPolicy;
+ groupListeners.focusTraversalPolicyChanged(this, previousFocusTraversalPolicy);
+ }
+ }
+
+ /**
+ * Tests whether this group is an ancestor of the currently focused
+ * node.
+ *
+ * @return
+ * <tt>true</tt> if a node is focused and this group is an
+ * ancestor of the node; <tt>false</tt>, otherwise.
+ */
+ public boolean containsFocus() {
+ Node focusedNode = getFocusedNode();
+ return (focusedNode != null
+ && isAncestor(focusedNode));
+ }
+
+ protected void descendantAdded(Node descendant) {
+ Group group = getGroup();
+
+ if (group != null) {
+ group.descendantAdded(descendant);
+ }
+ }
+
+ protected void descendantRemoved(Node descendant) {
+ Group group = getGroup();
+
+ if (group != null) {
+ group.descendantRemoved(descendant);
+ }
+ }
+
+ protected void descendantGainedFocus(Node descendant) {
+ Group group = getGroup();
+
+ if (group != null) {
+ group.descendantGainedFocus(descendant);
+ }
+ }
+
+ protected void descendantLostFocus(Node descendant) {
+ Group group = getGroup();
+
+ if (group != null) {
+ group.descendantLostFocus(descendant);
+ }
+ }
+
+ @Override
+ protected boolean mouseMoved(int x, int y, boolean captured) {
+ boolean consumed = false;
+
+ // Clear the mouse over node if its mouse-over state has
+ // changed (e.g. if its enabled or visible properties have
+ // changed)
+ if (mouseOverNode != null
+ && !mouseOverNode.isMouseOver()) {
+ mouseOverNode = null;
+ }
+
+ if (isEnabled()) {
+ // Synthesize mouse over/out events
+ Node node = getNodeAt(x, y);
+
+ if (mouseOverNode != node) {
+ if (mouseOverNode != null) {
+ mouseOverNode.mouseExited();
+ }
+
+ mouseOverNode = null;
+ }
+
+ // Notify group listeners
+ consumed = groupMouseListeners.mouseMoved(this, x, y, captured);
+
+ if (!consumed) {
+ if (mouseOverNode != node) {
+ mouseOverNode = node;
+
+ if (mouseOverNode!= null) {
+ mouseOverNode.mouseEntered();
+ }
+ }
+
+ // Propagate event to subnodes
+ if (node != null) {
+ // TODO Transform coordinates before passing to node
+ consumed = node.mouseMoved(x - node.getX(), y - node.getY(), captured);
+ }
+
+ // Notify the base class
+ if (!consumed) {
+ consumed = super.mouseMoved(x, y, captured);
+ }
+ }
+ }
+
+ return consumed;
+ }
+
+ @Override
+ protected void mouseExited() {
+ // Ensure that mouse out is called on descendant nodes
+ if (mouseOverNode != null
+ && mouseOverNode.isMouseOver()) {
+ mouseOverNode.mouseExited();
+ }
+
+ mouseOverNode = null;
+
+ super.mouseExited();
+ }
+
+ @Override
+ protected boolean mousePressed(Mouse.Button button, int x, int y) {
+ boolean consumed = false;
+
+ mouseDown = true;
+
+ if (isEnabled()) {
+ // Notify group listeners
+ consumed = groupMouseListeners.mousePressed(this, button, x, y);
+
+ if (!consumed) {
+ // Synthesize mouse click event
+ Node node = getNodeAt(x, y);
+
+ long currentTime = System.currentTimeMillis();
+ int multiClickInterval = Mouse.getMultiClickInterval();
+ if (mouseDownNode == node
+ && currentTime - mouseDownTime < multiClickInterval) {
+ mouseClickCount++;
+ } else {
+ mouseDownTime = System.currentTimeMillis();
+ mouseClickCount = 1;
+ }
+
+ mouseDownNode = node;
+
+ // Propagate event to subnodes
+ if (node != null) {
+ // Ensure that mouse over is called
+ if (!node.isMouseOver()) {
+ node.mouseEntered();
+ }
+
+ // TODO Transform coordinates before passing to node
+ consumed = node.mousePressed(button, x - node.getX(), y - node.getY());
+ }
+
+ // Notify the base class
+ if (!consumed) {
+ consumed = super.mousePressed(button, x, y);
+ }
+ }
+ }
+
+ return consumed;
+ }
+
+ @Override
+ protected boolean mouseReleased(Mouse.Button button, int x, int y) {
+ boolean consumed = false;
+
+ if (isEnabled()) {
+ // Notify group listeners
+ consumed = groupMouseListeners.mouseReleased(this, button, x, y);
+
+ if (!consumed) {
+ // Propagate event to subnodes
+ Node node = getNodeAt(x, y);
+
+ if (node != null) {
+ // Ensure that mouse over is called
+ if (!node.isMouseOver()) {
+ node.mouseEntered();
+ }
+
+ // TODO Transform coordinates before passing to node
+ consumed = node.mouseReleased(button, x - node.getX(), y - node.getY());
+ }
+
+ // Notify the base class
+ if (!consumed) {
+ consumed = super.mouseReleased(button, x, y);
+ }
+
+ // Synthesize mouse click event
+ if (mouseDown
+ && node != null
+ && node == mouseDownNode
+ && node.isEnabled()
+ && node.isVisible()) {
+
+ // TODO Transform coordinates before passing to node (consolidate with
+ // above?)
+ mouseClickConsumed = node.mouseClicked(button, x - node.getX(),
+ y - node.getY(), mouseClickCount);
+ }
+ }
+ }
+
+ mouseDown = false;
+
+ return consumed;
+ }
+
+ @Override
+ protected boolean mouseClicked(Mouse.Button button, int x, int y, int count) {
+ if (isEnabled()) {
+ if (!mouseClickConsumed) {
+ // Allow the event to propagate
+ mouseClickConsumed = super.mouseClicked(button, x, y, count);
+ }
+ }
+
+ return mouseClickConsumed;
+ }
+
+ @Override
+ protected boolean mouseWheelScrolled(Mouse.ScrollType scrollType, int scrollAmount,
+ int wheelRotation, int x, int y) {
+ boolean consumed = false;
+
+ if (isEnabled()) {
+ // Notify group listeners
+ consumed = groupMouseListeners.mouseWheelScrolled(this, scrollType, scrollAmount,
+ wheelRotation, x, y);
+
+ if (!consumed) {
+ // Propagate event to subnodes
+ Node node = getNodeAt(x, y);
+
+ if (node != null) {
+ // Ensure that mouse over is called
+ if (!node.isMouseOver()) {
+ node.mouseEntered();
+ }
+
+ // TODO Transform coordinates before passing to node
+ consumed = node.mouseWheelScrolled(scrollType, scrollAmount, wheelRotation,
+ x - node.getX(), y - node.getY());
+ }
+
+ // Notify the base class
+ if (!consumed) {
+ consumed = super.mouseWheelScrolled(scrollType, scrollAmount,
+ wheelRotation, x, y);
+ }
+ }
+ }
+
+ return consumed;
+ }
+
+ public ListenerList<GroupListener> getGroupListeners() {
+ return groupListeners;
+ }
+
+ public ListenerList<GroupMouseListener> getGroupMouseListeners() {
+ return groupMouseListeners;
+ }
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupListener.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupListener.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+/**
+ * Group listener interface.
+ */
+public interface GroupListener {
+ /**
+ * Group listener adapter.
+ */
+ public static class Adapter implements GroupListener {
+ @Override
+ public void preferredSizeChanged(Group group, int previousPreferredWidth,
+ int previousPreferredHeight) {
+ }
+
+ @Override
+ public void widthLimitsChanged(Group group, int previousMinimumWidth,
+ int previousMaximumWidth) {
+ }
+
+ @Override
+ public void heightLimitsChanged(Group group, int previousMinimumHeight,
+ int previousMaximumHeight) {
+ }
+
+
+ @Override
+ public void layoutChanged(Group group, Layout previousLayout) {
+ }
+
+ @Override
+ public void focusTraversalPolicyChanged(Group group,
+ FocusTraversalPolicy previousFocusTraversalPolicy) {
+ }
+ }
+
+ /**
+ * Called when a group's preferred size has changed.
+ *
+ * @param group
+ * @param previousPreferredWidth
+ * @param previousPreferredHeight
+ */
+ public void preferredSizeChanged(Group group, int previousPreferredWidth,
+ int previousPreferredHeight);
+
+ /**
+ * Called when a group's preferred width limits have changed.
+ *
+ * @param group
+ * @param previousMinimumWidth
+ * @param previousMaximumWidth
+ */
+ public void widthLimitsChanged(Group group, int previousMinimumWidth,
+ int previousMaximumWidth);
+
+ /**
+ * Called when a group's preferred height limits have changed.
+ *
+ * @param group
+ * @param previousMinimumHeight
+ * @param previousMaximumHeight
+ */
+ public void heightLimitsChanged(Group group, int previousMinimumHeight,
+ int previousMaximumHeight);
+
+ /**
+ * Called when a group's layout has changed.
+ *
+ * @param group
+ * @param previousLayout
+ */
+ public void layoutChanged(Group group, Layout previousLayout);
+
+ /**
+ * Called when a group's focus traversal policy has changed.
+ *
+ * @param group
+ * @param previousFocusTraversalPolicy
+ */
+ public void focusTraversalPolicyChanged(Group group,
+ FocusTraversalPolicy previousFocusTraversalPolicy);
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupMouseListener.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupMouseListener.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupMouseListener.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/GroupMouseListener.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+/**
+ * Group mouse listener interface. Group mouse events are "tunneling" events;
+ * consuming a group mouse event prevents it from propagating down the node
+ * hierarchy.
+ */
+public interface GroupMouseListener {
+ /**
+ * Group mouse listener adapter.
+ */
+ public static class Adapter implements GroupMouseListener {
+ @Override
+ public boolean mouseMoved(Group group, int x, int y, boolean captured) {
+ return false;
+ }
+
+ @Override
+ public boolean mousePressed(Group group, Mouse.Button button, int x, int y) {
+ return false;
+ }
+
+ @Override
+ public boolean mouseReleased(Group group, Mouse.Button button, int x, int y) {
+ return false;
+ }
+
+ @Override
+ public boolean mouseWheelScrolled(Group group, Mouse.ScrollType scrollType,
+ int scrollAmount, int wheelRotation, int x, int y) {
+ return false;
+ }
+ }
+
+ /**
+ * Called when the mouse is moved while over a group.
+ *
+ * @param group
+ * @param x
+ * @param y
+ * @param captured
+ *
+ * @return
+ * <tt>true</tt> to consume the event; <tt>false</tt> to allow it to
+ * propagate.
+ */
+ public boolean mouseMoved(Group group, int x, int y, boolean captured);
+
+ /**
+ * Called when the mouse is pressed over a group.
+ *
+ * @param group
+ * @param button
+ * @param x
+ * @param y
+ *
+ * @return
+ * <tt>true</tt> to consume the event; <tt>false</tt> to allow it to
+ * propagate.
+ */
+ public boolean mousePressed(Group group, Mouse.Button button, int x, int y);
+
+ /**
+ * Called when the mouse is released over a group.
+ *
+ * @param group
+ * @param button
+ * @param x
+ * @param y
+ *
+ * @return
+ * <tt>true</tt> to consume the event; <tt>false</tt> to allow it to
+ * propagate.
+ */
+ public boolean mouseReleased(Group group, Mouse.Button button, int x, int y);
+
+ /**
+ * Called when the mouse wheel is scrolled over a group.
+ *
+ * @param group
+ * @param scrollType
+ * @param scrollAmount
+ * @param wheelRotation
+ * @param x
+ * @param y
+ *
+ * @return
+ * <tt>true</tt> to consume the event; <tt>false</tt> to allow it to
+ * propagate.
+ */
+ public boolean mouseWheelScrolled(Group group, Mouse.ScrollType scrollType,
+ int scrollAmount, int wheelRotation, int x, int y);
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/HorizontalAlignment.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/HorizontalAlignment.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/HorizontalAlignment.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/HorizontalAlignment.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+/**
+ * Enumeration representing horizontal alignment values.
+ */
+public enum HorizontalAlignment {
+ /**
+ * Align to the right.
+ */
+ RIGHT,
+
+ /**
+ * Align to the left.
+ */
+ LEFT,
+
+ /**
+ * Align to center.
+ */
+ CENTER
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/Insets.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/Insets.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/Insets.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/Insets.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.pivot.beans.BeanAdapter;
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.json.JSONSerializer;
+
+/**
+ * Class representing the insets of an object.
+ */
+public final class Insets implements Serializable {
+ private static final long serialVersionUID = 0;
+
+ public final int top;
+ public final int left;
+ public final int bottom;
+ public final int right;
+
+ public static final String TOP_KEY = "top";
+ public static final String LEFT_KEY = "left";
+ public static final String BOTTOM_KEY = "bottom";
+ public static final String RIGHT_KEY = "right";
+
+ public static final Insets NONE = new Insets(0);
+
+ public Insets(int inset) {
+ this.top = inset;
+ this.left = inset;
+ this.bottom = inset;
+ this.right = inset;
+ }
+
+ public Insets(int top, int left, int bottom, int right) {
+ this.top = top;
+ this.left = left;
+ this.bottom = bottom;
+ this.right = right;
+ }
+
+ public Insets(Insets insets) {
+ if (insets == null) {
+ throw new IllegalArgumentException("insets is null.");
+ }
+
+ this.top = insets.top;
+ this.left = insets.left;
+ this.bottom = insets.bottom;
+ this.right = insets.right;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean equals = false;
+
+ if (object instanceof Insets) {
+ Insets insets = (Insets) object;
+ equals = (top == insets.top
+ && left == insets.left
+ && bottom == insets.bottom
+ && right == insets.right);
+ }
+
+ return equals;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + top;
+ result = prime * result + left;
+ result = prime * result + bottom;
+ result = prime * result + right;
+
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getName() + " [" + top + ", " + left + ", " + bottom + ", " + right + "]";
+ }
+
+ public static Insets decode(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+
+ Insets insets;
+ if (value.startsWith("{")) {
+ Map<String, ?> map;
+ try {
+ map = JSONSerializer.parseMap(value);
+ } catch (SerializationException exception) {
+ throw new IllegalArgumentException(exception);
+ }
+
+ int top = BeanAdapter.getInt(map, TOP_KEY);
+ int left = BeanAdapter.getInt(map, LEFT_KEY);
+ int bottom = BeanAdapter.getInt(map, BOTTOM_KEY);
+ int right = BeanAdapter.getInt(map, RIGHT_KEY);
+
+ insets = new Insets(top, left, bottom, right);
+ } else {
+ insets = new Insets(Integer.parseInt(value));
+ }
+
+ return insets;
+ }
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/Keyboard.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/Keyboard.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/Keyboard.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/Keyboard.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,339 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+import java.awt.Toolkit;
+import java.awt.event.KeyEvent;
+import java.lang.reflect.Field;
+import java.util.Locale;
+
+/**
+ * Class representing the system keyboard.
+ */
+public final class Keyboard {
+ /**
+ * Enumeration representing keyboard modifiers.
+ */
+ public enum Modifier {
+ SHIFT,
+ CTRL,
+ ALT,
+ META;
+
+ public int getMask() {
+ return 1 << ordinal();
+ }
+ }
+
+ /**
+ * Enumeration representing key locations.
+ */
+ public enum KeyLocation {
+ STANDARD,
+ LEFT,
+ RIGHT,
+ KEYPAD
+ }
+
+ /**
+ * Represents a keystroke, a combination of a keycode and modifier flags.
+ */
+ public static final class KeyStroke {
+ private int keyCode = KeyCode.UNDEFINED;
+ private int modifiers = 0x00;
+
+ public static final String COMMAND_ABBREVIATION = "CMD";
+
+ public KeyStroke(int keyCode, int modifiers) {
+ this.keyCode = keyCode;
+ this.modifiers = modifiers;
+ }
+
+ public int getKeyCode() {
+ return keyCode;
+ }
+
+ public int getModifiers() {
+ return modifiers;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean equals = false;
+
+ if (object instanceof KeyStroke) {
+ KeyStroke keyStroke = (KeyStroke)object;
+ equals = (this.keyCode == keyStroke.keyCode
+ && this.modifiers == keyStroke.modifiers);
+ }
+
+ return equals;
+ }
+
+ @Override
+ public int hashCode() {
+ // NOTE Key codes are currently defined as 16-bit values, so
+ // shifting by 4 bits to append the modifiers should be OK.
+ // However, if Oracle changes the key code values in the future,
+ // this may no longer be safe.
+ int hashCode = keyCode << 4 | modifiers;
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ int awtModifiers = 0x00;
+
+ if (((modifiers & Modifier.META.getMask()) > 0)) {
+ awtModifiers |= KeyEvent.META_DOWN_MASK;
+ }
+
+ if (((modifiers & Modifier.CTRL.getMask()) > 0)) {
+ awtModifiers |= KeyEvent.CTRL_DOWN_MASK;
+ }
+
+ if (((modifiers & Modifier.ALT.getMask()) > 0)) {
+ awtModifiers |= KeyEvent.ALT_DOWN_MASK;
+ }
+
+ if (((modifiers & Modifier.SHIFT.getMask()) > 0)) {
+ awtModifiers |= KeyEvent.SHIFT_DOWN_MASK;
+ }
+
+ return KeyEvent.getModifiersExText(awtModifiers) + getKeyStrokeModifierSeparator()
+ + KeyEvent.getKeyText(keyCode);
+ }
+
+ public static KeyStroke decode(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException("value is null.");
+ }
+
+ int keyCode = KeyCode.UNDEFINED;
+ int modifiers = 0x00;
+
+ String[] keys = value.split("-");
+ for (int i = 0, n = keys.length; i < n; i++) {
+ if (i < n - 1) {
+ // Modifier
+ String modifierAbbreviation = keys[i].toUpperCase(Locale.ENGLISH);
+
+ Modifier modifier;
+ if (modifierAbbreviation.equals(COMMAND_ABBREVIATION)) {
+ modifier = getCommandModifier();
+ } else {
+ modifier = Modifier.valueOf(modifierAbbreviation);
+ }
+
+ modifiers |= modifier.getMask();
+ } else {
+ // Keycode
+ try {
+ Field keyCodeField = KeyCode.class.getField(keys[i].toUpperCase(Locale.ENGLISH));
+ keyCode = (Integer)keyCodeField.get(null);
+ } catch(Exception exception) {
+ throw new IllegalArgumentException(exception);
+ }
+ }
+ }
+
+ return new KeyStroke(keyCode, modifiers);
+ }
+ }
+
+ /**
+ * Contains a set of key code constants that are common to all locales.
+ */
+ public static final class KeyCode {
+ public static final int A = KeyEvent.VK_A;
+ public static final int B = KeyEvent.VK_B;
+ public static final int C = KeyEvent.VK_C;
+ public static final int D = KeyEvent.VK_D;
+ public static final int E = KeyEvent.VK_E;
+ public static final int F = KeyEvent.VK_F;
+ public static final int G = KeyEvent.VK_G;
+ public static final int H = KeyEvent.VK_H;
+ public static final int I = KeyEvent.VK_I;
+ public static final int J = KeyEvent.VK_J;
+ public static final int K = KeyEvent.VK_K;
+ public static final int L = KeyEvent.VK_L;
+ public static final int M = KeyEvent.VK_M;
+ public static final int N = KeyEvent.VK_N;
+ public static final int O = KeyEvent.VK_O;
+ public static final int P = KeyEvent.VK_P;
+ public static final int Q = KeyEvent.VK_Q;
+ public static final int R = KeyEvent.VK_R;
+ public static final int S = KeyEvent.VK_S;
+ public static final int T = KeyEvent.VK_T;
+ public static final int U = KeyEvent.VK_U;
+ public static final int V = KeyEvent.VK_V;
+ public static final int W = KeyEvent.VK_W;
+ public static final int X = KeyEvent.VK_X;
+ public static final int Y = KeyEvent.VK_Y;
+ public static final int Z = KeyEvent.VK_Z;
+
+ public static final int N0 = KeyEvent.VK_0;
+ public static final int N1 = KeyEvent.VK_1;
+ public static final int N2 = KeyEvent.VK_2;
+ public static final int N3 = KeyEvent.VK_3;
+ public static final int N4 = KeyEvent.VK_4;
+ public static final int N5 = KeyEvent.VK_5;
+ public static final int N6 = KeyEvent.VK_6;
+ public static final int N7 = KeyEvent.VK_7;
+ public static final int N8 = KeyEvent.VK_8;
+ public static final int N9 = KeyEvent.VK_9;
+
+ public static final int TAB = KeyEvent.VK_TAB;
+ public static final int SPACE = KeyEvent.VK_SPACE;
+ public static final int ENTER = KeyEvent.VK_ENTER;
+ public static final int ESCAPE = KeyEvent.VK_ESCAPE;
+ public static final int BACKSPACE = KeyEvent.VK_BACK_SPACE;
+ public static final int DELETE = KeyEvent.VK_DELETE;
+
+ public static final int UP = KeyEvent.VK_UP;
+ public static final int DOWN = KeyEvent.VK_DOWN;
+ public static final int LEFT = KeyEvent.VK_LEFT;
+ public static final int RIGHT = KeyEvent.VK_RIGHT;
+
+ public static final int PAGE_UP = KeyEvent.VK_PAGE_UP;
+ public static final int PAGE_DOWN = KeyEvent.VK_PAGE_DOWN;
+
+ public static final int HOME = KeyEvent.VK_HOME;
+ public static final int END = KeyEvent.VK_END;
+
+ public static final int KEYPAD_0 = KeyEvent.VK_NUMPAD0;
+ public static final int KEYPAD_1 = KeyEvent.VK_NUMPAD1;
+ public static final int KEYPAD_2 = KeyEvent.VK_NUMPAD2;
+ public static final int KEYPAD_3 = KeyEvent.VK_NUMPAD3;
+ public static final int KEYPAD_4 = KeyEvent.VK_NUMPAD4;
+ public static final int KEYPAD_5 = KeyEvent.VK_NUMPAD5;
+ public static final int KEYPAD_6 = KeyEvent.VK_NUMPAD6;
+ public static final int KEYPAD_7 = KeyEvent.VK_NUMPAD7;
+ public static final int KEYPAD_8 = KeyEvent.VK_NUMPAD8;
+ public static final int KEYPAD_9 = KeyEvent.VK_NUMPAD9;
+ public static final int KEYPAD_UP = KeyEvent.VK_KP_UP;
+ public static final int KEYPAD_DOWN = KeyEvent.VK_KP_DOWN;
+ public static final int KEYPAD_LEFT = KeyEvent.VK_KP_LEFT;
+ public static final int KEYPAD_RIGHT = KeyEvent.VK_KP_RIGHT;
+
+ public static final int PLUS = KeyEvent.VK_PLUS;
+ public static final int MINUS = KeyEvent.VK_MINUS;
+ public static final int EQUALS = KeyEvent.VK_EQUALS;
+
+ public static final int ADD = KeyEvent.VK_ADD;
+ public static final int SUBTRACT = KeyEvent.VK_SUBTRACT;
+ public static final int MULTIPLY = KeyEvent.VK_MULTIPLY;
+ public static final int DIVIDE = KeyEvent.VK_DIVIDE;
+
+ public static final int F1 = KeyEvent.VK_F1;
+ public static final int F2 = KeyEvent.VK_F2;
+ public static final int F3 = KeyEvent.VK_F3;
+ public static final int F4 = KeyEvent.VK_F4;
+ public static final int F5 = KeyEvent.VK_F5;
+ public static final int F6 = KeyEvent.VK_F6;
+ public static final int F7 = KeyEvent.VK_F7;
+ public static final int F8 = KeyEvent.VK_F8;
+ public static final int F9 = KeyEvent.VK_F9;
+ public static final int F10 = KeyEvent.VK_F10;
+ public static final int F11 = KeyEvent.VK_F11;
+ public static final int F12 = KeyEvent.VK_F12;
+
+ public static final int UNDEFINED = KeyEvent.VK_UNDEFINED;
+ }
+
+ private static int modifiers = 0;
+
+ private static final int DEFAULT_CARET_BLINK_RATE = 600;
+
+ private static final Modifier COMMAND_MODIFIER;
+ private static final Modifier WORD_NAVIGATION_MODIFIER;
+ private static final String KEYSTROKE_MODIFIER_SEPARATOR;
+
+ static {
+ String osName = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
+
+ if (osName.startsWith("mac os x")) {
+ COMMAND_MODIFIER = Modifier.META;
+ WORD_NAVIGATION_MODIFIER = Modifier.ALT;
+ KEYSTROKE_MODIFIER_SEPARATOR = "";
+ } else {
+ COMMAND_MODIFIER = Modifier.CTRL;
+ WORD_NAVIGATION_MODIFIER = Modifier.CTRL;
+ KEYSTROKE_MODIFIER_SEPARATOR = "-";
+ }
+ }
+
+ /**
+ * Returns a bitfield representing the keyboard modifiers that are
+ * currently pressed.
+ */
+ public static int getModifiers() {
+ return modifiers;
+ }
+
+ protected static void setModifiers(int modifiers) {
+ Keyboard.modifiers = modifiers;
+ }
+
+ /**
+ * Tests the pressed state of a modifier.
+ *
+ * @param modifier
+ *
+ * @return
+ * <tt>true</tt> if the modifier is pressed; <tt>false</tt>, otherwise.
+ */
+ public static boolean isPressed(Modifier modifier) {
+ return (modifiers & modifier.getMask()) > 0;
+ }
+
+ /**
+ * Returns the system caret blink rate.
+ */
+ public static int getCaretBlinkRate() {
+ Toolkit toolkit = Toolkit.getDefaultToolkit();
+ Integer cursorBlinkRate = (Integer)toolkit.getDesktopProperty("awt.cursorBlinkRate");
+
+ if (cursorBlinkRate == null) {
+ cursorBlinkRate = DEFAULT_CARET_BLINK_RATE;
+ }
+
+ return cursorBlinkRate;
+ }
+
+ /**
+ * Returns the system command modifier key.
+ */
+ public static Modifier getCommandModifier() {
+ return COMMAND_MODIFIER;
+ }
+
+ /**
+ * Returns the word navigation modifier key.
+ */
+ public static Modifier getWordNavigationModifier() {
+ return WORD_NAVIGATION_MODIFIER;
+ }
+
+ /**
+ * Returns the keystroke modifier separator text.
+ */
+ public static String getKeyStrokeModifierSeparator() {
+ return KEYSTROKE_MODIFIER_SEPARATOR;
+ }
+}
+
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/Layout.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/Layout.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/Layout.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/Layout.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+/**
+ * Interface that encapsulates layout behavior for a group.
+ */
+public interface Layout {
+ /**
+ * Calculates the preferred width for a group.
+ *
+ * @param group
+ * @param height
+ */
+ public int getPreferredWidth(Group group, int height);
+
+ /**
+ * Calculates the preferred height for a group.
+ *
+ * @param group
+ * @param width
+ */
+ public int getPreferredHeight(Group group, int width);
+
+ /**
+ * Calculates the baseline for a group.
+ *
+ * @param group
+ * @param width
+ * @param height
+ * @return
+ */
+ public int getBaseline(Group group, int width, int height);
+
+ /**
+ * Lays out the group.
+ *
+ * @param group
+ */
+ public void layout(Group group);
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/Limits.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/Limits.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/Limits.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/Limits.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.pivot.beans.BeanAdapter;
+import org.apache.pivot.io.SerializationException;
+import org.apache.pivot.json.JSONSerializer;
+
+/**
+ * Class representing minimum and maximum values.
+ */
+public final class Limits implements Serializable {
+ private static final long serialVersionUID = 0;
+
+ public final int minimum;
+ public final int maximum;
+
+ public static final String MINIMUM_KEY = "minimum";
+ public static final String MAXIMUM_KEY = "maximum";
+
+ public Limits(int minimum, int maximum) {
+ if (minimum > maximum) {
+ throw new IllegalArgumentException("minimum is greater than maximum.");
+ }
+
+ this.minimum = minimum;
+ this.maximum = maximum;
+ }
+
+ public Limits(Limits limits) {
+ if (limits == null) {
+ throw new IllegalArgumentException("limits is null.");
+ }
+
+ minimum = limits.minimum;
+ maximum = limits.maximum;
+ }
+
+ /**
+ * Limits the specified value to the minimum and maximum values of
+ * this object.
+ *
+ * @param value
+ * The value to limit.
+ *
+ * @return
+ * The bounded value.
+ */
+ public int constrain(int value) {
+ if (value < minimum) {
+ value = minimum;
+ } else if (value > maximum) {
+ value = maximum;
+ }
+
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean equals = false;
+
+ if (object instanceof Limits) {
+ Limits limits = (Limits)object;
+ equals = (minimum == limits.minimum
+ && maximum == limits.maximum);
+ }
+
+ return equals;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * minimum + maximum;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+
+ buf.append(getClass().getName());
+ buf.append(" [");
+
+ if (minimum == Integer.MIN_VALUE) {
+ buf.append("MIN");
+ } else {
+ buf.append(minimum);
+ }
+
+ buf.append("-");
+
+ if (maximum == Integer.MAX_VALUE) {
+ buf.append("MAX");
+ } else {
+ buf.append(maximum);
+ }
+
+ buf.append("]");
+
+ return buf.toString();
+ }
+
+ public static Limits decode(String value) {
+ if (value == null) {
+ throw new IllegalArgumentException();
+ }
+
+ Map<String, ?> map;
+ try {
+ map = JSONSerializer.parseMap(value);
+ } catch (SerializationException exception) {
+ throw new IllegalArgumentException(exception);
+ }
+
+ int minimum = BeanAdapter.getInt(map, MINIMUM_KEY);
+ int maximum = BeanAdapter.getInt(map, MAXIMUM_KEY);
+
+ return new Limits(minimum, maximum);
+ }
+}
Added: pivot/branches/3.x/scene/src/org/apache/pivot/scene/LinearGradientPaint.java
URL: http://svn.apache.org/viewvc/pivot/branches/3.x/scene/src/org/apache/pivot/scene/LinearGradientPaint.java?rev=1057053&view=auto
==============================================================================
--- pivot/branches/3.x/scene/src/org/apache/pivot/scene/LinearGradientPaint.java (added)
+++ pivot/branches/3.x/scene/src/org/apache/pivot/scene/LinearGradientPaint.java Sun Jan 9 23:19:19 2011
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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 org.apache.pivot.scene;
+
+import java.util.List;
+
+/**
+ * Class representing a linear gradient paint.
+ */
+public final class LinearGradientPaint extends MultiStopGradientPaint {
+ public final Point start;
+ public final Point end;
+
+ public LinearGradientPaint(int startX, int startY, int endX, int endY, List<Stop> stops) {
+ this(new Point(startX, startY), new Point(endX, endY), stops);
+ }
+
+ public LinearGradientPaint(Point start, Point end, List<Stop> stops) {
+ super(stops);
+
+ this.start = start;
+ this.end = end;
+ }
+
+ @Override
+ protected Object getNativePaint() {
+ if (nativePaint == null) {
+ nativePaint = Platform.getPlatform().getNativePaint(this);
+ }
+
+ return nativePaint;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ boolean equals = false;
+
+ if (object instanceof LinearGradientPaint) {
+ LinearGradientPaint linearGradientPaint = (LinearGradientPaint)object;
+ equals = (start.equals(linearGradientPaint.start)
+ && end.equals(linearGradientPaint.end));
+ }
+
+ return equals;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * start.hashCode() + end.hashCode();
+ }
+}