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 [33/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/skin/ScrollPaneSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/ScrollPaneSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/ScrollPaneSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/ScrollPaneSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,973 @@
+/*
+ * 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.Component;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Keyboard;
+import pivot.wtk.Mouse;
+import pivot.wtk.Orientation;
+import pivot.wtk.Bounds;
+import pivot.wtk.ScrollBar;
+import pivot.wtk.ScrollBarValueListener;
+import pivot.wtk.ScrollPane;
+import pivot.wtk.ScrollPane.Corner;
+import pivot.wtk.ScrollPane.ScrollBarPolicy;
+import pivot.wtk.ScrollPaneListener;
+import pivot.wtk.Viewport;
+import pivot.wtk.ViewportListener;
+
+/**
+ * Scroll pane skin.
+ *
+ * @author tvolkert
+ */
+public class ScrollPaneSkin extends ContainerSkin
+ implements Viewport.Skin, ScrollPaneListener, ViewportListener,
+ ScrollBarValueListener {
+
+ private ScrollBar horizontalScrollBar = new ScrollBar(Orientation.HORIZONTAL);
+ private ScrollBar verticalScrollBar = new ScrollBar(Orientation.VERTICAL);
+
+ private Corner topLeftCorner = new Corner(Corner.Placement.TOP_LEFT);
+ private Corner bottomLeftCorner = new Corner(Corner.Placement.BOTTOM_LEFT);
+ private Corner bottomRightCorner = new Corner(Corner.Placement.BOTTOM_RIGHT);
+ private Corner topRightCorner = new Corner(Corner.Placement.TOP_RIGHT);
+
+ private int horizontalReveal = 30;
+ private int verticalReveal = 30;
+
+ private int cachedHorizontalScrollBarHeight = 0;
+ private int cachedVerticalScrollBarWidth = 0;
+
+ private static final int DEFAULT_HORIZONTAL_INCREMENT = 10;
+ private static final int DEFAULT_VERTICAL_INCREMENT = 10;
+
+ public ScrollPaneSkin() {
+ super();
+
+ horizontalScrollBar.setUnitIncrement(DEFAULT_HORIZONTAL_INCREMENT);
+ verticalScrollBar.setUnitIncrement(DEFAULT_VERTICAL_INCREMENT);
+ }
+
+ @Override
+ public void install(Component component) {
+ super.install(component);
+
+ ScrollPane scrollPane = (ScrollPane)component;
+ scrollPane.getViewportListeners().add(this);
+ scrollPane.getScrollPaneListeners().add(this);
+
+ scrollPane.add(horizontalScrollBar);
+ scrollPane.add(verticalScrollBar);
+
+ scrollPane.add(topLeftCorner);
+ scrollPane.add(bottomLeftCorner);
+ scrollPane.add(bottomRightCorner);
+ scrollPane.add(topRightCorner);
+
+ horizontalScrollBar.getScrollBarValueListeners().add(this);
+ verticalScrollBar.getScrollBarValueListeners().add(this);
+ }
+
+ @Override
+ public void uninstall() {
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+ scrollPane.getViewportListeners().remove(this);
+ scrollPane.getScrollPaneListeners().remove(this);
+
+ scrollPane.remove(horizontalScrollBar);
+ scrollPane.remove(verticalScrollBar);
+
+ scrollPane.remove(topLeftCorner);
+ scrollPane.remove(bottomLeftCorner);
+ scrollPane.remove(bottomRightCorner);
+ scrollPane.remove(topRightCorner);
+
+ horizontalScrollBar.getScrollBarValueListeners().remove(this);
+ verticalScrollBar.getScrollBarValueListeners().remove(this);
+
+ super.uninstall();
+ }
+
+ @Override
+ public int getPreferredWidth(int height) {
+ int preferredWidth = 0;
+
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+ Component view = scrollPane.getView();
+
+ if (view != null) {
+ int preferredRowHeaderWidth = 0;
+ Component rowHeader = scrollPane.getRowHeader();
+ if (rowHeader != null) {
+ preferredRowHeaderWidth = rowHeader.getPreferredWidth(-1);
+ }
+
+ int preferredColumnHeaderHeight = 0;
+ Component columnHeader = scrollPane.getColumnHeader();
+ if (columnHeader != null) {
+ preferredColumnHeaderHeight = columnHeader.getPreferredHeight(-1);
+ }
+
+ ScrollBarPolicy verticalPolicy = scrollPane.getVerticalScrollBarPolicy();
+
+ if (verticalPolicy != ScrollBarPolicy.FILL) {
+ // Get the unconstrained preferred size of the view
+ Dimensions preferredViewSize = view.getPreferredSize();
+
+ // If the policy is FILL_TO_CAPACITY, and the sum of the
+ // unconstrained preferred heights of the view and the column
+ // header is less than the height constraint, apply the FILL
+ // policy; otherwise, apply the AUTO policy
+
+ if (verticalPolicy == ScrollBarPolicy.FILL_TO_CAPACITY) {
+ if (height < 0) {
+ verticalPolicy = ScrollBarPolicy.AUTO;
+ } else {
+ int preferredHeight = preferredViewSize.height +
+ preferredColumnHeaderHeight;
+
+ if (preferredHeight < height) {
+ verticalPolicy = ScrollBarPolicy.FILL;
+ } else {
+ verticalPolicy = ScrollBarPolicy.AUTO;
+ }
+ }
+ }
+
+ // If the policy is ALWAYS, NEVER, or AUTO, the preferred
+ // width is the sum of the unconstrained preferred widths of
+ // the view and row header, plus the width of the scroll
+ // bar if policy is ALWAYS or if the view's preferred height is
+ // greater than the height constraint and the policy is AUTO
+
+ if (verticalPolicy == ScrollBarPolicy.ALWAYS
+ || verticalPolicy == ScrollBarPolicy.NEVER
+ || verticalPolicy == ScrollBarPolicy.AUTO) {
+ preferredWidth = preferredViewSize.width +
+ preferredRowHeaderWidth;
+
+ // If the sum of the preferred heights of the view and the
+ // column header is greater than the height constraint,
+ // include the preferred width of the scroll bar in the
+ // preferred width calculation
+ if (verticalPolicy == ScrollBarPolicy.ALWAYS
+ || (verticalPolicy == ScrollBarPolicy.AUTO
+ && height > 0
+ && preferredViewSize.height + preferredColumnHeaderHeight > height)) {
+ preferredWidth += verticalScrollBar.getPreferredWidth(-1);
+ }
+ }
+ }
+
+ if (verticalPolicy == ScrollBarPolicy.FILL) {
+ // Preferred width is the sum of the constrained preferred
+ // width of the view and the unconstrained preferred width of
+ // the row header
+
+ if (height >= 0) {
+ // Subtract the unconstrained preferred height of the
+ // column header from the height constraint
+ height = Math.max(height - preferredColumnHeaderHeight, 0);
+ }
+
+ preferredWidth = view.getPreferredWidth(height) +
+ preferredRowHeaderWidth;
+ }
+ }
+
+ return preferredWidth;
+ }
+
+ @Override
+ public int getPreferredHeight(int width) {
+ int preferredHeight = 0;
+
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+ Component view = scrollPane.getView();
+
+ if (view != null) {
+ int preferredRowHeaderWidth = 0;
+ Component rowHeader = scrollPane.getRowHeader();
+ if (rowHeader != null) {
+ preferredRowHeaderWidth = rowHeader.getPreferredWidth(-1);
+ }
+
+ int preferredColumnHeaderHeight = 0;
+ Component columnHeader = scrollPane.getColumnHeader();
+ if (columnHeader != null) {
+ preferredColumnHeaderHeight = columnHeader.getPreferredHeight(-1);
+ }
+
+ ScrollBarPolicy horizontalPolicy = scrollPane.getHorizontalScrollBarPolicy();
+
+ if (horizontalPolicy != ScrollBarPolicy.FILL) {
+ // Get the unconstrained preferred size of the view
+ Dimensions preferredViewSize = view.getPreferredSize();
+
+ // If the policy is FILL_TO_CAPACITY, and the sum of the
+ // unconstrained preferred widths of the view and the row
+ // header is less than the width constraint, apply the FILL
+ // policy; otherwise, apply the AUTO policy
+
+ if (horizontalPolicy == ScrollBarPolicy.FILL_TO_CAPACITY) {
+ if (width < 0) {
+ horizontalPolicy = ScrollBarPolicy.AUTO;
+ } else {
+ int preferredWidth = preferredViewSize.width +
+ preferredRowHeaderWidth;
+
+ if (preferredWidth < width) {
+ horizontalPolicy = ScrollBarPolicy.FILL;
+ } else {
+ horizontalPolicy = ScrollBarPolicy.AUTO;
+ }
+ }
+ }
+
+ // If the policy is ALWAYS, NEVER, or AUTO, the preferred
+ // height is the sum of the unconstrained preferred heights of
+ // the view and column header, plus the height of the scroll
+ // bar if policy is ALWAYS or if the view's preferred width is
+ // greater than the width constraint and the policy is AUTO
+
+ if (horizontalPolicy == ScrollBarPolicy.ALWAYS
+ || horizontalPolicy == ScrollBarPolicy.NEVER
+ || horizontalPolicy == ScrollBarPolicy.AUTO) {
+ preferredHeight = preferredViewSize.height +
+ preferredColumnHeaderHeight;
+
+ // If the sum of the preferred widths of the view and the
+ // row header is greater than the width constraint, include
+ // the preferred height of the scroll bar in the preferred
+ // height calculation
+ if (horizontalPolicy == ScrollBarPolicy.ALWAYS
+ || (horizontalPolicy == ScrollBarPolicy.AUTO
+ && width > 0
+ && preferredViewSize.width + preferredRowHeaderWidth > width)) {
+ preferredHeight += horizontalScrollBar.getPreferredHeight(-1);
+ }
+ }
+ }
+
+ if (horizontalPolicy == ScrollBarPolicy.FILL) {
+ // Preferred height is the sum of the constrained preferred height
+ // of the view and the unconstrained preferred height of the column
+ // header
+
+ if (width >= 0) {
+ // Subtract the unconstrained preferred width of the row header
+ // from the width constraint
+ width = Math.max(width - preferredRowHeaderWidth, 0);
+ }
+
+ preferredHeight = view.getPreferredHeight(width) +
+ preferredColumnHeaderHeight;
+ }
+ }
+
+ return preferredHeight;
+ }
+
+ @Override
+ public Dimensions getPreferredSize() {
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+
+ int preferredWidth = 0;
+ int preferredHeight = 0;
+
+ Component view = scrollPane.getView();
+ if (view != null) {
+ Dimensions preferredViewSize = view.getPreferredSize();
+
+ preferredWidth += preferredViewSize.width;
+ preferredHeight += preferredViewSize.height;
+
+ Component rowHeader = scrollPane.getRowHeader();
+ if (rowHeader != null) {
+ preferredWidth += rowHeader.getPreferredWidth(-1);
+ }
+
+ Component columnHeader = scrollPane.getColumnHeader();
+ if (columnHeader != null) {
+ preferredHeight += columnHeader.getPreferredHeight(-1);
+ }
+
+ if (scrollPane.getHorizontalScrollBarPolicy() == ScrollBarPolicy.ALWAYS) {
+ preferredHeight += horizontalScrollBar.getPreferredHeight(-1);
+ }
+
+ if (scrollPane.getVerticalScrollBarPolicy() == ScrollBarPolicy.ALWAYS) {
+ preferredWidth += verticalScrollBar.getPreferredWidth(-1);
+ }
+ }
+
+ return new Dimensions(preferredWidth, preferredHeight);
+ }
+
+ @Override
+ public boolean mouseWheel(Component component, Mouse.ScrollType scrollType, int scrollAmount,
+ int wheelRotation, int x, int y) {
+ boolean consumed = false;
+
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+ Component view = scrollPane.getView();
+
+ if (view != null) {
+ // The scroll orientation is tied to whether the shift key was
+ // presssed while the mouse wheel was scrolled
+ if (Keyboard.isPressed(Keyboard.Modifier.SHIFT)) {
+ // Treat the mouse wheel as a horizontal scroll event
+ int previousScrollLeft = scrollPane.getScrollLeft();
+ int newScrollLeft = previousScrollLeft + (scrollAmount * wheelRotation *
+ horizontalScrollBar.getUnitIncrement());
+
+ if (wheelRotation > 0) {
+ int maxScrollLeft = getMaxScrollLeft();
+ newScrollLeft = Math.min(newScrollLeft, maxScrollLeft);
+
+ if (previousScrollLeft < maxScrollLeft) {
+ consumed = true;
+ }
+ } else {
+ newScrollLeft = Math.max(newScrollLeft, 0);
+
+ if (previousScrollLeft > 0) {
+ consumed = true;
+ }
+ }
+
+ scrollPane.setScrollLeft(newScrollLeft);
+ } else {
+ // Treat the mouse wheel as a vertical scroll event
+ int previousScrollTop = scrollPane.getScrollTop();
+ int newScrollTop = previousScrollTop + (scrollAmount * wheelRotation *
+ verticalScrollBar.getUnitIncrement());
+
+ if (wheelRotation > 0) {
+ int maxScrollTop = getMaxScrollTop();
+ newScrollTop = Math.min(newScrollTop, maxScrollTop);
+
+ if (previousScrollTop < maxScrollTop) {
+ consumed = true;
+ }
+ } else {
+ newScrollTop = Math.max(newScrollTop, 0);
+
+ if (previousScrollTop > 0) {
+ consumed = true;
+ }
+ }
+
+ scrollPane.setScrollTop(newScrollTop);
+ }
+ }
+
+ return consumed;
+ }
+
+ @Override
+ public boolean keyPressed(Component component, int keyCode, Keyboard.KeyLocation keyLocation) {
+ boolean consumed = super.keyPressed(component, keyCode, keyLocation);
+
+ if (!consumed) {
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+
+ int scrollTop = scrollPane.getScrollTop();
+ int scrollLeft = scrollPane.getScrollLeft();
+
+ if (keyCode == Keyboard.KeyCode.UP) {
+ int newScrollTop = Math.max(scrollTop -
+ verticalScrollBar.getUnitIncrement(), 0);
+
+ scrollPane.setScrollTop(newScrollTop);
+
+ consumed = (newScrollTop != scrollTop);
+ } else if (keyCode == Keyboard.KeyCode.DOWN) {
+ int newScrollTop = Math.min(scrollTop +
+ verticalScrollBar.getUnitIncrement(), getMaxScrollTop());
+
+ scrollPane.setScrollTop(newScrollTop);
+
+ consumed = (newScrollTop != scrollTop);
+ } else if (keyCode == Keyboard.KeyCode.LEFT) {
+ int newScrollLeft = Math.max(scrollLeft -
+ horizontalScrollBar.getUnitIncrement(), 0);
+
+ scrollPane.setScrollLeft(newScrollLeft);
+
+ consumed = (newScrollLeft != scrollLeft);
+ } else if (keyCode == Keyboard.KeyCode.RIGHT) {
+ int newScrollLeft = Math.min(scrollLeft +
+ horizontalScrollBar.getUnitIncrement(), getMaxScrollLeft());
+
+ scrollPane.setScrollLeft(newScrollLeft);
+
+ consumed = (newScrollLeft != scrollLeft);
+ } else if (keyCode == Keyboard.KeyCode.PAGE_UP) {
+ int increment = verticalScrollBar.getBlockIncrement();
+ int newScrollTop = Math.max(scrollTop - increment, 0);
+
+ scrollPane.setScrollTop(newScrollTop);
+
+ consumed = (newScrollTop != scrollTop);
+ } else if (keyCode == Keyboard.KeyCode.PAGE_DOWN) {
+ int increment = verticalScrollBar.getBlockIncrement();
+ int newScrollTop = Math.min(scrollTop + increment, getMaxScrollTop());
+
+ scrollPane.setScrollTop(newScrollTop);
+
+ consumed = (newScrollTop != scrollTop);
+ }
+ }
+
+ return consumed;
+ }
+
+ /**
+ * Gets the maximum legal <tt>scrollTop</tt> value this this skin imposes.
+ * This is the largest value possible that still shows as much of the view
+ * component as it can.
+ *
+ * @return
+ * The maximum scrollTop value
+ */
+ private int getMaxScrollTop() {
+ int maxScrollTop = 0;
+
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+ Component view = scrollPane.getView();
+
+ if (view != null) {
+ int viewHeight = view.getHeight();
+ int columnHeaderHeight = 0;
+ int horizontalScrollBarHeight = 0;
+ int height = getHeight();
+
+ Component columnHeader = scrollPane.getColumnHeader();
+ if (columnHeader != null) {
+ columnHeaderHeight = columnHeader.getHeight();
+ }
+
+ if (horizontalScrollBar.isVisible()) {
+ horizontalScrollBarHeight = horizontalScrollBar.getHeight();
+ }
+
+ maxScrollTop = Math.max(viewHeight + columnHeaderHeight +
+ horizontalScrollBarHeight - height, 0);
+ }
+
+ return maxScrollTop;
+ }
+
+ /**
+ * Gets the maximum legal <tt>scrollLeft</tt> value this this skin imposes.
+ * This is the largest value possible that still shows as much of the view
+ * component as it can.
+ *
+ * @return
+ * The maximum scrollLeft value
+ */
+ private int getMaxScrollLeft() {
+ int maxScrollLeft = 0;
+
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+ Component view = scrollPane.getView();
+
+ if (view != null) {
+ int viewWidth = view.getWidth();
+ int rowHeaderWidth = 0;
+ int verticalScrollBarWidth = 0;
+ int width = getWidth();
+
+ Component rowHeader = scrollPane.getRowHeader();
+ if (rowHeader != null) {
+ rowHeaderWidth = rowHeader.getWidth();
+ }
+
+ if (verticalScrollBar.isVisible()) {
+ verticalScrollBarWidth = verticalScrollBar.getWidth();
+ }
+
+ maxScrollLeft = Math.max(viewWidth + rowHeaderWidth +
+ verticalScrollBarWidth - width, 0);
+ }
+
+ return maxScrollLeft;
+ }
+
+ public void layout() {
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+
+ ScrollBarPolicy horizontalPolicy = scrollPane.getHorizontalScrollBarPolicy();
+ ScrollBarPolicy verticalPolicy = scrollPane.getVerticalScrollBarPolicy();
+
+ boolean fillWidthToCapacity = false;
+ boolean fillHeightToCapacity = false;
+
+ // The FILL_TO_CAPACITY policy means that we try to use AUTO, and only
+ // if it ends up not being wide or tall enough do we use FILL
+
+ if (horizontalPolicy == ScrollBarPolicy.FILL_TO_CAPACITY) {
+ horizontalPolicy = ScrollBarPolicy.AUTO;
+ fillWidthToCapacity = true;
+ }
+
+ if (verticalPolicy == ScrollBarPolicy.FILL_TO_CAPACITY) {
+ verticalPolicy = ScrollBarPolicy.AUTO;
+ fillHeightToCapacity = true;
+ }
+
+ layoutHelper(horizontalPolicy, verticalPolicy);
+
+ Component view = scrollPane.getView();
+ if (view != null && (fillWidthToCapacity || fillHeightToCapacity)) {
+ // We assumed AUTO. Now we check our assumption to see if we
+ // need to adjust it to use FILL
+ boolean adjustWidth = false, adjustHeight = false;
+
+ if (fillWidthToCapacity) {
+ Component rowHeader = scrollPane.getRowHeader();
+ int rowHeaderWidth = rowHeader != null ? rowHeader.getWidth() : 0;
+
+ int verticalScrollBarWidth = verticalScrollBar.isVisible() ?
+ verticalScrollBar.getWidth() : 0;
+ int minViewWidth = getWidth() - rowHeaderWidth - verticalScrollBarWidth;
+
+ if (view.getWidth() < minViewWidth) {
+ horizontalPolicy = ScrollBarPolicy.FILL;
+ adjustWidth = true;
+ }
+ }
+
+ if (fillHeightToCapacity) {
+ Component columnHeader = scrollPane.getColumnHeader();
+ int columnHeaderHeight = columnHeader != null ?
+ columnHeader.getHeight() : 0;
+
+ int horizontalScrollBarHeight = horizontalScrollBar.isVisible() ?
+ horizontalScrollBar.getHeight() : 0;
+ int minViewHeight = getHeight() - columnHeaderHeight -
+ horizontalScrollBarHeight;
+
+ if (view.getHeight() < minViewHeight) {
+ verticalPolicy = ScrollBarPolicy.FILL;
+ adjustHeight = true;
+ }
+ }
+
+ if (adjustWidth || adjustHeight) {
+ layoutHelper(horizontalPolicy, verticalPolicy);
+ }
+ }
+
+ cachedHorizontalScrollBarHeight = horizontalScrollBar.getHeight();
+ cachedVerticalScrollBarWidth = verticalScrollBar.getWidth();
+ }
+
+ /**
+ * Layout helper method that assumes that the <tt>FILL_TO_CAPACITY</tt>
+ * scroll policy doesn't exist.
+ *
+ * @param horizontalPolicy
+ * The assumed horizontal scroll policy; musn't be <tt>FILL_TO_CAPACITY</tt>
+ *
+ * @param vertical policy
+ * The assumed vertical scroll policy; musn't be <tt>FILL_TO_CAPACITY</tt>
+ */
+ private void layoutHelper(ScrollBarPolicy horizontalPolicy,
+ ScrollBarPolicy verticalPolicy) {
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+
+ int width = getWidth();
+ int height = getHeight();
+
+ boolean constrainWidth = (horizontalPolicy == ScrollBarPolicy.FILL);
+ boolean constrainHeight = (verticalPolicy == ScrollBarPolicy.FILL);
+
+ Component view = scrollPane.getView();
+ Component columnHeader = scrollPane.getColumnHeader();
+ Component rowHeader = scrollPane.getRowHeader();
+ Component corner = scrollPane.getCorner();
+
+ int rowHeaderWidth = 0;
+ if (rowHeader != null) {
+ rowHeaderWidth = rowHeader.getPreferredWidth(-1);
+ }
+
+ int columnHeaderHeight = 0;
+ if (columnHeader != null) {
+ columnHeaderHeight = columnHeader.getPreferredHeight(-1);
+ }
+
+ int previousViewWidth, viewWidth = 0;
+ int previousViewHeight, viewHeight = 0;
+ int previousHorizontalScrollBarHeight, horizontalScrollBarHeight = cachedHorizontalScrollBarHeight;
+ int previousVerticalScrollBarWidth, verticalScrollBarWidth = cachedVerticalScrollBarWidth;
+ int i = 0;
+
+ do {
+ previousViewWidth = viewWidth;
+ previousViewHeight = viewHeight;
+ previousHorizontalScrollBarHeight = horizontalScrollBarHeight;
+ previousVerticalScrollBarWidth = verticalScrollBarWidth;
+
+ if (view != null) {
+ if (constrainWidth && constrainHeight) {
+ viewWidth = Math.max
+ (width - rowHeaderWidth - verticalScrollBarWidth, 0);
+ viewHeight = Math.max
+ (height - columnHeaderHeight - horizontalScrollBarHeight, 0);
+ } else if (constrainWidth) {
+ viewWidth = Math.max
+ (width - rowHeaderWidth - verticalScrollBarWidth, 0);
+ viewHeight = view.getPreferredHeight(viewWidth);
+ } else if (constrainHeight) {
+ viewHeight = Math.max
+ (height - columnHeaderHeight - horizontalScrollBarHeight, 0);
+ viewWidth = view.getPreferredWidth(viewHeight);
+ } else {
+ Dimensions viewPreferredSize = view.getPreferredSize();
+ viewWidth = viewPreferredSize.width;
+ viewHeight = viewPreferredSize.height;
+ }
+ }
+
+ if (horizontalPolicy == ScrollBarPolicy.ALWAYS
+ || (horizontalPolicy == ScrollBarPolicy.AUTO
+ && viewWidth > width - rowHeaderWidth - verticalScrollBarWidth)) {
+ horizontalScrollBarHeight = horizontalScrollBar.getPreferredHeight(-1);
+ } else {
+ horizontalScrollBarHeight = 0;
+ }
+
+ if (verticalPolicy == ScrollBarPolicy.ALWAYS
+ || (verticalPolicy == ScrollBarPolicy.AUTO
+ && viewHeight > height - columnHeaderHeight - horizontalScrollBarHeight)) {
+ verticalScrollBarWidth = verticalScrollBar.getPreferredWidth(-1);
+ } else {
+ verticalScrollBarWidth = 0;
+ }
+
+ if (++i > 4) {
+ // Infinite loop protection
+ System.err.println("Breaking out of potential infinite loop");
+ break;
+ }
+ } while (viewWidth != previousViewWidth
+ || viewHeight != previousViewHeight
+ || horizontalScrollBarHeight != previousHorizontalScrollBarHeight
+ || verticalScrollBarWidth != previousVerticalScrollBarWidth);
+
+ int scrollTop = scrollPane.getScrollTop();
+ int scrollLeft = scrollPane.getScrollLeft();
+
+ if (view != null) {
+ view.setSize(viewWidth, viewHeight);
+ view.setLocation(rowHeaderWidth - scrollLeft, columnHeaderHeight - scrollTop);
+ }
+
+ if (columnHeader != null) {
+ columnHeader.setSize(viewWidth, columnHeaderHeight);
+ columnHeader.setLocation(rowHeaderWidth - scrollLeft, 0);
+ }
+
+ if (rowHeader != null) {
+ rowHeader.setSize(rowHeaderWidth, viewHeight);
+ rowHeader.setLocation(0, columnHeaderHeight - scrollTop);
+ }
+
+ if (horizontalScrollBarHeight > 0) {
+ horizontalScrollBar.setVisible(true);
+
+ int horizontalScrollBarWidth = Math.max
+ (width - rowHeaderWidth - verticalScrollBarWidth, 0);
+ horizontalScrollBar.setSize(horizontalScrollBarWidth,
+ horizontalScrollBarHeight);
+ horizontalScrollBar.setLocation(rowHeaderWidth,
+ height - horizontalScrollBarHeight);
+ } else {
+ horizontalScrollBar.setVisible(false);
+ }
+
+ if (verticalScrollBarWidth > 0) {
+ verticalScrollBar.setVisible(true);
+
+ int verticalScrollBarHeight = Math.max
+ (height - columnHeaderHeight - horizontalScrollBarHeight, 0);
+ verticalScrollBar.setSize(verticalScrollBarWidth,
+ verticalScrollBarHeight);
+ verticalScrollBar.setLocation(width - verticalScrollBarWidth,
+ columnHeaderHeight);
+ } else {
+ verticalScrollBar.setVisible(false);
+ }
+
+ // Handle corner components
+
+ if (columnHeaderHeight > 0
+ && rowHeaderWidth > 0) {
+ if (corner != null) {
+ corner.setVisible(true);
+ corner.setSize(rowHeaderWidth, columnHeaderHeight);
+ corner.setLocation(0, 0);
+
+ topLeftCorner.setVisible(false);
+ } else {
+ topLeftCorner.setVisible(true);
+ topLeftCorner.setSize(rowHeaderWidth, columnHeaderHeight);
+ topLeftCorner.setLocation(0, 0);
+ }
+ } else {
+ if (corner != null) {
+ corner.setVisible(false);
+ }
+
+ topLeftCorner.setVisible(false);
+ }
+
+ if (rowHeaderWidth > 0
+ && horizontalScrollBarHeight > 0) {
+ bottomLeftCorner.setVisible(true);
+ bottomLeftCorner.setSize(rowHeaderWidth, horizontalScrollBarHeight);
+ bottomLeftCorner.setLocation(0, height - horizontalScrollBarHeight);
+ } else {
+ bottomLeftCorner.setVisible(false);
+ }
+
+ if (verticalScrollBarWidth > 0
+ && horizontalScrollBarHeight > 0) {
+ bottomRightCorner.setVisible(true);
+ bottomRightCorner.setSize(verticalScrollBarWidth, horizontalScrollBarHeight);
+ bottomRightCorner.setLocation(width - verticalScrollBarWidth,
+ height - horizontalScrollBarHeight);
+ } else {
+ bottomRightCorner.setVisible(false);
+ }
+
+ if (columnHeaderHeight > 0
+ && verticalScrollBarWidth > 0) {
+ topRightCorner.setVisible(true);
+ topRightCorner.setSize(verticalScrollBarWidth, columnHeaderHeight);
+ topRightCorner.setLocation(width - verticalScrollBarWidth, 0);
+ } else {
+ topRightCorner.setVisible(false);
+ }
+
+ // Perform bounds checking on the scrollTop and scrollLeft values,
+ // and adjust them as necessary. Make sure to do this after we've laid
+ // everything out, since our ViewPortListener methods rely on valid
+ // sizes from our components.
+
+ int maxScrollTop = getMaxScrollTop();
+ if (scrollTop > maxScrollTop) {
+ scrollPane.setScrollTop(maxScrollTop);
+ }
+
+ int maxScrollLeft = getMaxScrollLeft();
+ if (scrollLeft > maxScrollLeft) {
+ scrollPane.setScrollLeft(maxScrollLeft);
+ }
+
+ // Adjust the structure of our scroll bars. Make sure to do this after
+ // we adjust the scrollTop and scrollLeft values; otherwise we might
+ // try to set structure values that are out of bounds.
+
+ int viewportWidth = Math.max(width - rowHeaderWidth - verticalScrollBarWidth, 0);
+ horizontalScrollBar.setScope(0, viewWidth, Math.min(viewWidth, viewportWidth));
+ horizontalScrollBar.setBlockIncrement(Math.max(1, viewportWidth - horizontalReveal));
+
+ int viewportHeight = Math.max(height - columnHeaderHeight - horizontalScrollBarHeight, 0);
+ verticalScrollBar.setScope(0, viewHeight, Math.min(viewHeight, viewportHeight));
+ verticalScrollBar.setBlockIncrement(Math.max(1, viewportHeight - verticalReveal));
+ }
+
+ public int getHorizontalIncrement() {
+ return horizontalScrollBar.getUnitIncrement();
+ }
+
+ public void setHorizontalIncrement(int horizontalIncrement) {
+ horizontalScrollBar.setUnitIncrement(horizontalIncrement);
+ }
+
+ public int getVerticalIncrement() {
+ return verticalScrollBar.getUnitIncrement();
+ }
+
+ public void setVerticalIncrement(int verticalIncrement) {
+ verticalScrollBar.setUnitIncrement(verticalIncrement);
+ }
+
+ public int getHorizontalReveal() {
+ return horizontalReveal;
+ }
+
+ public void setHorizontalReveal(int horizontalReveal) {
+ this.horizontalReveal = horizontalReveal;
+ }
+
+ public int getVerticalReveal() {
+ return verticalReveal;
+ }
+
+ public void setVerticalReveal(int verticalReveal) {
+ this.verticalReveal = verticalReveal;
+ }
+
+ // Viewport.Skin methods
+
+ public Bounds getViewportBounds() {
+ int x = 0;
+ int y = 0;
+ int width = getWidth();
+ int height = getHeight();
+
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+
+ Component rowHeader = scrollPane.getRowHeader();
+ if (rowHeader != null) {
+ int rowHeaderWidth = rowHeader.getWidth();
+
+ x += rowHeaderWidth;
+ width -= rowHeaderWidth;
+ }
+
+ Component columnHeader = scrollPane.getColumnHeader();
+ if (columnHeader != null) {
+ int columnHeaderHeight = columnHeader.getHeight();
+
+ y += columnHeaderHeight;
+ height -= columnHeaderHeight;
+ }
+
+ if (horizontalScrollBar.isVisible()) {
+ height -= horizontalScrollBar.getHeight();
+ }
+
+ if (verticalScrollBar.isVisible()) {
+ width -= verticalScrollBar.getWidth();
+ }
+
+ return new Bounds(x, y, width, height);
+ }
+
+ // ScrollPaneListener methods
+
+ public void horizontalScrollBarPolicyChanged(ScrollPane scrollPane,
+ ScrollBarPolicy previousHorizontalScrollBarPolicy) {
+ invalidateComponent();
+ }
+
+ public void verticalScrollBarPolicyChanged(ScrollPane scrollPane,
+ ScrollBarPolicy previousVerticalScrollBarPolicy) {
+ invalidateComponent();
+ }
+
+ public void rowHeaderChanged(ScrollPane scrollPane, Component previousRowHeader) {
+ invalidateComponent();
+ }
+
+ public void columnHeaderChanged(ScrollPane scrollPane, Component previousColumnHeader) {
+ invalidateComponent();
+ }
+
+ public void cornerChanged(ScrollPane scrollPane, Component previousCorner) {
+ invalidateComponent();
+ }
+
+ // ViewportListener methods
+
+ public void scrollTopChanged(Viewport viewport, int previousScrollTop) {
+ // NOTE we don't invalidate the component here because we need only
+ // reposition the view and row header. Invalidating would yield
+ // the correct positioning, but it would do much more work than needed.
+
+ ScrollPane scrollPane = (ScrollPane)viewport;
+
+ Component view = scrollPane.getView();
+ Component columnHeader = scrollPane.getColumnHeader();
+ Component rowHeader = scrollPane.getRowHeader();
+
+ int scrollTop = scrollPane.getScrollTop();
+ int columnHeaderHeight = 0;
+
+ if (columnHeader != null) {
+ columnHeaderHeight = columnHeader.getHeight();
+ }
+
+ if (view != null) {
+ view.setLocation(view.getX(), columnHeaderHeight - scrollTop);
+ }
+
+ if (rowHeader != null) {
+ rowHeader.setLocation(0, columnHeaderHeight - scrollTop);
+ }
+
+ if (scrollTop >= 0 && scrollTop <= getMaxScrollTop()) {
+ verticalScrollBar.setValue(scrollTop);
+ }
+ }
+
+ public void scrollLeftChanged(Viewport viewport, int previousScrollLeft) {
+ // NOTE we don't invalidate the component here because we need only
+ // reposition the view and column header. Invalidating would yield
+ // the correct positioning, but it would do much more work than needed.
+
+ ScrollPane scrollPane = (ScrollPane)viewport;
+
+ Component view = scrollPane.getView();
+ Component columnHeader = scrollPane.getColumnHeader();
+ Component rowHeader = scrollPane.getRowHeader();
+
+ int scrollLeft = scrollPane.getScrollLeft();
+ int rowHeaderWidth = 0;
+
+ if (rowHeader != null) {
+ rowHeaderWidth = rowHeader.getWidth();
+ }
+
+ if (view != null) {
+ view.setLocation(rowHeaderWidth - scrollLeft, view.getY());
+ }
+
+ if (columnHeader != null) {
+ columnHeader.setLocation(rowHeaderWidth - scrollLeft, 0);
+ }
+
+ if (scrollLeft >= 0 && scrollLeft <= getMaxScrollLeft()) {
+ horizontalScrollBar.setValue(scrollLeft);
+ }
+ }
+
+ public void viewChanged(Viewport viewport, Component previousView) {
+ invalidateComponent();
+ }
+
+ // ScrollBarValueListener methods
+
+ public void valueChanged(ScrollBar scrollBar, int previousValue) {
+ ScrollPane scrollPane = (ScrollPane)getComponent();
+
+ int value = scrollBar.getValue();
+
+ if (scrollBar == horizontalScrollBar) {
+ scrollPane.setScrollLeft(value);
+ } else {
+ scrollPane.setScrollTop(value);
+ }
+ }
+}
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SeparatorSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SeparatorSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SeparatorSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SeparatorSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,271 @@
+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.Component;
+import pivot.wtk.Dimensions;
+import pivot.wtk.Insets;
+import pivot.wtk.Platform;
+import pivot.wtk.Separator;
+import pivot.wtk.SeparatorListener;
+import pivot.wtk.Theme;
+
+/**
+ * Separator skin.
+ *
+ * @author gbrown
+ */
+public class SeparatorSkin extends ComponentSkin
+ implements SeparatorListener {
+ private FontRenderContext fontRenderContext = new FontRenderContext(null, true, true);
+
+ private Font font;
+ private Color color;
+ private Color headingColor;
+ private int thickness;
+ private Insets padding;
+
+ public SeparatorSkin() {
+ Theme theme = Theme.getTheme();
+ font = theme.getFont().deriveFont(Font.BOLD);
+ color = Color.BLACK;
+ headingColor = Color.BLACK;
+ thickness = 1;
+ padding = new Insets(4, 0, 4, 4);
+ }
+
+ @Override
+ public void install(Component component) {
+ super.install(component);
+
+ Separator separator = (Separator)component;
+ separator.getSeparatorListeners().add(this);
+ }
+
+ @Override
+ public void uninstall() {
+ Separator separator = (Separator)getComponent();
+ separator.getSeparatorListeners().remove(this);
+
+ super.uninstall();
+ }
+
+ public int getPreferredWidth(int height) {
+ int preferredWidth = 0;
+
+ Separator separator = (Separator)getComponent();
+ String heading = separator.getHeading();
+
+ if (heading != null
+ && heading.length() > 0) {
+ Rectangle2D headingBounds = font.getStringBounds(heading, fontRenderContext);
+ preferredWidth = (int)Math.ceil(headingBounds.getWidth())
+ + (padding.left + padding.right);
+ }
+
+ return preferredWidth;
+ }
+
+ public int getPreferredHeight(int width) {
+ int preferredHeight = thickness;
+
+ Separator separator = (Separator)getComponent();
+ String heading = separator.getHeading();
+
+ if (heading != null
+ && heading.length() > 0) {
+ LineMetrics lm = font.getLineMetrics(heading, fontRenderContext);
+ preferredHeight = Math.max((int)Math.ceil(lm.getAscent() + lm.getDescent()
+ + lm.getLeading()), preferredHeight);
+ }
+
+ preferredHeight += (padding.top + padding.bottom);
+
+ return preferredHeight;
+ }
+
+ public Dimensions getPreferredSize() {
+ // TODO Optimize
+ return new Dimensions(getPreferredWidth(-1), getPreferredHeight(-1));
+ }
+
+ public void layout() {
+ // No-op
+ }
+
+ public void paint(Graphics2D graphics) {
+ Separator separator = (Separator)getComponent();
+ int width = getWidth();
+ int separatorY = padding.top;
+
+ String heading = separator.getHeading();
+
+ if (heading != null
+ && heading.length() > 0) {
+ LineMetrics lm = font.getLineMetrics(heading, fontRenderContext);
+
+ if (fontRenderContext.isAntiAliased()) {
+ graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ Platform.getTextAntialiasingHint());
+ }
+
+ if (fontRenderContext.usesFractionalMetrics()) {
+ graphics.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,
+ RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+ }
+
+ graphics.setFont(font);
+ graphics.setPaint(headingColor);
+ graphics.drawString(heading, padding.left, lm.getAscent() + padding.top);
+
+ Rectangle2D headingBounds = font.getStringBounds(heading, fontRenderContext);
+
+ Area titleClip = new Area(graphics.getClip());
+ titleClip.subtract(new Area(new Rectangle2D.Double(padding.left, padding.top,
+ headingBounds.getWidth() + padding.right, headingBounds.getHeight())));
+ graphics.clip(titleClip);
+
+ separatorY += (lm.getAscent() + lm.getDescent()) / 2 + 1;
+ }
+
+ graphics.setStroke(new BasicStroke(thickness));
+ graphics.setColor(color);
+ graphics.drawLine(0, separatorY, width, separatorY);
+ }
+
+ /**
+ * @return
+ * <tt>false</tt>; spacers are not focusable.
+ */
+ @Override
+ public boolean isFocusable() {
+ return false;
+ }
+
+ 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 getHeadingColor() {
+ return headingColor;
+ }
+
+ public void setHeadingColor(Color headingColor) {
+ if (headingColor == null) {
+ throw new IllegalArgumentException("headingColor is null.");
+ }
+
+ this.headingColor = headingColor;
+ repaintComponent();
+ }
+
+ public final void setHeadingColor(String headingColor) {
+ if (headingColor == null) {
+ throw new IllegalArgumentException("headingColor is null.");
+ }
+
+ setHeadingColor(decodeColor(headingColor));
+ }
+
+ public int getThickness() {
+ return thickness;
+ }
+
+ public void setThickness(int thickness) {
+ this.thickness = thickness;
+ invalidateComponent();
+ }
+
+ public final 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 final void setPadding(Number padding) {
+ if (padding == null) {
+ throw new IllegalArgumentException("padding is null.");
+ }
+
+ setPadding(padding.intValue());
+ }
+
+ // Separator events
+ public void headingChanged(Separator separator, String previousHeading) {
+ invalidateComponent();
+ }
+}
\ No newline at end of file
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SliderSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SliderSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SliderSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/SliderSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,55 @@
+/*
+ * 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.Component;
+import pivot.wtk.Slider;
+import pivot.wtk.SliderListener;
+import pivot.wtk.SliderValueListener;
+
+/**
+ * Abstract base class for slider skins.
+ *
+ * @author gbrown
+ */
+public abstract class SliderSkin extends ContainerSkin
+ implements SliderListener, SliderValueListener {
+ @Override
+ public void install(Component component) {
+ super.install(component);
+
+ Slider slider = (Slider)component;
+ slider.getSliderListeners().add(this);
+ slider.getSliderValueListeners().add(this);
+ }
+
+ @Override
+ public void uninstall() {
+ Slider slider = (Slider)getComponent();
+ slider.getSliderListeners().remove(this);
+ slider.getSliderValueListeners().remove(this);
+
+ super.uninstall();
+ }
+
+ public void boundsChanged(Slider slider, int previousMinimum, int previousMaximum) {
+ invalidateComponent();
+ }
+
+ public void valueChanged(Slider slider, int previousValue) {
+ // No-op
+ }
+}
Added: incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/StackPaneSkin.java
URL: http://svn.apache.org/viewvc/incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/StackPaneSkin.java?rev=758461&view=auto
==============================================================================
--- incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/StackPaneSkin.java (added)
+++ incubator/pivot/branches/1.1/wtk/src/pivot/wtk/skin/StackPaneSkin.java Wed Mar 25 23:08:38 2009
@@ -0,0 +1,81 @@
+/*
+ * 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.StackPane;
+import pivot.wtk.Component;
+import pivot.wtk.Dimensions;
+
+/**
+ * Stack pane skin.
+ *
+ * @author gbrown
+ */
+public class StackPaneSkin extends ContainerSkin {
+ public int getPreferredWidth(int height) {
+ int preferredWidth = 0;
+ StackPane stackPane = (StackPane)getComponent();
+
+ for (Component component : stackPane) {
+ preferredWidth = Math.max(preferredWidth,
+ component.getPreferredWidth(height));
+ }
+
+ return preferredWidth;
+ }
+
+ public int getPreferredHeight(int width) {
+ int preferredHeight = 0;
+ StackPane stackPane = (StackPane)getComponent();
+
+ for (Component component : stackPane) {
+ preferredHeight = Math.max(preferredHeight,
+ component.getPreferredHeight(width));
+ }
+
+ return preferredHeight;
+ }
+
+ public Dimensions getPreferredSize() {
+ int preferredWidth = 0;
+ int preferredHeight = 0;
+
+ StackPane stackPane = (StackPane)getComponent();
+
+ for (Component component : stackPane) {
+ Dimensions preferredCardSize = component.getPreferredSize();
+
+ preferredWidth = Math.max(preferredWidth,
+ preferredCardSize.width);
+
+ preferredHeight = Math.max(preferredHeight,
+ preferredCardSize.height);
+ }
+
+ return new Dimensions(preferredWidth, preferredHeight);
+ }
+
+ public void layout() {
+ // Set the size of all components to match the size of the stack pane
+ StackPane stackPane = (StackPane)getComponent();
+
+ int width = getWidth();
+ int height = getHeight();
+ for (Component component : stackPane) {
+ component.setSize(width, height);
+ }
+ }
+}