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