13f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
23f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// Use of this source code is governed by a BSD-style license that can be
33f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/panels/panel_scroller.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/compiler_specific.h"
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/logging.h"
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/string_util.h"
113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/utf_string_conversions.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/panels/panel_scroller_container.h"
13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/panels/panel_scroller_header.h"
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/widget/widget.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstruct PanelScroller::Panel {
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PanelScrollerHeader* header;
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PanelScrollerContainer* container;
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPanelScroller::PanelScroller()
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : views::View(),
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      divider_height_(18),
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      needs_layout_(true),
26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      scroll_pos_(0),
27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)),
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animated_scroll_begin_(0),
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animated_scroll_end_(0) {
303f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen  animation_.SetTweenType(ui::Tween::EASE_IN_OUT);
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  animation_.SetSlideDuration(300);
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Panel* panel = new Panel;
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header = new PanelScrollerHeader(this);
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header->set_title(ASCIIToUTF16("Email"));
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->container = new PanelScrollerContainer(this, new views::View());
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panels_.push_back(panel);
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel = new Panel;
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header = new PanelScrollerHeader(this);
41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header->set_title(ASCIIToUTF16("Chat"));
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->container = new PanelScrollerContainer(this, new views::View());
43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panels_.push_back(panel);
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel = new Panel;
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header = new PanelScrollerHeader(this);
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header->set_title(ASCIIToUTF16("Calendar"));
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->container = new PanelScrollerContainer(this, new views::View());
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panels_.push_back(panel);
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel = new Panel;
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header = new PanelScrollerHeader(this);
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header->set_title(ASCIIToUTF16("Recent searches"));
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->container = new PanelScrollerContainer(this, new views::View());
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panels_.push_back(panel);
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel = new Panel;
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header = new PanelScrollerHeader(this);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->header->set_title(ASCIIToUTF16("Pony news"));
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panel->container = new PanelScrollerContainer(this, new views::View());
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  panels_.push_back(panel);
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Add the containers first since they're on the bottom.
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[0]->container);
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[1]->container);
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[2]->container);
67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[3]->container);
68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[4]->container);
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[0]->header);
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[1]->header);
72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[2]->header);
73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[3]->header);
74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(panels_[4]->header);
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPanelScroller::~PanelScroller() {
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  STLDeleteContainerPointers(panels_.begin(), panels_.end());
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
82c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPanelScroller* PanelScroller::CreateWindow() {
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  views::Widget* widget = views::Widget::CreateWidget(
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      views::Widget::CreateParams(views::Widget::CreateParams::TYPE_WINDOW));
85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  widget->Init(NULL, gfx::Rect(0, 0, 100, 800));
86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PanelScroller* scroller = new PanelScroller();
88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  widget->SetContentsView(scroller);
89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  widget->Show();
91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return scroller;
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PanelScroller::ViewHierarchyChanged(bool is_add,
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         views::View* parent,
97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                         views::View* child) {
98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Our child views changed without us knowing it. Stop the animation and mark
99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // us as dirty (needs_layout_ = true).
100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  animation_.Stop();
101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  needs_layout_ = true;
102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size PanelScroller::GetPreferredSize() {
105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Size(75, 200);
106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PanelScroller::Layout() {
109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch/* TODO(brettw) this doesn't work for some reason.
110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (!needs_layout_ || !animation_.IsShowing())
111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  needs_layout_ = false;*/
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The current location in the content that we're laying out. This is before
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // scrolling is accounted for.
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int cur_content_pos = 0;
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Number of pixels used by headers stuck to the top of the scroll area.
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int top_header_pixel_count = 0;
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int panel_count = static_cast<int>(panels_.size());
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < panel_count; i++) {
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (cur_content_pos < scroll_pos_ + top_header_pixel_count) {
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // This panel is at least partially off the top. Put the header below the
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // others already there.
12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      panels_[i]->header->SetBoundsRect(gfx::Rect(0, top_header_pixel_count,
12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                                  width(), divider_height_));
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      top_header_pixel_count += divider_height_;
129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else if (cur_content_pos > height() + scroll_pos_ -
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               (panel_count - i) * divider_height_) {
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // When we've hit the bottom of the visible content, all the remaining
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // headers will stack up at the bottom. Counting this header, there are
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // (size() - i) left, which is used in the expression above.
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      int top = height() - (panel_count - i) * divider_height_;
13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      panels_[i]->header->SetBoundsRect(gfx::Rect(0, top,
13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                                  width(), divider_height_));
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      // Normal header positioning in-flow.
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      panels_[i]->header->SetBoundsRect(
14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen          gfx::Rect(0, cur_content_pos - scroll_pos_, width(),
14272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                    divider_height_));
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cur_content_pos += divider_height_;
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Now position the content. It always goes in-flow ignoring any stacked
148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // up headers at the top or bottom.
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int container_height = panels_[i]->container->GetPreferredSize().height();
15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    panels_[i]->container->SetBoundsRect(
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gfx::Rect(0, cur_content_pos - scroll_pos_,
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  width(), container_height));
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    cur_content_pos += container_height;
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PanelScroller::OnMousePressed(const views::MouseEvent& event) {
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool PanelScroller::OnMouseDragged(const views::MouseEvent& event) {
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PanelScroller::HeaderClicked(PanelScrollerHeader* source) {
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (size_t i = 0; i < panels_.size(); i++) {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (panels_[i]->header == source) {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ScrollToPanel(static_cast<int>(i));
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      return;
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NOTREACHED() << "Invalid panel passed to HeaderClicked.";
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PanelScroller::ScrollToPanel(int index) {
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int affected_panel_height =
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      panels_[index]->container->GetPreferredSize().height();
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The pixel size we need to reserve for the stuck headers.
180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int top_stuck_header_pixel_size = index * divider_height_;
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int bottom_stuck_header_pixel_size =
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      (static_cast<int>(panels_.size()) - index - 1) * divider_height_;
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Compute the offset of the top of the panel to scroll to.
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int space_above = 0;
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < index; i++) {
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    space_above += divider_height_ +
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        panels_[i]->container->GetPreferredSize().height();
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Compute the space below the top of the panel.
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int space_below = 0;
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = index; i < static_cast<int>(panels_.size()); i++) {
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    space_below += divider_height_ +
195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        panels_[i]->container->GetPreferredSize().height();
196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // The scroll position of the top of the stuck headers is the space above
199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // minus the size of the headers stuck there.
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int top_stuck_headers_scroll_pos = space_above - top_stuck_header_pixel_size;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // If the panel is already fully visible, do nothing.
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (scroll_pos_ <= top_stuck_headers_scroll_pos &&
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      space_above + divider_height_ + affected_panel_height -
205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bottom_stuck_header_pixel_size <= scroll_pos_ + height())
206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Compute the scroll position.
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (height() > space_below) {
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // There's enough room for this panel and everything below it to fit on the
211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // screen.
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    animated_scroll_end_ = (space_above + space_below) - height();
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (animated_scroll_end_ > top_stuck_headers_scroll_pos)
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animated_scroll_end_ = top_stuck_headers_scroll_pos;
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else if (space_above > scroll_pos_) {
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // If we're going to be scrolling the content up, scroll just until the
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // panel in question is fully visible.
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    animated_scroll_end_ = space_above +
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        divider_height_ + affected_panel_height +  // Size of this panel.
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        bottom_stuck_header_pixel_size -  // Leave room for these.
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        height();  // Available size in the window.
222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (animated_scroll_end_ > top_stuck_headers_scroll_pos)
223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animated_scroll_end_ = top_stuck_headers_scroll_pos;
224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    animated_scroll_end_ = top_stuck_headers_scroll_pos;
226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  animated_scroll_begin_ = scroll_pos_;
229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (animated_scroll_begin_ == animated_scroll_end_)
230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;  // Nothing to animate.
231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Start animating to the destination.
233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  animation_.Reset();
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  animation_.Show();
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2373f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsenvoid PanelScroller::AnimationProgressed(const ui::Animation* animation) {
238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scroll_pos_ = static_cast<int>(
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      static_cast<double>(animated_scroll_end_ - animated_scroll_begin_) *
240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      animation_.GetCurrentValue()) + animated_scroll_begin_;
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  Layout();
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SchedulePaint();
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
245