172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/tabs/side_tab_strip.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/view_ids.h"
821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/tabs/side_tab.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/tabs/tab_strip_controller.h"
10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/generated_resources.h"
11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "grit/theme_resources.h"
1272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/l10n/l10n_util.h"
1372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/base/resource/resource_bundle.h"
1472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "ui/gfx/canvas.h"
15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/background.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/controls/button/image_button.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/controls/button/text_button.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace {
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kVerticalTabSpacing = 2;
22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kTabStripWidth = 140;
23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kBackgroundColor = SkColorSetARGB(255, 209, 220, 248);
24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst SkColor kSeparatorColor = SkColorSetARGB(255, 151, 159, 179);
25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Height of the scroll buttons.
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kScrollButtonHeight = 20;
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Height of the separator.
30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int kSeparatorHeight = 1;
31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Padding between tabs and scroll button.
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst int kScrollButtonVerticalPadding = 2;
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The new tab button is rendered using a SideTab.
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass SideTabNewTabButton : public SideTab {
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  explicit SideTabNewTabButton(TabStripController* controller);
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual bool ShouldPaintHighlight() const OVERRIDE { return false; }
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual bool IsSelected() const OVERRIDE { return false; }
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual bool OnMousePressed(const views::MouseEvent& event) OVERRIDE;
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnMouseReleased(const views::MouseEvent& event) OVERRIDE;
44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabStripController* controller_;
47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(SideTabNewTabButton);
49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
51c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSideTabNewTabButton::SideTabNewTabButton(TabStripController* controller)
52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : SideTab(NULL),
53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      controller_(controller) {
54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Never show a close button for the new tab button.
55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  close_button()->SetVisible(false);
56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  TabRendererData data;
57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data.favicon = *ResourceBundle::GetSharedInstance().GetBitmapNamed(
58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      IDR_SIDETABS_NEW_TAB);
59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  data.title = l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE);
60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetData(data);
61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SideTabNewTabButton::OnMousePressed(const views::MouseEvent& event) {
64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return true;
65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabNewTabButton::OnMouseReleased(const views::MouseEvent& event) {
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (event.IsOnlyLeftMouseButton() && HitTest(event.location()))
69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    controller_->CreateNewTab();
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Button class used for the scroll buttons.
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass ScrollButton : public views::TextButton {
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen public:
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  enum Type {
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    UP,
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DOWN
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  };
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  explicit ScrollButton(views::ButtonListener* listener, Type type);
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen protected:
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // views::View overrides.
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen private:
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const Type type_;
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DISALLOW_COPY_AND_ASSIGN(ScrollButton);
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenScrollButton::ScrollButton(views::ButtonListener* listener,
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                           Type type)
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : views::TextButton(listener, std::wstring()),
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      type_(type) {
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ScrollButton::OnPaint(gfx::Canvas* canvas) {
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  TextButton::OnPaint(canvas);
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Draw the arrow.
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SkColor arrow_color = IsEnabled() ? SK_ColorBLACK : SK_ColorGRAY;
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int arrow_height = 5;
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int x = width() / 2;
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int y = (height() - arrow_height) / 2;
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int delta_y = 1;
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (type_ == DOWN) {
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delta_y = -1;
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    y += arrow_height;
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < arrow_height; ++i, --x, y += delta_y)
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    canvas->FillRectInt(arrow_color, x, y, (i * 2) + 1, 1);
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int SideTabStrip::kTabStripInset = 3;
119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SideTabStrip, public:
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSideTabStrip::SideTabStrip(TabStripController* controller)
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    : BaseTabStrip(controller, BaseTabStrip::VERTICAL_TAB_STRIP),
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      newtab_button_(new SideTabNewTabButton(controller)),
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      scroll_up_button_(NULL),
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      scroll_down_button_(NULL),
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      separator_(new views::View()),
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      first_tab_y_offset_(0),
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ideal_height_(0) {
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SetID(VIEW_ID_TAB_STRIP);
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  set_background(views::Background::CreateSolidBackground(kBackgroundColor));
133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(newtab_button_);
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  separator_->set_background(
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      views::Background::CreateSolidBackground(kSeparatorColor));
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AddChildView(separator_);
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_up_button_ = new ScrollButton(this, ScrollButton::UP);
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  AddChildView(scroll_up_button_);
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_down_button_ = new ScrollButton(this, ScrollButton::DOWN);
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  AddChildView(scroll_down_button_);
141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
143c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochSideTabStrip::~SideTabStrip() {
144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DestroyDragController();
145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch////////////////////////////////////////////////////////////////////////////////
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// SideTabStrip, AbstractTabStripView implementation:
149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochbool SideTabStrip::IsPositionInWindowCaption(const gfx::Point& point) {
151dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return GetEventHandlerForPoint(point) == this;
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::SetBackgroundOffset(const gfx::Point& offset) {
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen////////////////////////////////////////////////////////////////////////////////
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// SideTabStrip, BaseTabStrip implementation:
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::StartHighlight(int model_index) {
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::StopAllHighlighting() {
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTab* SideTabStrip::CreateTabForDragging() {
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SideTab* tab = new SideTab(NULL);
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Make sure the dragged tab shares our theme provider. We need to explicitly
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // do this as during dragging there isn't a theme provider.
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  tab->set_theme_provider(GetThemeProvider());
171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return tab;
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::RemoveTabAt(int model_index) {
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  StartRemoveTabAnimation(model_index);
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::SelectTabAt(int old_model_index, int new_model_index) {
179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GetBaseTabAtModelIndex(new_model_index)->SchedulePaint();
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (controller()->IsActiveTab(new_model_index))
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    MakeTabVisible(ModelIndexToTabIndex(new_model_index));
183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::TabTitleChangedNotLoading(int model_index) {
186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochgfx::Size SideTabStrip::GetPreferredSize() {
189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return gfx::Size(kTabStripWidth, 0);
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::PaintChildren(gfx::Canvas* canvas) {
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Make sure any tabs being dragged appear on top of all others by painting
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // them last.
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<BaseTab*> dragging_tabs;
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Make sure nothing draws on top of the scroll buttons.
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  canvas->Save();
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  canvas->ClipRectInt(kTabStripInset, kTabStripInset,
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                      width() - kTabStripInset - kTabStripInset,
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                      GetMaxTabY() - kTabStripInset);
202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Paint the new tab and separator first so that any tabs animating appear on
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // top.
205dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  separator_->Paint(canvas);
206dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  newtab_button_->Paint(canvas);
207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = tab_count() - 1; i >= 0; --i) {
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTab* tab = base_tab_at_tab_index(i);
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (tab->dragging())
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      dragging_tabs.push_back(tab);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else
213dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      tab->Paint(canvas);
214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < dragging_tabs.size(); ++i)
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    dragging_tabs[i]->Paint(canvas);
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  canvas->Restore();
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_down_button_->Paint(canvas);
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_up_button_->Paint(canvas);
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenviews::View* SideTabStrip::GetEventHandlerForPoint(const gfx::Point& point) {
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Check the scroll buttons first as they visually appear on top of everything
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // else.
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (scroll_down_button_->IsVisible()) {
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gfx::Point local_point(point);
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    View::ConvertPointToView(this, scroll_down_button_, &local_point);
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (scroll_down_button_->HitTest(local_point))
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return scroll_down_button_->GetEventHandlerForPoint(local_point);
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (scroll_up_button_->IsVisible()) {
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gfx::Point local_point(point);
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    View::ConvertPointToView(this, scroll_up_button_, &local_point);
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (scroll_up_button_->HitTest(local_point))
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return scroll_up_button_->GetEventHandlerForPoint(local_point);
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return views::View::GetEventHandlerForPoint(point);
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::ButtonPressed(views::Button* sender,
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                 const views::Event& event) {
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int max_offset = GetMaxOffset();
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (max_offset == 0) {
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // All the tabs fit, no need to scroll.
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Determine the index of the first visible tab.
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int initial_y = kTabStripInset;
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int first_vis_index = -1;
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < tab_count(); ++i) {
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (ideal_bounds(i).bottom() > initial_y) {
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      first_vis_index = i;
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (first_vis_index == -1)
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int delta = 0;
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (sender == scroll_up_button_) {
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delta = initial_y - ideal_bounds(first_vis_index).y();
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (delta <= 0) {
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (first_vis_index == 0) {
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        delta = -first_tab_y_offset_;
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      } else {
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        delta = initial_y - ideal_bounds(first_vis_index - 1).y();
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        DCHECK_NE(0, delta);  // Not fatal, but indicates we aren't scrolling.
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK_EQ(sender, scroll_down_button_);
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (ideal_bounds(first_vis_index).y() > initial_y) {
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delta = initial_y - ideal_bounds(first_vis_index).y();
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else if (first_vis_index + 1 == tab_count()) {
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delta = -first_tab_y_offset_;
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    } else {
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delta = initial_y - ideal_bounds(first_vis_index + 1).y();
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetFirstTabYOffset(first_tab_y_offset_ + delta);
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
288c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochBaseTab* SideTabStrip::CreateTab() {
289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return new SideTab(this);
290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::GenerateIdealBounds() {
29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  gfx::Rect layout_rect = GetContentsBounds();
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  layout_rect.Inset(kTabStripInset, kTabStripInset);
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int y = layout_rect.y() + first_tab_y_offset_;
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool last_was_mini = true;
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool has_non_closing_tab = false;
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  separator_bounds_.SetRect(0, -kSeparatorHeight, width(), kSeparatorHeight);
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_count(); ++i) {
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTab* tab = base_tab_at_tab_index(i);
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!tab->closing()) {
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (last_was_mini != tab->data().mini) {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (has_non_closing_tab) {
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          separator_bounds_.SetRect(0, y, width(), kSeparatorHeight);
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          y += kSeparatorHeight + kVerticalTabSpacing;
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        newtab_button_bounds_.SetRect(
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            layout_rect.x(), y, layout_rect.width(),
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch            newtab_button_->GetPreferredSize().height());
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        y = newtab_button_bounds_.bottom() + kVerticalTabSpacing;
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        last_was_mini = tab->data().mini;
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      gfx::Rect bounds = gfx::Rect(layout_rect.x(), y, layout_rect.width(),
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                   tab->GetPreferredSize().height());
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      set_ideal_bounds(i, bounds);
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      y = bounds.bottom() + kVerticalTabSpacing;
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      has_non_closing_tab = true;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (last_was_mini) {
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (has_non_closing_tab) {
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      separator_bounds_.SetRect(0, y, width(), kSeparatorHeight);
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      y += kSeparatorHeight + kVerticalTabSpacing;
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    newtab_button_bounds_ =
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        gfx::Rect(layout_rect.x(), y, layout_rect.width(),
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                  newtab_button_->GetPreferredSize().height());
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    y += newtab_button_->GetPreferredSize().height();
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ideal_height_ = y - layout_rect.y() - first_tab_y_offset_;
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_up_button_->SetEnabled(first_tab_y_offset_ != 0);
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_down_button_->SetEnabled(GetMaxOffset() != 0 &&
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                  first_tab_y_offset_ != GetMaxOffset());
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::StartInsertTabAnimation(int model_index) {
341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  PrepareForAnimation();
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  GenerateIdealBounds();
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int tab_data_index = ModelIndexToTabIndex(model_index);
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  BaseTab* tab = base_tab_at_tab_index(tab_data_index);
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (model_index == 0) {
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab->SetBounds(ideal_bounds(tab_data_index).x(), 0,
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   ideal_bounds(tab_data_index).width(), 0);
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTab* last_tab = base_tab_at_tab_index(tab_data_index - 1);
352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    tab->SetBounds(last_tab->x(), last_tab->bounds().bottom(),
353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                   ideal_bounds(tab_data_index).width(), 0);
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  AnimateToIdealBounds();
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SideTabStrip::AnimateToIdealBounds() {
360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (int i = 0; i < tab_count(); ++i) {
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    BaseTab* tab = base_tab_at_tab_index(i);
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!tab->closing() && !tab->dragging())
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      bounds_animator().AnimateViewTo(tab, ideal_bounds(i));
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bounds_animator().AnimateViewTo(newtab_button_, newtab_button_bounds_);
367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bounds_animator().AnimateViewTo(separator_, separator_bounds_);
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
371731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickvoid SideTabStrip::DoLayout() {
372731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  BaseTabStrip::DoLayout();
37372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  newtab_button_->SetBoundsRect(newtab_button_bounds_);
37472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  separator_->SetBoundsRect(separator_bounds_);
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int scroll_button_y = height() - kScrollButtonHeight;
376ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_up_button_->SetBounds(0, scroll_button_y, width() / 2,
377ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                               kScrollButtonHeight);
378ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  scroll_down_button_->SetBounds(width() / 2, scroll_button_y, width() / 2,
379ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                 kScrollButtonHeight);
380ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
381ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
382ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::LayoutDraggedTabsAt(const std::vector<BaseTab*>& tabs,
383ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       BaseTab* active_tab,
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       const gfx::Point& location,
385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       bool initial_drag) {
386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO: add support for initial_drag (see TabStrip's implementation).
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Rect layout_rect = GetContentsBounds();
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  layout_rect.Inset(kTabStripInset, kTabStripInset);
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int y = location.y();
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < tabs.size(); ++i) {
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BaseTab* tab = tabs[i];
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tab->SchedulePaint();
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tab->SetBounds(layout_rect.x(), y, layout_rect.width(),
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                   tab->GetPreferredSize().height());
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tab->SchedulePaint();
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    y += tab->height() + kVerticalTabSpacing;
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
398ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::CalculateBoundsForDraggedTabs(
401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<BaseTab*>& tabs,
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::vector<gfx::Rect>* bounds) {
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int y = 0;
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (size_t i = 0; i < tabs.size(); ++i) {
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BaseTab* tab = tabs[i];
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    gfx::Rect tab_bounds(tab->bounds());
407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tab_bounds.set_y(y);
408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    y += tab->height() + kVerticalTabSpacing;
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bounds->push_back(tab_bounds);
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint SideTabStrip::GetSizeNeededForTabs(const std::vector<BaseTab*>& tabs) {
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return static_cast<int>(tabs.size()) * SideTab::GetPreferredHeight();
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::OnBoundsChanged(const gfx::Rect& previous_bounds) {
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // When our height changes we may be able to show more.
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  first_tab_y_offset_ = std::max(GetMaxOffset(),
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                 std::min(0, first_tab_y_offset_));
421ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (int i = 0; i < controller()->GetCount(); ++i) {
422ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (controller()->IsActiveTab(i)) {
423ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      MakeTabVisible(ModelIndexToTabIndex(i));
424ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::SetFirstTabYOffset(int new_offset) {
430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int max_offset = GetMaxOffset();
431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (max_offset == 0) {
432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // All the tabs fit, no need to scroll.
433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  new_offset = std::max(max_offset, std::min(0, new_offset));
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (new_offset == first_tab_y_offset_)
437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  StopAnimating(false);
440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  first_tab_y_offset_ = new_offset;
441ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GenerateIdealBounds();
442ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DoLayout();
443ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
444ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
445ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
446ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint SideTabStrip::GetMaxOffset() const {
447ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int available_height = GetMaxTabY() - kTabStripInset;
448ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return std::min(0, available_height - ideal_height_);
449ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
450ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
451ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint SideTabStrip::GetMaxTabY() const {
452ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return height() - kTabStripInset - kScrollButtonVerticalPadding -
453ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      kScrollButtonHeight;
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid SideTabStrip::MakeTabVisible(int tab_index) {
457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (height() == 0)
458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (ideal_bounds(tab_index).y() < kTabStripInset) {
461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetFirstTabYOffset(first_tab_y_offset_ - ideal_bounds(tab_index).y() +
462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       kTabStripInset);
463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (ideal_bounds(tab_index).bottom() > GetMaxTabY()) {
464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetFirstTabYOffset(GetMaxTabY() - (ideal_bounds(tab_index).bottom() -
465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       first_tab_y_offset_));
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
468