Eliminates the need to call layout() explicitly on *LayoutPanel, which
should greatly simplify their use. RequiresLayout becomes
AnimatedLayout, which is now just a convenient moniker for the ability
of a panel to layout its children.

This also necessitated a change to LayoutPanel, such that it no longer
exposes the underlying Layout.Layer objects associated with each widget.

Review: http://gwt-code-reviews.appspot.com/89818

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@6624 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java b/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java
index a639a12..f150ff9 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Mail.java
@@ -53,7 +53,7 @@
     Window.setMargin("0px");
 
     // Special-case stuff to make topPanel overhang a bit.
-    Element topElem = outer.getContainerElementFor(topPanel);
+    Element topElem = outer.getWidgetContainerElement(topPanel);
     topElem.getStyle().setZIndex(2);
     topElem.getStyle().setOverflow(Overflow.VISIBLE);
 
@@ -69,6 +69,5 @@
     // displayed.
     RootLayoutPanel root = RootLayoutPanel.get();
     root.add(outer);
-    root.layout();
   }
 }
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
index b017fad..0ea1f15 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/MailList.java
@@ -78,7 +78,7 @@
     dock.add(new ScrollPanel(table));
     header.setWidth("100%");
     table.setWidth("100%");
-    dock.layout();
+
     initWidget(dock);
     setStyleName("mail-List");
 
diff --git a/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java b/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java
index 28687a1..7634684 100644
--- a/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java
+++ b/samples/mail/src/com/google/gwt/sample/mail/client/Shortcuts.java
@@ -33,8 +33,6 @@
   interface Binder extends UiBinder<StackLayoutPanel, Shortcuts> { }
   private static final Binder binder = GWT.create(Binder.class);
 
-  private StackLayoutPanel stackPanel;
-
   @UiField Mailboxes mailboxes;
   @UiField Tasks tasks;
   @UiField Contacts contacts;
@@ -45,12 +43,6 @@
    * @param images a bundle that provides the images for this widget
    */
   public Shortcuts() {
-    initWidget(stackPanel = binder.createAndBindUi(this));
-  }
-
-  @Override
-  protected void onLoad() {
-    // Show the mailboxes group by default.
-    stackPanel.showWidget(mailboxes);
+    initWidget(binder.createAndBindUi(this));
   }
 }
diff --git a/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
index 6474fb1..6daf3c0 100644
--- a/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
+++ b/user/javadoc/com/google/gwt/examples/DockLayoutPanelExample.java
@@ -33,18 +33,10 @@
     p.addWest(new HTML("west"), 2);
     p.add(new HTML("center"));
 
-    // Note the explicit call to layout(). This is required for the layout to
-    // take effect.
-    p.layout();
-
     // Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for
     // resize events on the window to ensure that its children are informed of
     // possible size changes.
     RootLayoutPanel rp = RootLayoutPanel.get();
     rp.add(p);
-
-    // The RootLayoutPanel also requires that its layout() method be explicitly
-    // called for the initial layout to take effect.
-    rp.layout();
   }
 }
diff --git a/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java
index 3fc43d1..9d0e49c 100644
--- a/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java
+++ b/user/javadoc/com/google/gwt/examples/LayoutPanelExample.java
@@ -18,7 +18,6 @@
 import static com.google.gwt.dom.client.Style.Unit.PCT;
 
 import com.google.gwt.core.client.EntryPoint;
-import com.google.gwt.layout.client.Layout.Layer;
 import com.google.gwt.user.client.ui.HTML;
 import com.google.gwt.user.client.ui.LayoutPanel;
 import com.google.gwt.user.client.ui.RootLayoutPanel;
@@ -34,22 +33,13 @@
     p.add(childOne);
     p.add(childTwo);
 
-    Layer layerOne = p.getLayer(childOne), layerTwo = p.getLayer(childTwo);
-    layerOne.setLeftWidth(0, PCT, 50, PCT);
-    layerTwo.setRightWidth(0, PCT, 50, PCT);
-
-    // Note the explicit call to layout(). This is required for the layout to
-    // take effect.
-    p.layout();
+    p.setWidgetLeftWidth(childOne, 0, PCT, 50, PCT);
+    p.setWidgetRightWidth(childTwo, 0, PCT, 50, PCT);
 
     // Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for
     // resize events on the window to ensure that its children are informed of
     // possible size changes.
     RootLayoutPanel rp = RootLayoutPanel.get();
     rp.add(p);
-
-    // The RootLayoutPanel also requires that its layout() method be explicitly
-    // called for the initial layout to take effect.
-    rp.layout();
   }
 }
diff --git a/user/javadoc/com/google/gwt/examples/SplitLayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/SplitLayoutPanelExample.java
index ba71d4e..1943e5e 100644
--- a/user/javadoc/com/google/gwt/examples/SplitLayoutPanelExample.java
+++ b/user/javadoc/com/google/gwt/examples/SplitLayoutPanelExample.java
@@ -29,18 +29,10 @@
     p.addNorth(new HTML("list"), 384);
     p.add(new HTML("details"));
 
-    // Note the explicit call to layout(). This is required for the layout to
-    // take effect.
-    p.layout();
-
     // Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for
     // resize events on the window to ensure that its children are informed of
     // possible size changes.
     RootLayoutPanel rp = RootLayoutPanel.get();
     rp.add(p);
-
-    // The RootLayoutPanel also requires that its layout() method be explicitly
-    // called for the initial layout to take effect.
-    rp.layout();
   }
 }
