Adds class to manage layout of the launcher and status area. When
entering fullscreen the shelf is hidden and exiting makes the shelf
visible. Transitions are animated, but it likely needs some tweaks.

BUG=none
TEST=none
[email protected]

Review URL: http://codereview.chromium.org/8475012

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108877 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/ui/aura_shell/shelf_layout_controller.cc b/ui/aura_shell/shelf_layout_controller.cc
new file mode 100644
index 0000000..9e8d01a
--- /dev/null
+++ b/ui/aura_shell/shelf_layout_controller.cc
@@ -0,0 +1,118 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/aura_shell/shelf_layout_controller.h"
+
+#include "ui/aura/desktop.h"
+#include "ui/aura/screen_aura.h"
+#include "ui/gfx/compositor/layer.h"
+#include "ui/gfx/compositor/layer_animator.h"
+#include "views/widget/widget.h"
+
+namespace aura_shell {
+namespace internal {
+
+namespace {
+
+ui::Layer* GetLayer(views::Widget* widget) {
+  return widget->GetNativeView()->layer();
+}
+
+}  // namespace
+
+ShelfLayoutController::ShelfLayoutController(views::Widget* launcher,
+                                             views::Widget* status)
+    : animating_(false),
+      visible_(true),
+      max_height_(-1),
+      launcher_(launcher),
+      status_(status) {
+  gfx::Rect launcher_bounds = launcher->GetWindowScreenBounds();
+  gfx::Rect status_bounds = status->GetWindowScreenBounds();
+  max_height_ = std::max(launcher_bounds.height(), status_bounds.height());
+  GetLayer(launcher)->GetAnimator()->AddObserver(this);
+}
+
+ShelfLayoutController::~ShelfLayoutController() {
+  GetLayer(launcher_)->GetAnimator()->RemoveObserver(this);
+}
+
+void ShelfLayoutController::LayoutShelf() {
+  StopAnimating();
+  TargetBounds target_bounds;
+  float target_opacity = visible_ ? 1.0f : 0.0f;
+  CalculateTargetBounds(visible_, &target_bounds);
+  GetLayer(launcher_)->SetOpacity(target_opacity);
+  GetLayer(status_)->SetOpacity(target_opacity);
+  launcher_->SetBounds(target_bounds.launcher_bounds);
+  status_->SetBounds(target_bounds.status_bounds);
+  aura::Desktop::GetInstance()->screen()->set_work_area_insets(
+      target_bounds.work_area_insets);
+}
+
+void ShelfLayoutController::SetVisible(bool visible) {
+  bool current_visibility = animating_ ? !visible_ : visible_;
+  if (visible == current_visibility)
+    return;  // Nothing changed.
+
+  StopAnimating();
+
+  TargetBounds target_bounds;
+  float target_opacity = visible ? 1.0f : 0.0f;
+  CalculateTargetBounds(visible, &target_bounds);
+  AnimateWidgetTo(launcher_, target_bounds.launcher_bounds, target_opacity);
+  AnimateWidgetTo(status_, target_bounds.status_bounds, target_opacity);
+  animating_ = true;
+  // |visible_| is updated once the animation completes.
+}
+
+void ShelfLayoutController::StopAnimating() {
+  if (animating_) {
+    animating_ = false;
+    visible_ = !visible_;
+  }
+  GetLayer(launcher_)->GetAnimator()->StopAnimating();
+}
+
+void ShelfLayoutController::CalculateTargetBounds(bool visible,
+                                                  TargetBounds* target_bounds) {
+  const gfx::Rect& available_bounds(aura::Desktop::GetInstance()->bounds());
+  int y = available_bounds.bottom() - (visible ? max_height_ : 0);
+  gfx::Rect status_bounds(status_->GetWindowScreenBounds());
+  target_bounds->status_bounds = gfx::Rect(
+      available_bounds.right() - status_bounds.width(),
+      y + (max_height_ - status_bounds.height()) / 2,
+      status_bounds.width(), status_bounds.height());
+  gfx::Rect launcher_bounds(launcher_->GetWindowScreenBounds());
+  target_bounds->launcher_bounds = gfx::Rect(
+      available_bounds.x(), y + (max_height_ - launcher_bounds.height()) / 2,
+      available_bounds.width() - status_bounds.width(),
+      launcher_bounds.height());
+  if (visible)
+    target_bounds->work_area_insets = gfx::Insets(0, 0, max_height_, 0);
+}
+
+void ShelfLayoutController::AnimateWidgetTo(views::Widget* widget,
+                                            const gfx::Rect& target_bounds,
+                                            float target_opacity) {
+  ui::Layer* layer = GetLayer(widget);
+  ui::LayerAnimator::ScopedSettings animation_setter(layer->GetAnimator());
+  widget->SetBounds(target_bounds);
+  layer->SetOpacity(target_opacity);
+}
+
+void ShelfLayoutController::OnLayerAnimationEnded(
+    const ui::LayerAnimationSequence* sequence) {
+  if (!animating_)
+    return;
+  animating_ = false;
+  visible_ = !visible_;
+  TargetBounds target_bounds;
+  CalculateTargetBounds(visible_, &target_bounds);
+  aura::Desktop::GetInstance()->screen()->set_work_area_insets(
+      target_bounds.work_area_insets);
+}
+
+}  // internal
+}  // aura_shell