Chromium Code Reviews| 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" |
| 11 #include "ui/accessibility/ax_view_state.h" | 11 #include "ui/accessibility/ax_view_state.h" |
| 12 #include "ui/base/default_style.h" | 12 #include "ui/base/default_style.h" |
| 13 #include "ui/base/material_design/material_design_controller.h" | 13 #include "ui/base/material_design/material_design_controller.h" |
| 14 #include "ui/base/resource/resource_bundle.h" | 14 #include "ui/base/resource/resource_bundle.h" |
| 15 #include "ui/events/keycodes/keyboard_codes.h" | 15 #include "ui/events/keycodes/keyboard_codes.h" |
| 16 #include "ui/gfx/canvas.h" | 16 #include "ui/gfx/canvas.h" |
| 17 #include "ui/gfx/font_list.h" | 17 #include "ui/gfx/font_list.h" |
| 18 #include "ui/native_theme/native_theme.h" | 18 #include "ui/native_theme/native_theme.h" |
| 19 #include "ui/views/border.h" | 19 #include "ui/views/border.h" |
| 20 #include "ui/views/controls/label.h" | 20 #include "ui/views/controls/label.h" |
| 21 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h" | 21 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h" |
| 22 #include "ui/views/layout/box_layout.h" | 22 #include "ui/views/layout/box_layout.h" |
| 23 #include "ui/views/layout/fill_layout.h" | |
| 23 #include "ui/views/layout/layout_manager.h" | 24 #include "ui/views/layout/layout_manager.h" |
| 24 #include "ui/views/widget/widget.h" | 25 #include "ui/views/widget/widget.h" |
| 25 | 26 |
| 26 namespace { | 27 namespace { |
| 27 | 28 |
| 28 // TODO(markusheintz|msw): Use NativeTheme colors. | 29 // TODO(markusheintz|msw): Use NativeTheme colors. |
| 29 const SkColor kTabTitleColor_Inactive = SkColorSetRGB(0x64, 0x64, 0x64); | 30 const SkColor kTabTitleColor_Inactive = SkColorSetRGB(0x64, 0x64, 0x64); |
| 30 const SkColor kTabTitleColor_Active = SK_ColorBLACK; | 31 const SkColor kTabTitleColor_Active = SK_ColorBLACK; |
| 31 const SkColor kTabTitleColor_Hovered = SK_ColorBLACK; | 32 const SkColor kTabTitleColor_Hovered = SK_ColorBLACK; |
| 32 const SkColor kTabBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8); | 33 const SkColor kTabBorderColor = SkColorSetRGB(0xC8, 0xC8, 0xC8); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 50 class MdTab : public Tab { | 51 class MdTab : public Tab { |
| 51 public: | 52 public: |
| 52 MdTab(TabbedPane* tabbed_pane, const base::string16& title, View* contents); | 53 MdTab(TabbedPane* tabbed_pane, const base::string16& title, View* contents); |
| 53 ~MdTab() override; | 54 ~MdTab() override; |
| 54 | 55 |
| 55 // Overridden from Tab: | 56 // Overridden from Tab: |
| 56 void OnStateChanged() override; | 57 void OnStateChanged() override; |
| 57 | 58 |
| 58 // Overridden from View: | 59 // Overridden from View: |
| 59 void OnPaintBorder(gfx::Canvas* canvas) override; | 60 void OnPaintBorder(gfx::Canvas* canvas) override; |
| 61 gfx::Size GetPreferredSize() const override; | |
|
msw
2016/10/12 20:18:35
nit: order above OnPaintBorder to match base class
Elly Fong-Jones
2016/10/12 21:23:05
Done.
| |
| 60 | 62 |
| 61 private: | 63 private: |
| 62 DISALLOW_COPY_AND_ASSIGN(MdTab); | 64 DISALLOW_COPY_AND_ASSIGN(MdTab); |
| 63 }; | 65 }; |
| 64 | 66 |
| 65 // The tab strip shown above the tab contents. | 67 // The tab strip shown above the tab contents. |
| 66 class TabStrip : public View { | 68 class TabStrip : public View { |
| 67 public: | 69 public: |
| 68 // Internal class name. | 70 // Internal class name. |
| 69 static const char kViewClassName[]; | 71 static const char kViewClassName[]; |
| 70 | 72 |
| 71 explicit TabStrip(TabbedPane* tabbed_pane); | 73 TabStrip(); |
| 72 ~TabStrip() override; | 74 ~TabStrip() override; |
| 73 | 75 |
| 74 // Overridden from View: | 76 // Overridden from View: |
| 75 gfx::Size GetPreferredSize() const override; | |
| 76 void Layout() override; | |
| 77 const char* GetClassName() const override; | 77 const char* GetClassName() const override; |
| 78 void OnPaint(gfx::Canvas* canvas) override; | 78 void OnPaintBorder(gfx::Canvas* canvas) override; |
| 79 | |
| 80 Tab* GetSelectedTab() const; | |
| 81 Tab* GetTabAtDeltaFromSelected(int delta) const; | |
| 82 Tab* GetTabAtIndex(int index) const; | |
| 83 int GetSelectedTabIndex() const; | |
| 79 | 84 |
| 80 private: | 85 private: |
| 81 TabbedPane* tabbed_pane_; | |
| 82 | |
| 83 DISALLOW_COPY_AND_ASSIGN(TabStrip); | 86 DISALLOW_COPY_AND_ASSIGN(TabStrip); |
| 84 }; | 87 }; |
| 85 | 88 |
| 86 // A subclass of TabStrip that implements the Harmony visual styling. This | 89 // A subclass of TabStrip that implements the Harmony visual styling. This |
| 87 // class uses a BoxLayout to position tabs. | 90 // class uses a BoxLayout to position tabs. |
| 88 class MdTabStrip : public TabStrip { | 91 class MdTabStrip : public TabStrip { |
| 89 public: | 92 public: |
| 90 explicit MdTabStrip(TabbedPane* tabbed_pane); | 93 MdTabStrip(); |
| 91 ~MdTabStrip() override; | 94 ~MdTabStrip() override; |
| 92 | 95 |
| 93 // Overridden from View: | 96 // Overridden from View: |
| 94 gfx::Size GetPreferredSize() const override; | 97 void OnPaintBorder(gfx::Canvas* canvas) override; |
| 95 void Layout() override; | |
| 96 void OnPaint(gfx::Canvas* canvas) override; | |
| 97 | 98 |
| 98 private: | 99 private: |
| 99 DISALLOW_COPY_AND_ASSIGN(MdTabStrip); | 100 DISALLOW_COPY_AND_ASSIGN(MdTabStrip); |
| 100 }; | 101 }; |
| 101 | 102 |
| 102 // static | 103 // static |
| 103 const char Tab::kViewClassName[] = "Tab"; | 104 const char Tab::kViewClassName[] = "Tab"; |
| 104 | 105 |
| 105 Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents) | 106 Tab::Tab(TabbedPane* tabbed_pane, const base::string16& title, View* contents) |
| 106 : tabbed_pane_(tabbed_pane), | 107 : tabbed_pane_(tabbed_pane), |
| 107 title_(new Label( | 108 title_(new Label( |
| 108 title, | 109 title, |
| 109 ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta( | 110 ui::ResourceBundle::GetSharedInstance().GetFontListWithDelta( |
| 110 ui::kLabelFontSizeDelta, | 111 ui::kLabelFontSizeDelta, |
| 111 gfx::Font::NORMAL, | 112 gfx::Font::NORMAL, |
| 112 kActiveWeight))), | 113 kActiveWeight))), |
| 113 tab_state_(TAB_ACTIVE), | 114 tab_state_(TAB_ACTIVE), |
| 114 contents_(contents) { | 115 contents_(contents) { |
| 115 // Calculate this now while the font list is guaranteed to be bold. | 116 // Calculate this now while the font list is guaranteed to be bold. |
| 116 preferred_title_size_ = title_->GetPreferredSize(); | 117 preferred_title_size_ = title_->GetPreferredSize(); |
| 117 | 118 |
| 119 SetBorder(Border::CreateEmptyBorder(gfx::Insets(5, 10))); | |
|
msw
2016/10/12 20:18:35
nit: please use constants defined here or bonus po
Elly Fong-Jones
2016/10/12 21:23:05
Done.
| |
| 120 SetLayoutManager(new FillLayout); | |
| 121 | |
| 118 SetState(TAB_INACTIVE); | 122 SetState(TAB_INACTIVE); |
| 119 AddChildView(title_); | 123 AddChildView(title_); |
| 120 } | 124 } |
| 121 | 125 |
| 122 Tab::~Tab() {} | 126 Tab::~Tab() {} |
| 123 | 127 |
| 124 void Tab::SetSelected(bool selected) { | 128 void Tab::SetSelected(bool selected) { |
| 125 contents_->SetVisible(selected); | 129 contents_->SetVisible(selected); |
| 126 SetState(selected ? TAB_ACTIVE : TAB_INACTIVE); | 130 SetState(selected ? TAB_ACTIVE : TAB_INACTIVE); |
| 127 #if defined(OS_MACOSX) | 131 #if defined(OS_MACOSX) |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 180 SetState(selected() ? TAB_ACTIVE : TAB_INACTIVE); | 184 SetState(selected() ? TAB_ACTIVE : TAB_INACTIVE); |
| 181 break; | 185 break; |
| 182 default: | 186 default: |
| 183 break; | 187 break; |
| 184 } | 188 } |
| 185 event->SetHandled(); | 189 event->SetHandled(); |
| 186 } | 190 } |
| 187 | 191 |
| 188 gfx::Size Tab::GetPreferredSize() const { | 192 gfx::Size Tab::GetPreferredSize() const { |
| 189 gfx::Size size(preferred_title_size_); | 193 gfx::Size size(preferred_title_size_); |
| 190 size.Enlarge(21, 9); | 194 size.Enlarge(GetInsets().width(), GetInsets().height()); |
| 191 const int kTabMinWidth = 54; | |
| 192 if (size.width() < kTabMinWidth) | |
| 193 size.set_width(kTabMinWidth); | |
| 194 return size; | 195 return size; |
| 195 } | 196 } |
| 196 | 197 |
| 197 void Tab::Layout() { | |
| 198 gfx::Rect bounds = GetLocalBounds(); | |
| 199 bounds.Inset(0, 1, 0, 0); | |
| 200 bounds.ClampToCenteredSize(preferred_title_size_); | |
| 201 title_->SetBoundsRect(bounds); | |
| 202 } | |
| 203 | |
| 204 const char* Tab::GetClassName() const { | 198 const char* Tab::GetClassName() const { |
| 205 return kViewClassName; | 199 return kViewClassName; |
| 206 } | 200 } |
| 207 | 201 |
| 208 void Tab::SetState(TabState tab_state) { | 202 void Tab::SetState(TabState tab_state) { |
| 209 if (tab_state == tab_state_) | 203 if (tab_state == tab_state_) |
| 210 return; | 204 return; |
| 211 tab_state_ = tab_state; | 205 tab_state_ = tab_state; |
| 212 OnStateChanged(); | 206 OnStateChanged(); |
| 213 SchedulePaint(); | 207 SchedulePaint(); |
| 214 } | 208 } |
| 215 | 209 |
| 216 bool Tab::ContainerHasFocus() { | |
| 217 return tabbed_pane_->HasFocus(); | |
| 218 } | |
| 219 | |
| 220 void Tab::OnFocus() { | 210 void Tab::OnFocus() { |
| 221 OnStateChanged(); | 211 OnStateChanged(); |
| 222 // When the tab gains focus, send an accessibility event indicating that the | 212 // 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 | 213 // 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 | 214 // with focus will send an AX_EVENT_FOCUS of its own, so there's no need to |
| 225 // send one in OnBlur(). | 215 // send one in OnBlur(). |
| 226 if (contents()) | 216 if (contents()) |
| 227 contents()->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); | 217 contents()->NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS, true); |
| 228 SchedulePaint(); | 218 SchedulePaint(); |
| 229 } | 219 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 295 | 285 |
| 296 // Draw the lighter-colored stroke first, then draw the heavier stroke over | 286 // 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 | 287 // the bottom of it. This is fine because the heavier stroke has 1.0 alpha, so |
| 298 // the lighter stroke won't show through. | 288 // the lighter stroke won't show through. |
| 299 canvas->DrawRect(bounds, paint); | 289 canvas->DrawRect(bounds, paint); |
| 300 canvas->FillRect( | 290 canvas->FillRect( |
| 301 gfx::Rect(0, height() - kBorderStrokeWidth, width(), kBorderStrokeWidth), | 291 gfx::Rect(0, height() - kBorderStrokeWidth, width(), kBorderStrokeWidth), |
| 302 base_color); | 292 base_color); |
| 303 } | 293 } |
| 304 | 294 |
| 295 gfx::Size MdTab::GetPreferredSize() const { | |
| 296 return gfx::Size(Tab::GetPreferredSize().width(), kHarmonyTabStripTabHeight); | |
| 297 } | |
| 298 | |
| 305 // static | 299 // static |
| 306 const char TabStrip::kViewClassName[] = "TabStrip"; | 300 const char TabStrip::kViewClassName[] = "TabStrip"; |
| 307 | 301 |
| 308 TabStrip::TabStrip(TabbedPane* tabbed_pane) : tabbed_pane_(tabbed_pane) {} | 302 TabStrip::TabStrip() { |
| 303 BoxLayout* layout = new BoxLayout(BoxLayout::kHorizontal, 9, 0, 0); | |
|
msw
2016/10/12 20:18:35
ditto nit: 9 -> constant, shared if possible.
Elly Fong-Jones
2016/10/12 21:23:05
Done.
| |
| 304 layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START); | |
| 305 layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END); | |
| 306 layout->SetDefaultFlex(0); | |
| 307 SetLayoutManager(layout); | |
| 308 } | |
| 309 | 309 |
| 310 TabStrip::~TabStrip() {} | 310 TabStrip::~TabStrip() {} |
| 311 | 311 |
| 312 gfx::Size TabStrip::GetPreferredSize() const { | |
| 313 gfx::Size size; | |
| 314 for (int i = 0; i < child_count(); ++i) { | |
| 315 const gfx::Size child_size = child_at(i)->GetPreferredSize(); | |
| 316 size.SetSize(size.width() + child_size.width(), | |
| 317 std::max(size.height(), child_size.height())); | |
| 318 } | |
| 319 return size; | |
| 320 } | |
| 321 | |
| 322 void TabStrip::Layout() { | |
| 323 const int kTabOffset = 9; | |
| 324 int x = kTabOffset; // Layout tabs with an offset to the tabstrip border. | |
| 325 for (int i = 0; i < child_count(); ++i) { | |
| 326 gfx::Size ps = child_at(i)->GetPreferredSize(); | |
| 327 child_at(i)->SetBounds(x, 0, ps.width(), ps.height()); | |
| 328 x = child_at(i)->bounds().right(); | |
| 329 } | |
| 330 } | |
| 331 | |
| 332 const char* TabStrip::GetClassName() const { | 312 const char* TabStrip::GetClassName() const { |
| 333 return kViewClassName; | 313 return kViewClassName; |
| 334 } | 314 } |
| 335 | 315 |
| 336 void TabStrip::OnPaint(gfx::Canvas* canvas) { | 316 void TabStrip::OnPaintBorder(gfx::Canvas* canvas) { |
| 337 OnPaintBackground(canvas); | |
| 338 | |
| 339 // Draw the TabStrip border. | |
| 340 SkPaint paint; | 317 SkPaint paint; |
| 341 paint.setColor(kTabBorderColor); | 318 paint.setColor(kTabBorderColor); |
| 342 paint.setStrokeWidth(kTabBorderThickness); | 319 paint.setStrokeWidth(kTabBorderThickness); |
| 343 SkScalar line_y = SkIntToScalar(height()) - (kTabBorderThickness / 2); | 320 SkScalar line_y = SkIntToScalar(height()) - (kTabBorderThickness / 2); |
| 344 SkScalar line_end = SkIntToScalar(width()); | 321 SkScalar line_end = SkIntToScalar(width()); |
| 345 int selected_tab_index = tabbed_pane_->selected_tab_index(); | 322 int selected_tab_index = GetSelectedTabIndex(); |
| 346 if (selected_tab_index >= 0) { | 323 if (selected_tab_index >= 0) { |
| 347 Tab* selected_tab = tabbed_pane_->GetTabAt(selected_tab_index); | 324 Tab* selected_tab = GetTabAtIndex(selected_tab_index); |
| 348 SkPath path; | 325 SkPath path; |
| 349 SkScalar tab_height = | 326 SkScalar tab_height = |
| 350 SkIntToScalar(selected_tab->height()) - kTabBorderThickness; | 327 SkIntToScalar(selected_tab->height()) - kTabBorderThickness; |
| 351 SkScalar tab_width = | 328 SkScalar tab_width = |
| 352 SkIntToScalar(selected_tab->width()) - kTabBorderThickness; | 329 SkIntToScalar(selected_tab->width()) - kTabBorderThickness; |
| 353 SkScalar tab_start = SkIntToScalar(selected_tab->GetMirroredX()); | 330 SkScalar tab_start = SkIntToScalar(selected_tab->GetMirroredX()); |
| 354 path.moveTo(0, line_y); | 331 path.moveTo(0, line_y); |
| 355 path.rLineTo(tab_start, 0); | 332 path.rLineTo(tab_start, 0); |
| 356 path.rLineTo(0, -tab_height); | 333 path.rLineTo(0, -tab_height); |
| 357 path.rLineTo(tab_width, 0); | 334 path.rLineTo(tab_width, 0); |
| 358 path.rLineTo(0, tab_height); | 335 path.rLineTo(0, tab_height); |
| 359 path.lineTo(line_end, line_y); | 336 path.lineTo(line_end, line_y); |
| 360 | 337 |
| 361 SkPaint paint; | 338 SkPaint paint; |
| 362 paint.setStyle(SkPaint::kStroke_Style); | 339 paint.setStyle(SkPaint::kStroke_Style); |
| 363 paint.setColor(kTabBorderColor); | 340 paint.setColor(kTabBorderColor); |
| 364 paint.setStrokeWidth(kTabBorderThickness); | 341 paint.setStrokeWidth(kTabBorderThickness); |
| 365 canvas->DrawPath(path, paint); | 342 canvas->DrawPath(path, paint); |
| 366 } else { | 343 } else { |
| 367 canvas->sk_canvas()->drawLine(0, line_y, line_end, line_y, paint); | 344 canvas->sk_canvas()->drawLine(0, line_y, line_end, line_y, paint); |
| 368 } | 345 } |
| 369 } | 346 } |
| 370 | 347 |
| 371 MdTabStrip::MdTabStrip(TabbedPane* tabbed_pane) : TabStrip(tabbed_pane) { | 348 Tab* TabStrip::GetTabAtIndex(int index) const { |
| 349 return static_cast<Tab*>(const_cast<View*>(child_at(index))); | |
| 350 } | |
| 351 | |
| 352 int TabStrip::GetSelectedTabIndex() const { | |
| 353 for (int i = 0; i < child_count(); ++i) | |
| 354 if (GetTabAtIndex(i)->selected()) | |
| 355 return i; | |
| 356 return -1; | |
| 357 } | |
| 358 | |
| 359 Tab* TabStrip::GetSelectedTab() const { | |
| 360 int index = GetSelectedTabIndex(); | |
| 361 return index >= 0 ? GetTabAtIndex(index) : nullptr; | |
| 362 } | |
| 363 | |
| 364 Tab* TabStrip::GetTabAtDeltaFromSelected(int delta) const { | |
| 365 int index = (GetSelectedTabIndex() + delta) % child_count(); | |
| 366 if (index < 0) | |
| 367 index += child_count(); | |
| 368 return GetTabAtIndex(index); | |
| 369 } | |
| 370 | |
| 371 MdTabStrip::MdTabStrip() { | |
| 372 BoxLayout* layout = | 372 BoxLayout* layout = |
| 373 new BoxLayout(BoxLayout::kHorizontal, 0, kHarmonyTabStripVerticalPad, 0); | 373 new BoxLayout(BoxLayout::kHorizontal, 0, kHarmonyTabStripVerticalPad, 0); |
| 374 layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); | 374 layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER); |
| 375 layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); | 375 layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_STRETCH); |
| 376 layout->SetDefaultFlex(1); | 376 layout->SetDefaultFlex(1); |
| 377 SetLayoutManager(layout); | 377 SetLayoutManager(layout); |
| 378 } | 378 } |
| 379 | 379 |
| 380 MdTabStrip::~MdTabStrip() {} | 380 MdTabStrip::~MdTabStrip() {} |
| 381 | 381 |
| 382 gfx::Size MdTabStrip::GetPreferredSize() const { | 382 // The tab strip "border" is drawn as part of the tabs. |
| 383 return gfx::Size(width(), | 383 void MdTabStrip::OnPaintBorder(gfx::Canvas* canvas) { } |
|
msw
2016/10/12 20:18:35
nit: {}
Elly Fong-Jones
2016/10/12 21:23:05
Done.
| |
| 384 kHarmonyTabStripVerticalPad * 2 + kHarmonyTabStripTabHeight); | |
| 385 } | |
| 386 | |
| 387 // Let this class's LayoutManager handle the layout. | |
| 388 void MdTabStrip::Layout() { | |
| 389 return View::Layout(); | |
| 390 } | |
| 391 | |
| 392 // The tab strip "border" is drawn as part of the tabs, so all this method needs | |
| 393 // to do is paint the background. | |
| 394 void MdTabStrip::OnPaint(gfx::Canvas* canvas) { | |
| 395 OnPaintBackground(canvas); | |
| 396 } | |
| 397 | 384 |
| 398 TabbedPane::TabbedPane() | 385 TabbedPane::TabbedPane() |
| 399 : listener_(NULL), | 386 : listener_(NULL), |
| 400 tab_strip_(ui::MaterialDesignController::IsSecondaryUiMaterial() | 387 tab_strip_(ui::MaterialDesignController::IsSecondaryUiMaterial() |
| 401 ? new MdTabStrip(this) | 388 ? new MdTabStrip |
| 402 : new TabStrip(this)), | 389 : new TabStrip), |
| 403 contents_(new View()), | 390 contents_(new View()) { |
| 404 selected_tab_index_(-1) { | |
| 405 AddChildView(tab_strip_); | 391 AddChildView(tab_strip_); |
| 406 AddChildView(contents_); | 392 AddChildView(contents_); |
| 407 } | 393 } |
| 408 | 394 |
| 409 TabbedPane::~TabbedPane() {} | 395 TabbedPane::~TabbedPane() {} |
| 410 | 396 |
| 397 int TabbedPane::GetSelectedTabIndex() const { | |
| 398 return tab_strip_->GetSelectedTabIndex(); | |
| 399 } | |
| 400 | |
| 411 int TabbedPane::GetTabCount() { | 401 int TabbedPane::GetTabCount() { |
| 412 DCHECK_EQ(tab_strip_->child_count(), contents_->child_count()); | 402 DCHECK_EQ(tab_strip_->child_count(), contents_->child_count()); |
| 413 return contents_->child_count(); | 403 return contents_->child_count(); |
| 414 } | 404 } |
| 415 | 405 |
| 416 void TabbedPane::AddTab(const base::string16& title, View* contents) { | 406 void TabbedPane::AddTab(const base::string16& title, View* contents) { |
| 417 AddTabAtIndex(tab_strip_->child_count(), title, contents); | 407 AddTabAtIndex(tab_strip_->child_count(), title, contents); |
| 418 } | 408 } |
| 419 | 409 |
| 420 void TabbedPane::AddTabAtIndex(int index, | 410 void TabbedPane::AddTabAtIndex(int index, |
| 421 const base::string16& title, | 411 const base::string16& title, |
| 422 View* contents) { | 412 View* contents) { |
| 423 DCHECK(index >= 0 && index <= GetTabCount()); | 413 DCHECK(index >= 0 && index <= GetTabCount()); |
| 424 contents->SetVisible(false); | 414 contents->SetVisible(false); |
| 425 | 415 |
| 426 tab_strip_->AddChildViewAt( | 416 tab_strip_->AddChildViewAt( |
| 427 ui::MaterialDesignController::IsSecondaryUiMaterial() | 417 ui::MaterialDesignController::IsSecondaryUiMaterial() |
| 428 ? new MdTab(this, title, contents) | 418 ? new MdTab(this, title, contents) |
| 429 : new Tab(this, title, contents), | 419 : new Tab(this, title, contents), |
| 430 index); | 420 index); |
| 431 contents_->AddChildViewAt(contents, index); | 421 contents_->AddChildViewAt(contents, index); |
| 432 // TODO(ellyjones): if index < selected_tab_index(), selected_tab_index() gets | 422 if (!GetSelectedTab()) |
| 433 // out of sync with which tab believes it is selected. This class should | |
| 434 // directly ask Tabs whether they are selected. | |
| 435 if (selected_tab_index() < 0) | |
| 436 SelectTabAt(index); | 423 SelectTabAt(index); |
| 437 | 424 |
| 438 PreferredSizeChanged(); | 425 PreferredSizeChanged(); |
| 439 } | 426 } |
| 440 | 427 |
| 441 void TabbedPane::SelectTabAt(int index) { | 428 void TabbedPane::SelectTab(Tab* new_selected_tab) { |
| 442 DCHECK(index >= 0 && index < GetTabCount()); | 429 Tab* old_selected_tab = tab_strip_->GetSelectedTab(); |
| 443 if (index == selected_tab_index()) | 430 if (old_selected_tab == new_selected_tab) |
| 444 return; | 431 return; |
| 445 | 432 |
| 446 Tab* old_selected_tab = GetSelectedTab(); | |
| 447 Tab* new_selected_tab = GetTabAt(index); | |
| 448 new_selected_tab->SetSelected(true); | 433 new_selected_tab->SetSelected(true); |
| 449 selected_tab_index_ = index; | |
| 450 if (old_selected_tab) { | 434 if (old_selected_tab) { |
| 451 if (old_selected_tab->HasFocus()) | 435 if (old_selected_tab->HasFocus()) |
| 452 new_selected_tab->RequestFocus(); | 436 new_selected_tab->RequestFocus(); |
| 453 old_selected_tab->SetSelected(false); | 437 old_selected_tab->SetSelected(false); |
| 454 } | 438 } |
| 455 tab_strip_->SchedulePaint(); | 439 tab_strip_->SchedulePaint(); |
| 456 | 440 |
| 457 FocusManager* focus_manager = new_selected_tab->contents()->GetFocusManager(); | 441 FocusManager* focus_manager = new_selected_tab->contents()->GetFocusManager(); |
| 458 if (focus_manager) { | 442 if (focus_manager) { |
| 459 const View* focused_view = focus_manager->GetFocusedView(); | 443 const View* focused_view = focus_manager->GetFocusedView(); |
| 460 if (focused_view && contents_->Contains(focused_view) && | 444 if (focused_view && contents_->Contains(focused_view) && |
| 461 !new_selected_tab->contents()->Contains(focused_view)) | 445 !new_selected_tab->contents()->Contains(focused_view)) |
| 462 focus_manager->SetFocusedView(new_selected_tab->contents()); | 446 focus_manager->SetFocusedView(new_selected_tab->contents()); |
| 463 } | 447 } |
| 464 | 448 |
| 465 if (listener()) | 449 if (listener()) |
| 466 listener()->TabSelectedAt(index); | 450 listener()->TabSelectedAt(tab_strip_->GetIndexOf(new_selected_tab)); |
| 467 } | 451 } |
| 468 | 452 |
| 469 void TabbedPane::SelectTab(Tab* tab) { | 453 void TabbedPane::SelectTabAt(int index) { |
| 470 const int index = tab_strip_->GetIndexOf(tab); | 454 Tab* tab = tab_strip_->GetTabAtIndex(index); |
| 471 if (index >= 0) | 455 if (tab) |
| 472 SelectTabAt(index); | 456 SelectTab(tab); |
| 473 } | 457 } |
| 474 | 458 |
| 475 gfx::Size TabbedPane::GetPreferredSize() const { | 459 gfx::Size TabbedPane::GetPreferredSize() const { |
| 476 gfx::Size size; | 460 gfx::Size size; |
| 477 for (int i = 0; i < contents_->child_count(); ++i) | 461 for (int i = 0; i < contents_->child_count(); ++i) |
| 478 size.SetToMax(contents_->child_at(i)->GetPreferredSize()); | 462 size.SetToMax(contents_->child_at(i)->GetPreferredSize()); |
| 479 size.Enlarge(0, tab_strip_->GetPreferredSize().height()); | 463 size.Enlarge(0, tab_strip_->GetPreferredSize().height()); |
| 480 return size; | 464 return size; |
| 481 } | 465 } |
| 482 | 466 |
| 483 Tab* TabbedPane::GetTabAt(int index) { | |
| 484 return static_cast<Tab*>(tab_strip_->child_at(index)); | |
| 485 } | |
| 486 | |
| 487 Tab* TabbedPane::GetSelectedTab() { | 467 Tab* TabbedPane::GetSelectedTab() { |
| 488 return selected_tab_index() >= 0 ? GetTabAt(selected_tab_index()) : nullptr; | 468 return tab_strip_->GetSelectedTab(); |
| 489 } | 469 } |
| 490 | 470 |
| 491 bool TabbedPane::MoveSelectionBy(int delta) { | 471 bool TabbedPane::MoveSelectionBy(int delta) { |
| 492 const int tab_count = GetTabCount(); | 472 if (contents_->child_count() <= 1) |
| 493 if (tab_count <= 1) | |
| 494 return false; | 473 return false; |
| 495 int next_selected_index = (selected_tab_index() + delta) % tab_count; | 474 SelectTab(tab_strip_->GetTabAtDeltaFromSelected(delta)); |
|
msw
2016/10/12 20:18:35
nit: it might make sense to just keep this inlined
Elly Fong-Jones
2016/10/12 21:23:05
I de-inlined it so TabbedPane could stop dealing w
| |
| 496 if (next_selected_index < 0) | |
| 497 next_selected_index += tab_count; | |
| 498 SelectTabAt(next_selected_index); | |
| 499 return true; | 475 return true; |
| 500 } | 476 } |
| 501 | 477 |
| 502 void TabbedPane::Layout() { | 478 void TabbedPane::Layout() { |
| 503 const gfx::Size size = tab_strip_->GetPreferredSize(); | 479 const gfx::Size size = tab_strip_->GetPreferredSize(); |
| 504 tab_strip_->SetBounds(0, 0, width(), size.height()); | 480 tab_strip_->SetBounds(0, 0, width(), size.height()); |
| 505 contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(), | 481 contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(), |
| 506 std::max(0, height() - size.height())); | 482 std::max(0, height() - size.height())); |
| 507 for (int i = 0; i < contents_->child_count(); ++i) | 483 for (int i = 0; i < contents_->child_count(); ++i) |
| 508 contents_->child_at(i)->SetSize(contents_->size()); | 484 contents_->child_at(i)->SetSize(contents_->size()); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 530 | 506 |
| 531 View* TabbedPane::GetSelectedTabContentView() { | 507 View* TabbedPane::GetSelectedTabContentView() { |
| 532 return GetSelectedTab() ? GetSelectedTab()->contents() : nullptr; | 508 return GetSelectedTab() ? GetSelectedTab()->contents() : nullptr; |
| 533 } | 509 } |
| 534 | 510 |
| 535 void TabbedPane::GetAccessibleState(ui::AXViewState* state) { | 511 void TabbedPane::GetAccessibleState(ui::AXViewState* state) { |
| 536 state->role = ui::AX_ROLE_TAB_LIST; | 512 state->role = ui::AX_ROLE_TAB_LIST; |
| 537 } | 513 } |
| 538 | 514 |
| 539 } // namespace views | 515 } // namespace views |
| OLD | NEW |