diff --git a/user/javadoc/com/google/gwt/examples/StackLayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/StackLayoutPanelExample.java
index b493b01..deee46b 100644
--- a/user/javadoc/com/google/gwt/examples/StackLayoutPanelExample.java
+++ b/user/javadoc/com/google/gwt/examples/StackLayoutPanelExample.java
@@ -30,18 +30,10 @@
     p.add(new HTML("that"), new HTML("[that]"), 384);
     p.add(new HTML("the other"), new HTML("[the other]"), 0);
 
-    // Note the explicit call to layout(). This is required for the layout to
-    // take effect.
-    p.layout();
-
     // Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for
     // resize events on the window to ensure that its children are informed of
     // possible size changes.
     RootLayoutPanel rp = RootLayoutPanel.get();
     rp.add(p);
-
-    // The RootLayoutPanel also requires that its layout() method be explicitly
-    // called for the initial layout to take effect.
-    rp.layout();
   }
 }
diff --git a/user/javadoc/com/google/gwt/examples/TabLayoutPanelExample.java b/user/javadoc/com/google/gwt/examples/TabLayoutPanelExample.java
index 78d1c2e..05ddbb7 100644
--- a/user/javadoc/com/google/gwt/examples/TabLayoutPanelExample.java
+++ b/user/javadoc/com/google/gwt/examples/TabLayoutPanelExample.java
@@ -35,9 +35,5 @@
     // possible size changes.
     RootLayoutPanel rp = RootLayoutPanel.get();
     rp.add(p);
-
-    // The RootLayoutPanel requires that its layout() method be explicitly
-    // called for the initial layout to take effect.
-    rp.layout();
   }
 }
diff --git a/user/src/com/google/gwt/layout/client/Layout.java b/user/src/com/google/gwt/layout/client/Layout.java
index 483a805..c5d9d10 100644
--- a/user/src/com/google/gwt/layout/client/Layout.java
+++ b/user/src/com/google/gwt/layout/client/Layout.java
@@ -449,32 +449,7 @@
    * called after updating any of its children's {@link Layer layers}.
    */
   public void layout() {
-    for (Layer l : layers) {
-      l.left = l.sourceLeft = l.targetLeft;
-      l.top = l.sourceTop = l.targetTop;
-      l.right = l.sourceRight = l.targetRight;
-      l.bottom = l.sourceBottom = l.targetBottom;
-      l.width = l.sourceWidth = l.targetWidth;
-      l.height = l.sourceHeight = l.targetHeight;
-
-      l.setLeft = l.setTargetLeft;
-      l.setTop = l.setTargetTop;
-      l.setRight = l.setTargetRight;
-      l.setBottom = l.setTargetBottom;
-      l.setWidth = l.setTargetWidth;
-      l.setHeight = l.setTargetHeight;
-
-      l.leftUnit = l.targetLeftUnit;
-      l.topUnit = l.targetTopUnit;
-      l.rightUnit = l.targetRightUnit;
-      l.bottomUnit = l.targetBottomUnit;
-      l.widthUnit = l.targetWidthUnit;
-      l.heightUnit = l.targetHeightUnit;
-
-      impl.layout(l);
-    }
-
-    impl.finalizeLayout(parentElem);
+    layout(0);
   }
 
   /**
@@ -495,6 +470,41 @@
    * @param callback the animation callback
    */
   public void layout(int duration, final AnimationCallback callback) {
+    // If there's no actual animation going on, don't do any of the expensive
+    // constraint calculations or anything like that.
+    if (duration == 0) {
+      for (Layer l : layers) {
+        l.left = l.sourceLeft = l.targetLeft;
+        l.top = l.sourceTop = l.targetTop;
+        l.right = l.sourceRight = l.targetRight;
+        l.bottom = l.sourceBottom = l.targetBottom;
+        l.width = l.sourceWidth = l.targetWidth;
+        l.height = l.sourceHeight = l.targetHeight;
+
+        l.setLeft = l.setTargetLeft;
+        l.setTop = l.setTargetTop;
+        l.setRight = l.setTargetRight;
+        l.setBottom = l.setTargetBottom;
+        l.setWidth = l.setTargetWidth;
+        l.setHeight = l.setTargetHeight;
+
+        l.leftUnit = l.targetLeftUnit;
+        l.topUnit = l.targetTopUnit;
+        l.rightUnit = l.targetRightUnit;
+        l.bottomUnit = l.targetBottomUnit;
+        l.widthUnit = l.targetWidthUnit;
+        l.heightUnit = l.targetHeightUnit;
+
+        impl.layout(l);
+      }
+
+      impl.finalizeLayout(parentElem);
+      if (callback != null) {
+        callback.onAnimationComplete();
+      }
+      return;
+    }
+
     // Deal with constraint changes (e.g. left-width => right-width, etc)
     int parentWidth = parentElem.getClientWidth();
     int parentHeight = parentElem.getClientHeight();
diff --git a/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java
index 71dd0ac..836a762 100644
--- a/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/DockLayoutPanelParser.java
@@ -83,9 +83,6 @@
             childFieldName);
       }
     }
-
-    // Emit the layout() call.
-    writer.addStatement("%s.layout();", fieldName);
   }
 
   private String addMethodName(XMLElement elem) {
diff --git a/user/src/com/google/gwt/uibinder/parsers/StackLayoutPanelParser.java b/user/src/com/google/gwt/uibinder/parsers/StackLayoutPanelParser.java
index 00395c9..d7081a9 100644
--- a/user/src/com/google/gwt/uibinder/parsers/StackLayoutPanelParser.java
+++ b/user/src/com/google/gwt/uibinder/parsers/StackLayoutPanelParser.java
@@ -73,9 +73,6 @@
       writer.addStatement("%s.add(%s, %s, %s);", fieldName, childFieldName,
           headerFieldName, size);
     }
