| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/views/controls/tabbed_pane/tabbed_pane.h" | 5 #include "ui/views/controls/tabbed_pane/tabbed_pane.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/macros.h" | 8 #include "base/macros.h" |
| 9 #include "third_party/skia/include/core/SkPaint.h" | 9 #include "third_party/skia/include/core/SkPaint.h" |
| 10 #include "third_party/skia/include/core/SkPath.h" | 10 #include "third_party/skia/include/core/SkPath.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 const int kHarmonyTabStripVerticalPad = 16; | 39 const int kHarmonyTabStripVerticalPad = 16; |
| 40 const int kHarmonyTabStripTabHeight = 40; | 40 const int kHarmonyTabStripTabHeight = 40; |
| 41 | 41 |
| 42 } // namespace | 42 } // namespace |
| 43 | 43 |
| 44 namespace views { | 44 namespace views { |
| 45 | 45 |
| 46 // static | 46 // static |
| 47 const char TabbedPane::kViewClassName[] = "TabbedPane"; | 47 const char TabbedPane::kViewClassName[] = "TabbedPane"; |
| 48 | 48 |
| 49 // The tab view shown in the tab strip. | |
| 50 class Tab : public View { | |
| 51 public: | |
| 52 // Internal class name. | |
| 53 static const char kViewClassName[]; | |
| 54 | |
| 55 Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents); | |
| 56 ~Tab() override; | |
| 57 | |
| 58 View* contents() const { return contents_; } | |
| 59 | |
| 60 bool selected() const { return contents_->visible(); } | |
| 61 void SetSelected(bool selected); | |
| 62 | |
| 63 // Overridden from View: | |
| 64 bool OnMousePressed(const ui::MouseEvent& event) override; | |
| 65 void OnMouseEntered(const ui::MouseEvent& event) override; | |
| 66 void OnMouseExited(const ui::MouseEvent& event) override; | |
| 67 void OnGestureEvent(ui::GestureEvent* event) override; | |
| 68 gfx::Size GetPreferredSize() const override; | |
| 69 void Layout() override; | |
| 70 const char* GetClassName() const override; | |
| 71 | |
| 72 protected: | |
| 73 Label* title() { return title_; } | |
| 74 | |
| 75 // Called whenever |tab_state_| changes. | |
| 76 virtual void OnStateChanged(); | |
| 77 | |
| 78 private: | |
| 79 enum TabState { | |
| 80 TAB_INACTIVE, | |
| 81 TAB_ACTIVE, | |
| 82 TAB_HOVERED, | |
| 83 }; | |
| 84 | |
| 85 void SetState(TabState tab_state); | |
| 86 | |
| 87 TabbedPane* tabbed_pane_; | |
| 88 Label* title_; | |
| 89 gfx::Size preferred_title_size_; | |
| 90 TabState tab_state_; | |
| 91 // The content view associated with this tab. | |
| 92 View* contents_; | |
| 93 | |
| 94 DISALLOW_COPY_AND_ASSIGN(Tab); | |
| 95 }; | |
| 96 | |
| 97 // A subclass of Tab that implements the Harmony visual styling. | 49 // A subclass of Tab that implements the Harmony visual styling. |
| 98 class MdTab : public Tab { | 50 class MdTab : public Tab { |
| 99 public: | 51 public: |
| 100 MdTab(TabbedPane* tabbed_pane, const base::string16& title, View* contents); | 52 MdTab(TabbedPane* tabbed_pane, const base::string16& title, View* contents); |
| 101 ~MdTab() override; | 53 ~MdTab() override; |
| 102 | 54 |
| 103 // Overridden from Tab: | 55 // Overridden from Tab: |
| 104 void OnStateChanged() override; | 56 void OnStateChanged() override; |
| 105 | 57 |
| 58 // Overridden from View: |
| 59 void OnPaintBorder(gfx::Canvas* canvas) override; |
| 60 |
| 106 private: | 61 private: |
| 107 DISALLOW_COPY_AND_ASSIGN(MdTab); | 62 DISALLOW_COPY_AND_ASSIGN(MdTab); |
| 108 }; | 63 }; |
| 109 | 64 |
| 110 // The tab strip shown above the tab contents. | 65 // The tab strip shown above the tab contents. |
| 111 class TabStrip : public View { | 66 class TabStrip : public View { |
| 112 public: | 67 public: |
| 113 // Internal class name. | 68 // Internal class name. |
| 114 static const char kViewClassName[]; | 69 static const char kViewClassName[]; |
| 115 | 70 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 | 117 |
| 163 SetState(TAB_INACTIVE); | 118 SetState(TAB_INACTIVE); |
| 164 AddChildView(title_); | 119 AddChildView(title_); |
| 165 } | 120 } |
| 166 | 121 |
| 167 Tab::~Tab() {} | 122 Tab::~Tab() {} |
| 168 | 123 |
| 169 void Tab::SetSelected(bool selected) { | 124 void Tab::SetSelected(bool selected) { |
| 170 contents_->SetVisible(selected); | 125 contents_->SetVisible(selected); |
| 171 SetState(selected ? TAB_ACTIVE : TAB_INACTIVE); | 126 SetState(selected ? TAB_ACTIVE : TAB_INACTIVE); |
| 127 #if defined(OS_MACOSX) |
| 128 SetFocusBehavior(selected ? FocusBehavior::ACCESSIBLE_ONLY |
| 129 : FocusBehavior::NEVER); |
| 130 #else |
| 131 SetFocusBehavior(selected ? FocusBehavior::ALWAYS : FocusBehavior::NEVER); |
| 132 #endif |
| 172 } | 133 } |
| 173 | 134 |
| 174 void Tab::OnStateChanged() { | 135 void Tab::OnStateChanged() { |
| 175 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 136 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 176 switch (tab_state_) { | 137 switch (tab_state_) { |
| 177 case TAB_INACTIVE: | 138 case TAB_INACTIVE: |
| 178 title_->SetEnabledColor(kTabTitleColor_Inactive); | 139 title_->SetEnabledColor(kTabTitleColor_Inactive); |
| 179 title_->SetFontList(rb.GetFontListWithDelta( | 140 title_->SetFontList(rb.GetFontListWithDelta( |
| 180 ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kInactiveWeight)); | 141 ui::kLabelFontSizeDelta, gfx::Font::NORMAL, kInactiveWeight)); |
| 181 break; | 142 break; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 245 } | 206 } |
| 246 | 207 |
| 247 void Tab::SetState(TabState tab_state) { | 208 void Tab::SetState(TabState tab_state) { |
| 248 if (tab_state == tab_state_) | 209 if (tab_state == tab_state_) |
| 249 return; | 210 return; |
| 250 tab_state_ = tab_state; | 211 tab_state_ = tab_state; |
| 251 OnStateChanged(); | 212 OnStateChanged(); |
| 252 SchedulePaint(); | 213 SchedulePaint(); |
| 253 } | 214 } |
| 254 | 215 |
| 216 bool Tab::ContainerHasFocus() { |
| 217 return tabbed_pane_->HasFocus(); |
| 218 } |
| 219 |
| 220 void Tab::OnFocus() { |
| 221 OnStateChanged(); |
| 222 // When the tab gains focus, send an accessibility event indicating that the |
| 223 // contents are focused. When the tab loses focus, whichever new View ends up |
| 224 // with focus will send an AX_EVENT_FOCUS of its own, so there's no need to |
| 225 // send one in OnBlur(). |
| 226 if (contents()) |
| 227 contents()->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); |
| 228 SchedulePaint(); |
| 229 } |
| 230 |
| 231 void Tab::OnBlur() { |
| 232 OnStateChanged(); |
| 233 SchedulePaint(); |
| 234 } |
| 235 |
| 236 bool Tab::OnKeyPressed(const ui::KeyEvent& event) { |
| 237 ui::KeyboardCode key = event.key_code(); |
| 238 if (key != ui::VKEY_LEFT && key != ui::VKEY_RIGHT) |
| 239 return false; |
| 240 return tabbed_pane_->MoveSelectionBy(key == ui::VKEY_RIGHT ? 1 : -1); |
| 241 } |
| 242 |
| 255 MdTab::MdTab(TabbedPane* tabbed_pane, | 243 MdTab::MdTab(TabbedPane* tabbed_pane, |
| 256 const base::string16& title, | 244 const base::string16& title, |
| 257 View* contents) | 245 View* contents) |
| 258 : Tab(tabbed_pane, title, contents) { | 246 : Tab(tabbed_pane, title, contents) { |
| 259 OnStateChanged(); | 247 OnStateChanged(); |
| 260 } | 248 } |
| 261 | 249 |
| 262 MdTab::~MdTab() {} | 250 MdTab::~MdTab() {} |
| 263 | 251 |
| 264 void MdTab::OnStateChanged() { | 252 void MdTab::OnStateChanged() { |
| 265 ui::NativeTheme* theme = GetNativeTheme(); | 253 ui::NativeTheme* theme = GetNativeTheme(); |
| 266 SkColor border_color = theme->GetSystemColor( | |
| 267 selected() ? ui::NativeTheme::kColorId_FocusedBorderColor | |
| 268 : ui::NativeTheme::kColorId_UnfocusedBorderColor); | |
| 269 int border_thickness = selected() ? 2 : 1; | |
| 270 SetBorder( | |
| 271 Border::CreateSolidSidedBorder(0, 0, border_thickness, 0, border_color)); | |
| 272 | 254 |
| 273 SkColor font_color = selected() | 255 SkColor font_color = selected() |
| 274 ? theme->GetSystemColor(ui::NativeTheme::kColorId_ProminentButtonColor) | 256 ? theme->GetSystemColor(ui::NativeTheme::kColorId_ProminentButtonColor) |
| 275 : theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonEnabledColor); | 257 : theme->GetSystemColor(ui::NativeTheme::kColorId_ButtonEnabledColor); |
| 276 title()->SetEnabledColor(font_color); | 258 title()->SetEnabledColor(font_color); |
| 277 | 259 |
| 278 gfx::Font::Weight font_weight = gfx::Font::Weight::MEDIUM; | 260 gfx::Font::Weight font_weight = gfx::Font::Weight::MEDIUM; |
| 279 #if defined(OS_WIN) | 261 #if defined(OS_WIN) |
| 280 if (selected()) | 262 if (selected()) |
| 281 font_weight = gfx::Font::Weight::BOLD; | 263 font_weight = gfx::Font::Weight::BOLD; |
| 282 #endif | 264 #endif |
| 283 | 265 |
| 284 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); | 266 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); |
| 285 title()->SetFontList(rb.GetFontListWithDelta(ui::kLabelFontSizeDelta, | 267 title()->SetFontList(rb.GetFontListWithDelta(ui::kLabelFontSizeDelta, |
| 286 gfx::Font::NORMAL, font_weight)); | 268 gfx::Font::NORMAL, font_weight)); |
| 287 } | 269 } |
| 288 | 270 |
| 271 void MdTab::OnPaintBorder(gfx::Canvas* canvas) { |
| 272 const int kBorderStrokeWidth = 2; |
| 273 if (!HasFocus()) { |
| 274 SkColor color = GetNativeTheme()->GetSystemColor( |
| 275 selected() ? ui::NativeTheme::kColorId_FocusedBorderColor |
| 276 : ui::NativeTheme::kColorId_UnfocusedBorderColor); |
| 277 int thickness = selected() ? kBorderStrokeWidth : kBorderStrokeWidth / 2; |
| 278 canvas->FillRect(gfx::Rect(0, height() - thickness, width(), thickness), |
| 279 color); |
| 280 return; |
| 281 } |
| 282 |
| 283 // TODO(ellyjones): should this 0x66 be part of NativeTheme somehow? |
| 284 SkColor base_color = GetNativeTheme()->GetSystemColor( |
| 285 ui::NativeTheme::kColorId_FocusedBorderColor); |
| 286 SkColor light_color = SkColorSetA(base_color, 0x66); |
| 287 |
| 288 SkPaint paint; |
| 289 paint.setColor(light_color); |
| 290 paint.setStyle(SkPaint::kStroke_Style); |
| 291 paint.setStrokeWidth(kBorderStrokeWidth); |
| 292 |
| 293 gfx::RectF bounds = gfx::RectF(GetLocalBounds()); |
| 294 bounds.Inset(gfx::Insets(kBorderStrokeWidth / 2.f)); |
| 295 |
| 296 // Draw the lighter-colored stroke first, then draw the heavier stroke over |
| 297 // the bottom of it. This is fine because the heavier stroke has 1.0 alpha, so |
| 298 // the lighter stroke won't show through. |
| 299 canvas->DrawRect(bounds, paint); |
| 300 canvas->FillRect( |
| 301 gfx::Rect(0, height() - kBorderStrokeWidth, width(), kBorderStrokeWidth), |
| 302 base_color); |
| 303 } |
| 304 |
| 289 // static | 305 // static |
| 290 const char TabStrip::kViewClassName[] = "TabStrip"; | 306 const char TabStrip::kViewClassName[] = "TabStrip"; |
| 291 | 307 |
| 292 TabStrip::TabStrip(TabbedPane* tabbed_pane) : tabbed_pane_(tabbed_pane) {} | 308 TabStrip::TabStrip(TabbedPane* tabbed_pane) : tabbed_pane_(tabbed_pane) {} |
| 293 | 309 |
| 294 TabStrip::~TabStrip() {} | 310 TabStrip::~TabStrip() {} |
| 295 | 311 |
| 296 gfx::Size TabStrip::GetPreferredSize() const { | 312 gfx::Size TabStrip::GetPreferredSize() const { |
| 297 gfx::Size size; | 313 gfx::Size size; |
| 298 for (int i = 0; i < child_count(); ++i) { | 314 for (int i = 0; i < child_count(); ++i) { |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 379 OnPaintBackground(canvas); | 395 OnPaintBackground(canvas); |
| 380 } | 396 } |
| 381 | 397 |
| 382 TabbedPane::TabbedPane() | 398 TabbedPane::TabbedPane() |
| 383 : listener_(NULL), | 399 : listener_(NULL), |
| 384 tab_strip_(ui::MaterialDesignController::IsSecondaryUiMaterial() | 400 tab_strip_(ui::MaterialDesignController::IsSecondaryUiMaterial() |
| 385 ? new MdTabStrip(this) | 401 ? new MdTabStrip(this) |
| 386 : new TabStrip(this)), | 402 : new TabStrip(this)), |
| 387 contents_(new View()), | 403 contents_(new View()), |
| 388 selected_tab_index_(-1) { | 404 selected_tab_index_(-1) { |
| 389 #if defined(OS_MACOSX) | |
| 390 SetFocusBehavior(FocusBehavior::ACCESSIBLE_ONLY); | |
| 391 #else | |
| 392 SetFocusBehavior(FocusBehavior::ALWAYS); | |
| 393 #endif | |
| 394 | |
| 395 AddChildView(tab_strip_); | 405 AddChildView(tab_strip_); |
| 396 AddChildView(contents_); | 406 AddChildView(contents_); |
| 397 } | 407 } |
| 398 | 408 |
| 399 TabbedPane::~TabbedPane() {} | 409 TabbedPane::~TabbedPane() {} |
| 400 | 410 |
| 401 int TabbedPane::GetTabCount() { | 411 int TabbedPane::GetTabCount() { |
| 402 DCHECK_EQ(tab_strip_->child_count(), contents_->child_count()); | 412 DCHECK_EQ(tab_strip_->child_count(), contents_->child_count()); |
| 403 return contents_->child_count(); | 413 return contents_->child_count(); |
| 404 } | 414 } |
| 405 | 415 |
| 406 View* TabbedPane::GetSelectedTab() { | |
| 407 return selected_tab_index() < 0 ? | |
| 408 NULL : GetTabAt(selected_tab_index())->contents(); | |
| 409 } | |
| 410 | |
| 411 void TabbedPane::AddTab(const base::string16& title, View* contents) { | 416 void TabbedPane::AddTab(const base::string16& title, View* contents) { |
| 412 AddTabAtIndex(tab_strip_->child_count(), title, contents); | 417 AddTabAtIndex(tab_strip_->child_count(), title, contents); |
| 413 } | 418 } |
| 414 | 419 |
| 415 void TabbedPane::AddTabAtIndex(int index, | 420 void TabbedPane::AddTabAtIndex(int index, |
| 416 const base::string16& title, | 421 const base::string16& title, |
| 417 View* contents) { | 422 View* contents) { |
| 418 DCHECK(index >= 0 && index <= GetTabCount()); | 423 DCHECK(index >= 0 && index <= GetTabCount()); |
| 419 contents->SetVisible(false); | 424 contents->SetVisible(false); |
| 420 | 425 |
| 421 tab_strip_->AddChildViewAt( | 426 tab_strip_->AddChildViewAt( |
| 422 ui::MaterialDesignController::IsSecondaryUiMaterial() | 427 ui::MaterialDesignController::IsSecondaryUiMaterial() |
| 423 ? new MdTab(this, title, contents) | 428 ? new MdTab(this, title, contents) |
| 424 : new Tab(this, title, contents), | 429 : new Tab(this, title, contents), |
| 425 index); | 430 index); |
| 426 contents_->AddChildViewAt(contents, index); | 431 contents_->AddChildViewAt(contents, index); |
| 432 // TODO(ellyjones): if index < selected_tab_index(), selected_tab_index() gets |
| 433 // out of sync with which tab believes it is selected. This class should |
| 434 // directly ask Tabs whether they are selected. |
| 427 if (selected_tab_index() < 0) | 435 if (selected_tab_index() < 0) |
| 428 SelectTabAt(index); | 436 SelectTabAt(index); |
| 429 | 437 |
| 430 PreferredSizeChanged(); | 438 PreferredSizeChanged(); |
| 431 } | 439 } |
| 432 | 440 |
| 433 void TabbedPane::SelectTabAt(int index) { | 441 void TabbedPane::SelectTabAt(int index) { |
| 434 DCHECK(index >= 0 && index < GetTabCount()); | 442 DCHECK(index >= 0 && index < GetTabCount()); |
| 435 if (index == selected_tab_index()) | 443 if (index == selected_tab_index()) |
| 436 return; | 444 return; |
| 437 | 445 |
| 438 if (selected_tab_index() >= 0) | 446 Tab* old_selected_tab = GetSelectedTab(); |
| 439 GetTabAt(selected_tab_index())->SetSelected(false); | 447 Tab* new_selected_tab = GetTabAt(index); |
| 440 | 448 new_selected_tab->SetSelected(true); |
| 441 selected_tab_index_ = index; | 449 selected_tab_index_ = index; |
| 442 Tab* tab = GetTabAt(index); | 450 if (old_selected_tab) { |
| 443 tab->SetSelected(true); | 451 if (old_selected_tab->HasFocus()) |
| 452 new_selected_tab->RequestFocus(); |
| 453 old_selected_tab->SetSelected(false); |
| 454 } |
| 444 tab_strip_->SchedulePaint(); | 455 tab_strip_->SchedulePaint(); |
| 445 | 456 |
| 446 FocusManager* focus_manager = tab->contents()->GetFocusManager(); | 457 FocusManager* focus_manager = new_selected_tab->contents()->GetFocusManager(); |
| 447 if (focus_manager) { | 458 if (focus_manager) { |
| 448 const View* focused_view = focus_manager->GetFocusedView(); | 459 const View* focused_view = focus_manager->GetFocusedView(); |
| 449 if (focused_view && contents_->Contains(focused_view) && | 460 if (focused_view && contents_->Contains(focused_view) && |
| 450 !tab->contents()->Contains(focused_view)) | 461 !new_selected_tab->contents()->Contains(focused_view)) |
| 451 focus_manager->SetFocusedView(tab->contents()); | 462 focus_manager->SetFocusedView(new_selected_tab->contents()); |
| 452 } | 463 } |
| 453 | 464 |
| 454 if (listener()) | 465 if (listener()) |
| 455 listener()->TabSelectedAt(index); | 466 listener()->TabSelectedAt(index); |
| 456 } | 467 } |
| 457 | 468 |
| 458 void TabbedPane::SelectTab(Tab* tab) { | 469 void TabbedPane::SelectTab(Tab* tab) { |
| 459 const int index = tab_strip_->GetIndexOf(tab); | 470 const int index = tab_strip_->GetIndexOf(tab); |
| 460 if (index >= 0) | 471 if (index >= 0) |
| 461 SelectTabAt(index); | 472 SelectTabAt(index); |
| 462 } | 473 } |
| 463 | 474 |
| 464 gfx::Size TabbedPane::GetPreferredSize() const { | 475 gfx::Size TabbedPane::GetPreferredSize() const { |
| 465 gfx::Size size; | 476 gfx::Size size; |
| 466 for (int i = 0; i < contents_->child_count(); ++i) | 477 for (int i = 0; i < contents_->child_count(); ++i) |
| 467 size.SetToMax(contents_->child_at(i)->GetPreferredSize()); | 478 size.SetToMax(contents_->child_at(i)->GetPreferredSize()); |
| 468 size.Enlarge(0, tab_strip_->GetPreferredSize().height()); | 479 size.Enlarge(0, tab_strip_->GetPreferredSize().height()); |
| 469 return size; | 480 return size; |
| 470 } | 481 } |
| 471 | 482 |
| 472 Tab* TabbedPane::GetTabAt(int index) { | 483 Tab* TabbedPane::GetTabAt(int index) { |
| 473 return static_cast<Tab*>(tab_strip_->child_at(index)); | 484 return static_cast<Tab*>(tab_strip_->child_at(index)); |
| 474 } | 485 } |
| 475 | 486 |
| 487 Tab* TabbedPane::GetSelectedTab() { |
| 488 return selected_tab_index() >= 0 ? GetTabAt(selected_tab_index()) : nullptr; |
| 489 } |
| 490 |
| 491 bool TabbedPane::MoveSelectionBy(int delta) { |
| 492 const int tab_count = GetTabCount(); |
| 493 if (tab_count <= 1) |
| 494 return false; |
| 495 int next_selected_index = (selected_tab_index() + delta) % tab_count; |
| 496 if (next_selected_index < 0) |
| 497 next_selected_index += tab_count; |
| 498 SelectTabAt(next_selected_index); |
| 499 return true; |
| 500 } |
| 501 |
| 476 void TabbedPane::Layout() { | 502 void TabbedPane::Layout() { |
| 477 const gfx::Size size = tab_strip_->GetPreferredSize(); | 503 const gfx::Size size = tab_strip_->GetPreferredSize(); |
| 478 tab_strip_->SetBounds(0, 0, width(), size.height()); | 504 tab_strip_->SetBounds(0, 0, width(), size.height()); |
| 479 contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(), | 505 contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(), |
| 480 std::max(0, height() - size.height())); | 506 std::max(0, height() - size.height())); |
| 481 for (int i = 0; i < contents_->child_count(); ++i) | 507 for (int i = 0; i < contents_->child_count(); ++i) |
| 482 contents_->child_at(i)->SetSize(contents_->size()); | 508 contents_->child_at(i)->SetSize(contents_->size()); |
| 483 } | 509 } |
| 484 | 510 |
| 485 void TabbedPane::ViewHierarchyChanged( | 511 void TabbedPane::ViewHierarchyChanged( |
| 486 const ViewHierarchyChangedDetails& details) { | 512 const ViewHierarchyChangedDetails& details) { |
| 487 if (details.is_add) { | 513 if (details.is_add) { |
| 488 // Support navigating tabs by Ctrl+Tab and Ctrl+Shift+Tab. | 514 // Support navigating tabs by Ctrl+Tab and Ctrl+Shift+Tab. |
| 489 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, | 515 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, |
| 490 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN)); | 516 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN)); |
| 491 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, ui::EF_CONTROL_DOWN)); | 517 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, ui::EF_CONTROL_DOWN)); |
| 492 } | 518 } |
| 493 } | 519 } |
| 494 | 520 |
| 495 bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) { | 521 bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) { |
| 496 // Handle Ctrl+Tab and Ctrl+Shift+Tab navigation of pages. | 522 // Handle Ctrl+Tab and Ctrl+Shift+Tab navigation of pages. |
| 497 DCHECK(accelerator.key_code() == ui::VKEY_TAB && accelerator.IsCtrlDown()); | 523 DCHECK(accelerator.key_code() == ui::VKEY_TAB && accelerator.IsCtrlDown()); |
| 498 const int tab_count = GetTabCount(); | 524 return MoveSelectionBy(accelerator.IsShiftDown() ? -1 : 1); |
| 499 if (tab_count <= 1) | |
| 500 return false; | |
| 501 const int increment = accelerator.IsShiftDown() ? -1 : 1; | |
| 502 int next_tab_index = (selected_tab_index() + increment) % tab_count; | |
| 503 // Wrap around. | |
| 504 if (next_tab_index < 0) | |
| 505 next_tab_index += tab_count; | |
| 506 SelectTabAt(next_tab_index); | |
| 507 return true; | |
| 508 } | 525 } |
| 509 | 526 |
| 510 const char* TabbedPane::GetClassName() const { | 527 const char* TabbedPane::GetClassName() const { |
| 511 return kViewClassName; | 528 return kViewClassName; |
| 512 } | 529 } |
| 513 | 530 |
| 514 void TabbedPane::OnFocus() { | 531 View* TabbedPane::GetSelectedTabContentView() { |
| 515 View::OnFocus(); | 532 return GetSelectedTab() ? GetSelectedTab()->contents() : nullptr; |
| 516 | |
| 517 View* selected_tab = GetSelectedTab(); | |
| 518 if (selected_tab) { | |
| 519 selected_tab->NotifyAccessibilityEvent( | |
| 520 ui::AX_EVENT_FOCUS, true); | |
| 521 } | |
| 522 } | 533 } |
| 523 | 534 |
| 524 void TabbedPane::GetAccessibleState(ui::AXViewState* state) { | 535 void TabbedPane::GetAccessibleState(ui::AXViewState* state) { |
| 525 state->role = ui::AX_ROLE_TAB_LIST; | 536 state->role = ui::AX_ROLE_TAB_LIST; |
| 526 } | 537 } |
| 527 | 538 |
| 528 } // namespace views | 539 } // namespace views |
| OLD | NEW |