-
-    // Emit the layout() call.
-    writer.addStatement("%s.layout();", fieldName);
   }
 
   private boolean isElementType(XMLElement parent, XMLElement child, String type) {
diff --git a/user/src/com/google/gwt/user/client/ui/AnimatedLayout.java b/user/src/com/google/gwt/user/client/ui/AnimatedLayout.java
new file mode 100644
index 0000000..6ad86ba
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/AnimatedLayout.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2009 Google 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 com.google.gwt.user.client.ui;
+
+import com.google.gwt.layout.client.Layout.AnimationCallback;
+
+/**
+ * Specifies that a panel can animate between layouts.
+ * 
+ * <p>
+ * The normal use pattern is to set all childrens' positions, then to call
+ * {@link #animate(int)} to move them to their new positions over some period
+ * of time.
+ * </p>
+ */
+public interface AnimatedLayout {
+
+  /**
+   * Layout children, animating over the specified period of time.
+   * 
+   * @param duration the animation duration, in milliseconds
+   */
+  void animate(int duration);
+
+  /**
+   * Layout children, animating over the specified period of time.
+   * 
+   * <p>
+   * This method provides a callback that will be informed of animation updates.
+   * This can be used to create more complex animation effects.
+   * </p>
+   * 
+   * @param duration the animation duration, in milliseconds
+   * @param callback the animation callback
+   */
+  void animate(final int duration, final AnimationCallback callback);
+
+  /**
+   * Layout children immediately.
+   * 
+   * <p>
+   * This is not normally necessary, unless you want to update child widgets'
+   * positions explicitly to create a starting point for a subsequent call to
+   * {@link #animate(int)}.
+   * </p>
+   * 
+   * @see #animate(int)
+   * @see #animate(int, AnimationCallback)
+   */
+  void forceLayout();
+}
diff --git a/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
index f34524b..b339f15 100644
--- a/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/DockLayoutPanel.java
@@ -26,15 +26,8 @@
  * allows its last widget to take up the remaining space in its center.
  * 
  * <p>
- * Whenever children are added to, or removed from, this panel, you must call
- * one of {@link #layout()}, {@link #layout(int)}, or
- * {@link #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)}
- * to update the panel's layout.
- * </p>
- * 
- * <p>
- * This widget will <em>only</em> work in standards mode, which requires
- * that the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
+ * This widget will <em>only</em> work in standards mode, which requires that
+ * the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
  * declaration.
  * </p>
  * 
@@ -50,12 +43,12 @@
  * 
  * TODO(jgw): RTL support.
  */
-public class DockLayoutPanel extends ComplexPanel implements RequiresLayout,
+public class DockLayoutPanel extends ComplexPanel implements AnimatedLayout,
     RequiresResize, ProvidesResize {
 
   /**
-   * Used in {@link DockLayoutPanel#addEast(Widget, double)} et al to
-   * specify the direction in which a child widget will be added.
+   * Used in {@link DockLayoutPanel#addEast(Widget, double)} et al to specify
+   * the direction in which a child widget will be added.
    */
   public enum Direction {
     NORTH, EAST, SOUTH, WEST, CENTER, LINE_START, LINE_END
@@ -78,9 +71,21 @@
     }
   }
 
+  private class DockAnimateCommand extends LayoutCommand {
+    public DockAnimateCommand(Layout layout) {
+      super(layout);
+    }
+
+    @Override
+    protected void doBeforeLayout() {
+      doLayout();
+    }
+  }
+
   private final Unit unit;
   private Widget center;
   private final Layout layout;
+  private final LayoutCommand animCmd;
 
   /**
    * Creates an empty dock panel.
@@ -92,6 +97,7 @@
 
     setElement(Document.get().createDivElement());
     layout = new Layout(getElement());
+    animCmd = new DockAnimateCommand(layout);
   }
 
   /**
@@ -145,43 +151,50 @@
     insert(widget, Direction.WEST, size, null);
   }
 
+  public void animate(int duration) {
+    animate(0, null);
+  }
+
+  public void animate(int duration, final Layout.AnimationCallback callback) {
+    animCmd.schedule(duration, callback);
+  }
+
+  public void forceLayout() {
+    animCmd.cancel();
+    doLayout();
+    layout.layout();
+    onResize();
+  }
+
   /**
-   * Gets the container element associated with the given child widget.
+   * Gets the container element wrapping the given child widget.
    * 
-   * <p>
-   * The container element is created by the {@link Layout} class. This should
-   * be used with certain styles, such as
-   * {@link com.google.gwt.dom.client.Style#setZIndex(int)}, that must be
-   * applied to the container, rather than directly to the child widget.
-   * </p>
-   * 
-   * TODO(jgw): Is this really the best way to do this?
-   * 
-   * @param widget the widget whose container element is to be retrieved
+   * @param child
    * @return the widget's container element
    */
-  public Element getContainerElementFor(Widget widget) {
-    assertIsChild(widget);
-    return ((LayoutData) widget.getLayoutData()).layer.getContainerElement();
+  public Element getWidgetContainerElement(Widget child) {
+    assertIsChild(child);
+    return ((LayoutData) child.getLayoutData()).layer.getContainerElement();
   }
 
   /**
    * Gets the layout direction of the given child widget.
    * 
-   * @param w the widget to be queried
+   * @param child the widget to be queried
    * @return the widget's layout direction, or <code>null</code> if it is not a
    *         child of this panel
    */
-  public Direction getWidgetDirection(Widget w) {
-    if (w.getParent() != this) {
+  public Direction getWidgetDirection(Widget child) {
+    assertIsChild(child);
+    if (child.getParent() != this) {
       return null;
     }
-    return ((LayoutData) w.getLayoutData()).direction;
+    return ((LayoutData) child.getLayoutData()).direction;
   }
 
   /**
-   * Adds a widget to the east edge of the dock, inserting it before an
-   * existing widget.
+   * Adds a widget to the east edge of the dock, inserting it before an existing
+   * widget.
    * 
    * @param widget the widget to be added
    * @param size the child widget's size
@@ -219,8 +232,8 @@
   }
 
   /**
-   * Adds a widget to the west edge of the dock, inserting it before an
-   * existing widget.
+   * Adds a widget to the west edge of the dock, inserting it before an existing
+   * widget.
    * 
    * @param widget the widget to be added
    * @param size the child widget's size
@@ -231,83 +244,6 @@
     insert(widget, Direction.WEST, size, before);
   }
 
-  public void layout() {
-    layout(0);
-  }
-
-  public void layout(int duration) {
-    layout(0, null);
-  }
-
-  public void layout(int duration, final Layout.AnimationCallback callback) {
-    int left = 0, top = 0, right = 0, bottom = 0;
-
-    for (Widget child : getChildren()) {
-      LayoutData data = (LayoutData) child.getLayoutData();
-      Layer layer = data.layer;
-
-      switch (data.direction) {
-        case NORTH:
-          layer.setLeftRight(left, unit, right, unit);
-          layer.setTopHeight(top, unit, data.size, unit);
-          top += data.size;
-          break;
-
-        case SOUTH:
-          layer.setLeftRight(left, unit, right, unit);
-          layer.setBottomHeight(bottom, unit, data.size, unit);
-          bottom += data.size;
-          break;
-
-        case WEST:
-          layer.setTopBottom(top, unit, bottom, unit);
-          layer.setLeftWidth(left, unit, data.size, unit);
-          left += data.size;
-          break;
-
-        case EAST:
-          layer.setTopBottom(top, unit, bottom, unit);
-          layer.setRightWidth(right, unit, data.size, unit);
-          right += data.size;
-          break;
-
-        case CENTER:
-          layer.setLeftRight(left, unit, right, unit);
-          layer.setTopBottom(top, unit, bottom, unit);
-          break;
-      }
-    }
-
-    layout.layout(duration, new Layout.AnimationCallback() {
-      public void onAnimationComplete() {
-        for (Widget child : getChildren()) {
-          LayoutData data = (LayoutData) child.getLayoutData();
-          if (data.size != data.oldSize) {
-            data.oldSize = data.size;
-            if (child instanceof RequiresResize) {
-              ((RequiresResize) child).onResize();
-            }
-          }
-
-          if (callback != null) {
-            callback.onAnimationComplete();
-          }
-        }
-      }
-
-      public void onLayout(Layer layer, double progress) {
-        Widget child = (Widget) layer.getUserObject();
-        if (child instanceof RequiresResize) {
-          ((RequiresResize) child).onResize();
-        }
-
-        if (callback != null) {
-          callback.onLayout(layer, progress);
-        }
-      }
-    });
-  }
-
   public void onResize() {
     for (Widget child : getChildren()) {
       if (child instanceof RequiresResize) {
@@ -378,6 +314,9 @@
 
     // Adopt.
     adopt(widget);
+
+    // Update the layout.
+    animate(0);
   }
 
   @Override
@@ -393,4 +332,44 @@
   private void assertIsChild(Widget widget) {
     assert (widget == null) || (widget.getParent() == this) : "The specified widget is not a child of this panel";
   }
+
+  private void doLayout() {
+    int left = 0, top = 0, right = 0, bottom = 0;
+
+    for (Widget child : getChildren()) {
+      LayoutData data = (LayoutData) child.getLayoutData();
+      Layer layer = data.layer;
+
+      switch (data.direction) {
+        case NORTH:
+          layer.setLeftRight(left, unit, right, unit);
+          layer.setTopHeight(top, unit, data.size, unit);
+          top += data.size;
+          break;
+
+        case SOUTH:
+          layer.setLeftRight(left, unit, right, unit);
+          layer.setBottomHeight(bottom, unit, data.size, unit);
+          bottom += data.size;
+          break;
+
+        case WEST:
+          layer.setTopBottom(top, unit, bottom, unit);
+          layer.setLeftWidth(left, unit, data.size, unit);
+          left += data.size;
+          break;
+
+        case EAST:
+          layer.setTopBottom(top, unit, bottom, unit);
+          layer.setRightWidth(right, unit, data.size, unit);
+          right += data.size;
+          break;
+
+        case CENTER:
+          layer.setLeftRight(left, unit, right, unit);
+          layer.setTopBottom(top, unit, bottom, unit);
+          break;
+      }
+    }
+  }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/LayoutCommand.java b/user/src/com/google/gwt/user/client/ui/LayoutCommand.java
new file mode 100644
index 0000000..9de09d2
--- /dev/null
+++ b/user/src/com/google/gwt/user/client/ui/LayoutCommand.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2009 Google 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 com.google.gwt.user.client.ui;
+
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.layout.client.Layout;
+import com.google.gwt.layout.client.Layout.AnimationCallback;
+import com.google.gwt.layout.client.Layout.Layer;
+
+/**
+ * A scheduled command used by animated layouts to ensure that only layout is
+ * ever performed for a panel within a given user event.
+ * 
+ * <p>
+ * Note: This class assumes that {@link Layout.Layer#getUserObject()} will
+ * return the widget associated with a given layer.
+ * </p>
+ */
+public class LayoutCommand implements ScheduledCommand {
+
+  private boolean scheduled, canceled;
+  private int duration;
+  private Layout.AnimationCallback callback;
+  private final Layout layout;
+
+  /**
+   * Creates a new command for the given layout object
+   * 
+   * @param layout
+   */
+  public LayoutCommand(Layout layout) {
+    this.layout = layout;
+  }
+
+  public final void execute() {
+    if (canceled) {
+      return;
+    }
+
+    scheduled = false;
+
+    doBeforeLayout();
+
+    layout.layout(duration, new Layout.AnimationCallback() {
+      public void onAnimationComplete() {
+        // Chain to the passed callback.
+        if (callback != null) {
+          callback.onAnimationComplete();
+        }
+      }
+
+      public void onLayout(Layer layer, double progress) {
+        // Inform the child associated with this layer that its size may
+        // have changed.
+        Widget child = (Widget) layer.getUserObject();
+        if (child instanceof RequiresResize) {
+          ((RequiresResize) child).onResize();
+        }
+
+        // Chain to the passed callback.
+        if (callback != null) {
+          callback.onLayout(layer, progress);
+        }
+      }
+    });
+  }
+
+  /**
+   * Called before the layout is executed. Override this method to perform any
+   * work that needs to happen just before it.
+   */
+  protected void doBeforeLayout() {
+  }
+
+  /**
+   * Schedules a layout. The duration and callback passed to this method will
+   * supercede any previous call that has not yet been executed.
+   * 
+   * @param duration
+   * @param callback
+   */
+  public void schedule(int duration, AnimationCallback callback) {
+    this.duration = duration;
+    this.callback = callback;
+
+    canceled = false;
+    if (!scheduled) {
+      scheduled = true;
+      Scheduler.get().scheduleFinally(this);
+    }
+  }
+
+  /**
+   * Cancels this command. A subsequent call to
+   * {@link #schedule(int, AnimationCallback)} will re-enable it.
+   */
+  public void cancel() {
+    // There's no way to "unschedule" a command, so we use a canceled flag.
+    canceled = true;
+  }
+}
diff --git a/user/src/com/google/gwt/user/client/ui/LayoutPanel.java b/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
index 637c904..452c0db 100644
--- a/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/LayoutPanel.java
@@ -16,7 +16,11 @@
 package com.google.gwt.user.client.ui;
 
 import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.Style.Unit;
 import com.google.gwt.layout.client.Layout;
+import com.google.gwt.layout.client.Layout.Alignment;
+import com.google.gwt.layout.client.Layout.AnimationCallback;
 import com.google.gwt.layout.client.Layout.Layer;
 
 /**
@@ -25,13 +29,6 @@
  * {@link Layout} class.
  * 
  * <p>
- * Whenever children are added to, or removed from, this panel, you must call
- * one of {@link #layout()}, {@link #layout(int)}, or
- * {@link #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)}
- * to update the panel's layout.
- * </p>
- * 
- * <p>
  * This widget will <em>only</em> work in standards mode, which requires that
  * the HTML page in which it is run have an explicit &lt;!DOCTYPE&gt;
  * declaration.
@@ -46,13 +43,12 @@
  * <h3>Example</h3>
  * {@example com.google.gwt.examples.LayoutPanelExample}
  * </p>
- * 
- * TODO: implements IndexedPanel (I think)
  */
-public class LayoutPanel extends ComplexPanel implements RequiresLayout,
+public class LayoutPanel extends ComplexPanel implements AnimatedLayout,
     RequiresResize, ProvidesResize {
 
   private final Layout layout;
+  private final LayoutCommand animCmd;
 
   /**
    * Creates an empty layout panel.
@@ -60,6 +56,7 @@
   public LayoutPanel() {
     setElement(Document.get().createDivElement());
     layout = new Layout(getElement());
+    animCmd = new LayoutCommand(layout);
   }
 
   /**
@@ -67,9 +64,9 @@
    * 
    * <p>
    * By default, each child will fill the panel. To build more interesting
-   * layouts, use {@link #getLayer(Widget)} to get the
-   * {@link com.google.gwt.layout.client.Layout.Layer} associated with each
-   * child, and set its layout constraints as desired.
+   * layouts, set child widgets' layout constraints using
+   * {@link #setWidgetLeftRight(Widget, double, Unit, double, Unit)} and related
+   * methods.
    * </p>
    * 
    * @param widget the widget to be added
@@ -78,23 +75,29 @@
     insert(widget, getWidgetCount());
   }
 
+  public void animate(int duration) {
+    animate(duration, null);
+  }
+
+  public void animate(final int duration, final AnimationCallback callback) {
+    animCmd.schedule(duration, callback);
+  }
+
+  public void forceLayout() {
+    animCmd.cancel();
+    layout.layout();
+    onResize();
+  }
+
   /**
-   * Gets the {@link Layer} associated with the given widget. This layer may be
-   * used to manipulate the child widget's layout constraints.
+   * Gets the container element wrapping the given child widget.
    * 
-   * <p>
-   * After you have made changes to any of the child widgets' constraints, you
-   * must call one of the {@link RequiresLayout} methods for those changes to
-   * be reflected visually.
-   * </p>
-   * 
-   * @param child the child widget whose layer is to be retrieved
-   * @return the associated layer
+   * @param child
+   * @return the widget's container element
    */
-  public Layout.Layer getLayer(Widget child) {
-    assert child.getParent() == this :
-      "The requested widget is not a child of this panel";
-    return (Layout.Layer) child.getLayoutData();
+  public Element getWidgetContainerElement(Widget child) {
+    assertIsChild(child);
+    return getLayer(child).getContainerElement();
   }
 
   /**
@@ -102,9 +105,9 @@
    * 
    * <p>
    * By default, each child will fill the panel. To build more interesting
-   * layouts, use {@link #getLayer(Widget)} to get the
-   * {@link com.google.gwt.layout.client.Layout.Layer} associated with each
-   * child, and set its layout constraints as desired.
+   * layouts, set child widgets' layout constraints using
+   * {@link #setWidgetLeftRight(Widget, double, Unit, double, Unit)} and related
+   * methods.
    * </p>
    * 
    * <p>
@@ -131,39 +134,8 @@
 
     // Adopt.
     adopt(widget);
-  }
 
-  public void layout() {
-    layout.layout();
-  }
-
-  public void layout(int duration) {
-    layout.layout(duration);
-  }
-
-  public void layout(int duration, final Layout.AnimationCallback callback) {
-    layout.layout(duration, new Layout.AnimationCallback() {
-      public void onAnimationComplete() {
-        // Chain to the passed callback.
-        if (callback != null) {
-          callback.onAnimationComplete();
-        }
-      }
-
-      public void onLayout(Layer layer, double progress) {
-        // Inform the child associated with this layer that its size may have
-        // changed.
-        Widget child = (Widget) layer.getUserObject();
-        if (child instanceof RequiresResize) {
-          ((RequiresResize) child).onResize();
-        }
-
-        // Chain to the passed callback.
-        if (callback != null) {
-          callback.onLayout(layer, progress);
-        }
-      }
-    });
+    animate(0);
   }
 
   public void onResize() {
@@ -184,12 +156,123 @@
   }
 
   /**
-   * Gets the {@link Layout} instance associated with this widget.
+   * Sets the child widget's bottom and height values.
    * 
-   * @return this widget's layout instance
+   * @param child
+   * @param bottom
+   * @param bottomUnit
+   * @param height
+   * @param heightUnit
    */
-  protected Layout getLayout() {
-    return layout;
+  public void setWidgetBottomHeight(Widget child, double bottom,
+      Unit bottomUnit, double height, Unit heightUnit) {
+    assertIsChild(child);
+    getLayer(child).setBottomHeight(bottom, bottomUnit, height, heightUnit);
+    animate(0);
+  }
+
+  /**
+   * Sets the child widget's horizontal position within its layer.
+   * 
+   * @param child
+   * @param position
+   */
+  public void setWidgetHorizontalPosition(Widget child, Alignment position) {
+    assertIsChild(child);
+    getLayer(child).setChildHorizontalPosition(position);
+    animate(0);
+  }
+
+  /**
+   * Sets the child widget's left and right values.
+   * 
+   * @param child
+   * @param left
+   * @param leftUnit
+   * @param right
+   * @param rightUnit
+   */
+  public void setWidgetLeftRight(Widget child, double left, Unit leftUnit,
+      double right, Unit rightUnit) {
+    assertIsChild(child);
+    getLayer(child).setLeftRight(left, leftUnit, right, rightUnit);
+    animate(0);
+  }
+
+  /**
+   * Sets the child widget's left and width values.
+   * 
+   * @param child
+   * @param left
+   * @param leftUnit
+   * @param width
+   * @param widthUnit
+   */
+  public void setWidgetLeftWidth(Widget child, double left, Unit leftUnit,
+      double width, Unit widthUnit) {
+    assertIsChild(child);
+    getLayer(child).setLeftWidth(left, leftUnit, width, widthUnit);
+    animate(0);
+  }
+
+  /**
+   * Sets the child widget's right and width values.
+   * 
+   * @param child
+   * @param right
+   * @param rightUnit
+   * @param width
+   * @param widthUnit
+   */
+  public void setWidgetRightWidth(Widget child, double right, Unit rightUnit,
+      double width, Unit widthUnit) {
+    assertIsChild(child);
+    getLayer(child).setRightWidth(right, rightUnit, width, widthUnit);
+    animate(0);
+  }
+
+  /**
+   * Sets the child widget's top and bottom values.
+   * 
+   * @param child
+   * @param top
+   * @param topUnit
+   * @param bottom
+   * @param bottomUnit
+   */
+  public void setWidgetTopBottom(Widget child, double top, Unit topUnit,
+      double bottom, Unit bottomUnit) {
+    assertIsChild(child);
+    getLayer(child).setTopBottom(top, topUnit, bottom, bottomUnit);
+    animate(0);
+  }
+
+  /**
+   * Sets the child widget's top and height values.
+   * 
+   * @param child
+   * @param top
+   * @param topUnit
+   * @param height
+   * @param heightUnit
+   */
+  public void setWidgetTopHeight(Widget child, double top, Unit topUnit,
+      double height, Unit heightUnit) {
+    assertIsChild(child);
+    getLayer(child).setTopHeight(top, topUnit, height, heightUnit);
+    animate(0);
+  }
+
+  /**
+   * Sets the child widget's vertical position within its layer.
+   * 
+   * @param child
+   * @param position
+   */
+  public void setWidgetVerticalPosition(Widget child, Alignment position) {
+    assertIsChild(child);
+    getLayer(child).setChildVerticalPosition(position);
+    animate(0);
   }
 
   @Override
@@ -201,4 +284,23 @@
   protected void onUnload() {
     layout.onDetach();
   }
+
+  /**
+   * Gets the {@link Layout} instance associated with this widget. This is made
+   * package-protected for use by {@link RootLayoutPanel}.
+   * 
+   * @return this widget's layout instance
+   */
+  Layout getLayout() {
+    return layout;
+  }
+
+  private void assertIsChild(Widget widget) {
+    assert (widget == null) || (widget.getParent() == this) : "The specified widget is not a child of this panel";
+  }
+
+  private Layout.Layer getLayer(Widget child) {
+    assert child.getParent() == this : "The requested widget is not a child of this panel";
+    return (Layout.Layer) child.getLayoutData();
+  }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/RequiresLayout.java b/user/src/com/google/gwt/user/client/ui/RequiresLayout.java
deleted file mode 100644
index 680c9a6..0000000
--- a/user/src/com/google/gwt/user/client/ui/RequiresLayout.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2009 Google 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 com.google.gwt.user.client.ui;
-
-import com.google.gwt.layout.client.Layout;
-
-/**
- * Designates that a widget requires a method to be explicitly called after its
- * children are modified.
- * 
- * <p>
- * Widgets that implement this interface perform some layout work that will not
- * be fully realized until {@link #layout()} or one of its overloads is called.
- * This is required after adding or removing child widgets, and after any other
- * operations that the implementor designates as requiring layout. Note that
- * only <em>one</em> call to {@link #layout()} is required after any number of
- * modifications.
- * </p>
- */
-public interface RequiresLayout {
-
-  /**
-   * Layout children immediately.
-   * 
-   * @see #layout(int)
-   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
-   */
-  void layout();
-
-  /**
-   * Layout children, animating over the specified period of time.
-   * 
-   * @param duration the animation duration, in milliseconds
-   * 
-   * @see #layout()
-   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
-   */
-  void layout(int duration);
-
-  /**
-   * Layout children, animating over the specified period of time.
-   * 
-   * <p>
-   * This method provides a callback that will be informed of animation updates.
-   * This can be used to create more complex animation effects.
-   * </p>
-   * 
-   * @param duration the animation duration, in milliseconds
-   * @param callback the animation callback
-   * 
-   * @see #layout()
-   * @see #layout(int, com.google.gwt.layout.client.Layout.AnimationCallback)
-   */
-  void layout(int duration, final Layout.AnimationCallback callback);
-}
diff --git a/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
index 0af2857..c1c13a2 100644
--- a/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/SplitLayoutPanel.java
@@ -173,7 +173,7 @@
         layoutCommand = new Command() {
           public void execute() {
             layoutCommand = null;
-            layout();
+            forceLayout();
           }
         };
         DeferredCommand.addCommand(layoutCommand);
diff --git a/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
index a280d32..6298394 100644
--- a/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/StackLayoutPanel.java
@@ -15,9 +15,9 @@
  */
 package com.google.gwt.user.client.ui;
 
+import com.google.gwt.core.client.Scheduler;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
 import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.layout.client.Layout.AnimationCallback;
-import com.google.gwt.layout.client.Layout.Layer;
 import com.google.gwt.user.client.Event;
 
 import java.util.ArrayList;
@@ -52,7 +52,7 @@
  * - default style.
  */
 public class StackLayoutPanel extends Composite implements HasWidgets,
-    RequiresLayout, RequiresResize, ProvidesResize {
+    RequiresResize, ProvidesResize {
 
   private class ClickWrapper extends Composite {
     private Widget target;
@@ -75,16 +75,11 @@
     public double headerSize;
     public Widget header;
     public Widget widget;
-    public Layer widgetLayer;
-    public Layer headerLayer;
 
-    public LayoutData(Widget widget, Widget header, double headerSize,
-        Layer widgetLayer, Layer headerLayer) {
+    public LayoutData(Widget widget, Widget header, double headerSize) {
       this.widget = widget;
       this.header = header;
       this.headerSize = headerSize;
-      this.widgetLayer = widgetLayer;
-      this.headerLayer = headerLayer;
     }
   }
 
@@ -122,18 +117,15 @@
     layoutPanel.add(wrapper);
     layoutPanel.add(widget);
 
-    Layer headerLayer = layoutPanel.getLayer(wrapper);
-    headerLayer.setLeftRight(0, Unit.PX, 0, Unit.PX);
+    layoutPanel.setWidgetLeftRight(wrapper, 0, Unit.PX, 0, Unit.PX);
+    layoutPanel.setWidgetLeftRight(widget, 0, Unit.PX, 0, Unit.PX);
 
-    Layer widgetLayer = layoutPanel.getLayer(widget);
-    widgetLayer.setLeftRight(0, Unit.PX, 0, Unit.PX);
-
-    LayoutData data = new LayoutData(widget, wrapper, headerSize, widgetLayer,
-        headerLayer);
+    LayoutData data = new LayoutData(widget, wrapper, headerSize);
     layoutData.add(data);
 
     if (visibleWidget == null) {
-      visibleWidget = widget;
+      // Don't animate the initial widget display.
+      showWidget(widget, 0);
     }
   }
 
@@ -169,46 +161,6 @@
     };
   }
 
-  public void layout() {
-    layout(0);
-  }
-
-  public void layout(int duration) {
-    layout(duration, null);
-  }
-
-  public void layout(int duration, AnimationCallback callback) {
-    int top = 0, bottom = 0;
-    int i = 0, visibleIndex = -1;
-    for (; i < layoutData.size(); ++i) {
-      LayoutData data = layoutData.get(i);
-      data.headerLayer.setTopHeight(top, unit, data.headerSize, unit);
-
-      top += data.headerSize;
-
-      data.widgetLayer.setTopHeight(top, unit, 0, unit);
-
-      if (data.widget == visibleWidget) {
-        visibleIndex = i;
-        break;
-      }
-    }
-
-    assert visibleIndex != -1;
-
-    for (int j = layoutData.size() - 1; j > i; --j) {
-      LayoutData data = layoutData.get(j);
-      data.headerLayer.setBottomHeight(bottom, unit, data.headerSize, unit);
-      data.widgetLayer.setBottomHeight(bottom, unit, 0, unit);
-      bottom += data.headerSize;
-    }
-
-    LayoutData data = layoutData.get(visibleIndex);
-    data.widgetLayer.setTopBottom(top, unit, bottom, unit);
-
-    layoutPanel.layout(duration, callback);
-  }
-
   public void onResize() {
     layoutPanel.onResize();
   }
@@ -230,7 +182,49 @@
    * @param widget the child widget to be shown.
    */
   public void showWidget(Widget widget) {
+    showWidget(widget, ANIMATION_TIME);
+  }
+
+  private void animate(int duration) {
+    int top = 0, bottom = 0;
+    int i = 0, visibleIndex = -1;
+    for (; i < layoutData.size(); ++i) {
+      LayoutData data = layoutData.get(i);
+      layoutPanel.setWidgetTopHeight(data.header, top, unit, data.headerSize,
+          unit);
+
+      top += data.headerSize;
+
+      layoutPanel.setWidgetTopHeight(data.widget, top, unit, 0, unit);
+
+      if (data.widget == visibleWidget) {
+        visibleIndex = i;
+        break;
+      }
+    }
+
+    assert visibleIndex != -1;
+
+    for (int j = layoutData.size() - 1; j > i; --j) {
+      LayoutData data = layoutData.get(j);
+      layoutPanel.setWidgetBottomHeight(data.header, bottom, unit,
+          data.headerSize, unit);
+      layoutPanel.setWidgetBottomHeight(data.widget, bottom, unit, 0, unit);
+      bottom += data.headerSize;
+    }
+
+    LayoutData data = layoutData.get(visibleIndex);
+    layoutPanel.setWidgetTopBottom(data.widget, top, unit, bottom, unit);
+
+    layoutPanel.animate(duration);
+  }
+
+  private void showWidget(Widget widget, final int duration) {
     visibleWidget = widget;
-    layout(ANIMATION_TIME);
+    Scheduler.get().scheduleFinally(new ScheduledCommand() {
+      public void execute() {
+        animate(duration);
+      }
+    });
   }
 }
diff --git a/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
index cf72920..4335fc3 100644
--- a/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
+++ b/user/src/com/google/gwt/user/client/ui/TabLayoutPanel.java
@@ -29,7 +29,6 @@
 import com.google.gwt.event.logical.shared.SelectionHandler;
 import com.google.gwt.event.shared.HandlerRegistration;
 import com.google.gwt.layout.client.Layout.Alignment;
-import com.google.gwt.layout.client.Layout.Layer;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -60,8 +59,8 @@
  * - Update style mechanism (gwt-Tab, etc. not really sufficient).
  */
 public class TabLayoutPanel extends LayoutComposite implements HasWidgets,
-    ProvidesResize, IndexedPanel,
-    HasBeforeSelectionHandlers<Integer>, HasSelectionHandlers<Integer> {
+    ProvidesResize, IndexedPanel, HasBeforeSelectionHandlers<Integer>,
+    HasSelectionHandlers<Integer> {
 
   private static final int BIG_ENOUGH_TO_NOT_WRAP = 16384;
 
@@ -127,12 +126,9 @@
     initWidget(panel);
 
     panel.add(tabBar);
-    Layer layer = panel.getLayer(tabBar);
-    layer.setLeftRight(0, Unit.PX, 0, Unit.PX);
-    layer.setTopHeight(0, Unit.PX, barHeight, barUnit);
-    panel.layout();
-
-    panel.getLayer(tabBar).setChildVerticalPosition(Alignment.END);
+    panel.setWidgetLeftRight(tabBar, 0, Unit.PX, 0, Unit.PX);
+    panel.setWidgetTopHeight(tabBar, 0, Unit.PX, barHeight, barUnit);
+    panel.setWidgetVerticalPosition(tabBar, Alignment.END);
 
     // Make the tab bar extremely wide so that tabs themselves never wrap.
     // (Its layout container is overflow:hidden)
@@ -356,13 +352,13 @@
 
     // Update the tabs being selected and unselected.
     if (selectedIndex != -1) {
-      Layer layer = panel.getLayer(children.get(selectedIndex));
-      layer.getContainerElement().getStyle().setVisibility(Visibility.HIDDEN);
+      Element container = panel.getWidgetContainerElement(children.get(selectedIndex));
+      container.getStyle().setVisibility(Visibility.HIDDEN);
       tabs.get(selectedIndex).setSelected(false);
     }
 
-    Layer layer = panel.getLayer(children.get(index));
-    layer.getContainerElement().getStyle().setVisibility(Visibility.VISIBLE);
+    Element container = panel.getWidgetContainerElement(children.get(index));
+    container.getStyle().setVisibility(Visibility.VISIBLE);
     tabs.get(index).setSelected(true);
     selectedIndex = index;
 
@@ -445,10 +441,9 @@
   }
 
   private void layoutChild(Widget child) {
-    Layer layer = panel.getLayer(child);
-    layer.setLeftRight(0, Unit.PX, 0, Unit.PX);
-    layer.setTopBottom(barHeight, barUnit, 0, Unit.PX);
-    layer.getContainerElement().getStyle().setVisibility(Visibility.HIDDEN);
-    panel.layout();
+    panel.setWidgetLeftRight(child, 0, Unit.PX, 0, Unit.PX);
+    panel.setWidgetTopBottom(child, barHeight, barUnit, 0, Unit.PX);
+    panel.getWidgetContainerElement(child).getStyle().setVisibility(
+        Visibility.HIDDEN);
   }
 }