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 "ui/base/accessibility/accessible_view_state.h" | 8 #include "ui/base/accessibility/accessible_view_state.h" |
| 9 #include "ui/base/keycodes/keyboard_codes.h" | 9 #include "ui/base/keycodes/keyboard_codes.h" |
| 10 #include "ui/views/controls/native/native_view_host.h" | 10 #include "ui/gfx/canvas.h" |
| 11 #include "ui/views/controls/tabbed_pane/native_tabbed_pane_views.h" | 11 #include "ui/gfx/font.h" |
| 12 #include "ui/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h" | |
| 13 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h" | 12 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h" |
| 13 #include "ui/views/layout/layout_manager.h" | |
| 14 #include "ui/views/widget/widget.h" | 14 #include "ui/views/widget/widget.h" |
| 15 | 15 |
| 16 // TODO(markusheintz): This should be removed once the native Windows tabbed | |
| 17 // pane is not used anymore (http://crbug.com/138059). | |
| 18 #if defined(OS_WIN) && !defined(USE_AURA) | |
| 19 #include "ui/views/controls/tabbed_pane/native_tabbed_pane_win.h" | |
| 20 #endif | |
| 21 | |
| 22 namespace { | 16 namespace { |
| 23 | 17 |
| 24 views::NativeTabbedPaneWrapper* CreateNativeWrapper( | 18 // TODO(markusheintz|msw): Use NativeTheme colors. |
| 25 views::TabbedPane* tabbed_pane) { | 19 const SkColor kTabTitleColor_Inactive = SkColorSetRGB(0x66, 0x66, 0x66); |
| 26 #if defined(OS_WIN) && !defined(USE_AURA) | 20 const SkColor kTabTitleColor_Active = SkColorSetRGB(0x20, 0x20, 0x20); |
| 27 if (tabbed_pane->use_native_win_control()) | 21 const SkColor kTabTitleColor_Pressed = SkColorSetRGB(0x33, 0x33, 0x33); |
| 28 return new views::NativeTabbedPaneWin(tabbed_pane); | 22 const SkColor kTabTitleColor_Hovered = SkColorSetRGB(0x22, 0x22, 0x22); |
| 29 #endif | 23 const SkColor kTabBackgroundColor_Active = SK_ColorWHITE; |
| 30 return new views::NativeTabbedPaneViews(tabbed_pane); | 24 const SkColor kTabBorderColor = SkColorSetRGB(0xCC, 0xCC, 0xCC); |
| 31 } | 25 const SkScalar kTabBorderThickness = 1.0f; |
| 26 const SkScalar kTabBorderRadius = 2.0f; | |
| 32 | 27 |
| 33 } // namespace | 28 } // namespace |
| 34 | 29 |
| 35 namespace views { | 30 namespace views { |
| 36 | 31 |
| 32 class Tab : public View { | |
| 33 public: | |
| 34 Tab(TabStrip* tab_strip, const string16& title, View* contents) | |
| 35 : tab_strip_(tab_strip), | |
| 36 title_(title), | |
| 37 contents_(contents), | |
| 38 title_color_(kTabTitleColor_Inactive) {} | |
| 39 virtual ~Tab() {} | |
| 40 | |
| 41 static int GetMinimumTabHeight() { | |
| 42 return gfx::Font().GetHeight() + 10; | |
| 43 } | |
| 44 | |
| 45 static View* GetContents(View* tab) { | |
| 46 return static_cast<Tab*>(tab)->contents_; | |
| 47 } | |
| 48 | |
| 49 void OnSelectedStateChanged(bool selected); | |
| 50 | |
| 51 // Overridden from View: | |
| 52 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; | |
| 53 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; | |
| 54 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; | |
| 55 virtual void OnMouseCaptureLost() OVERRIDE; | |
| 56 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE; | |
| 57 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE; | |
| 58 virtual gfx::Size GetPreferredSize() OVERRIDE { | |
|
sky
2013/02/06 17:29:55
Be consistant, inline it all or none of it.
msw
2013/02/07 00:29:36
Done.
| |
| 59 const int kTabMinWidth = 54; | |
| 60 gfx::Size ps(GetTabTitleFont().GetStringWidth(title_), | |
| 61 GetMinimumTabHeight()); | |
| 62 ps.Enlarge(30, 10); | |
| 63 if (ps.width() < kTabMinWidth) | |
| 64 ps.set_width(kTabMinWidth); | |
| 65 return ps; | |
| 66 } | |
| 67 | |
| 68 // Overridden from ui::EventHandler. | |
| 69 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; | |
| 70 | |
| 71 private: | |
| 72 void PaintTabBackground(gfx::Canvas* canvas) { | |
| 73 // Fill the background. Note that we don't constrain to the bounds as | |
| 74 // canvas is already clipped for us. | |
| 75 canvas->DrawColor(kTabBackgroundColor_Active); | |
| 76 } | |
| 77 | |
| 78 void PaintTabBorder(gfx::Canvas* canvas) { | |
| 79 SkPath path; | |
| 80 SkRect bounds = { 0, 0, SkIntToScalar(width()), SkIntToScalar(height()) }; | |
| 81 SkScalar radii[8] = { kTabBorderRadius, kTabBorderRadius, | |
| 82 kTabBorderRadius, kTabBorderRadius, | |
| 83 0, 0, | |
| 84 0, 0 }; | |
| 85 path.addRoundRect(bounds, radii, SkPath::kCW_Direction); | |
| 86 | |
| 87 SkPaint paint; | |
| 88 paint.setAntiAlias(true); | |
| 89 paint.setStyle(SkPaint::kStroke_Style); | |
| 90 paint.setColor(kTabBorderColor); | |
| 91 paint.setStrokeWidth(kTabBorderThickness * 2); | |
| 92 | |
| 93 canvas->DrawPath(path, paint); | |
| 94 } | |
| 95 | |
| 96 void PaintTabTitle(gfx::Canvas* canvas, bool selected) { | |
| 97 int text_width = GetTabTitleFont().GetStringWidth(title_); | |
| 98 int text_height = GetTabTitleFont().GetHeight(); | |
| 99 int text_x = (width() - text_width) / 2; | |
| 100 int text_y = 5; | |
| 101 gfx::Rect text_rect(text_x, text_y, text_width, text_height); | |
| 102 canvas->DrawStringInt(title_, GetTabTitleFont(), title_color_, text_rect); | |
| 103 } | |
| 104 | |
| 105 void SetTitleColor(SkColor color) { | |
| 106 title_color_ = color; | |
| 107 SchedulePaint(); | |
| 108 } | |
| 109 | |
| 110 const gfx::Font& GetTabTitleFont() { | |
| 111 static gfx::Font* title_font = NULL; | |
| 112 if (!title_font) | |
| 113 title_font = new gfx::Font(gfx::Font().DeriveFont(0, gfx::Font::BOLD)); | |
| 114 return *title_font; | |
| 115 } | |
| 116 | |
| 117 TabStrip* tab_strip_; | |
| 118 string16 title_; | |
| 119 View* contents_; | |
| 120 SkColor title_color_; | |
| 121 | |
| 122 DISALLOW_COPY_AND_ASSIGN(Tab); | |
| 123 }; | |
| 124 | |
| 125 class TabStrip : public View { | |
| 126 public: | |
| 127 explicit TabStrip(TabbedPane* owner) | |
| 128 : owner_(owner), | |
| 129 selected_tab_(NULL) { | |
| 130 const int kCount = 4; | |
| 131 // The gradient colors are derived from the tabbed panes used for the | |
| 132 // WebUI. | |
| 133 SkColor colors[] = { | |
| 134 SkColorSetRGB(0xff, 0xff, 0xff), | |
| 135 SkColorSetRGB(0xff, 0xff, 0xff), | |
| 136 SkColorSetRGB(0xfa, 0xfa, 0xfa), | |
| 137 SkColorSetRGB(0xf2, 0xf2, 0xf2) | |
| 138 }; | |
| 139 // The relative positions of the gradient colors are derived from the | |
| 140 // tabbed panes used for the WebUI. | |
| 141 SkScalar pos[4] = {0.0f, 0.6f, 0.8f, 1.0f}; | |
| 142 set_background(Background::CreateVerticalMultiColorGradientBackground( | |
| 143 colors, pos, kCount)); | |
| 144 } | |
| 145 virtual ~TabStrip() {} | |
| 146 | |
| 147 void SelectTab(View* tab) { | |
|
sky
2013/02/06 17:29:55
This should take a Tab* and selected_tab_ should b
msw
2013/02/07 00:29:37
Moot.
| |
| 148 if (tab == selected_tab_) | |
| 149 return; | |
| 150 if (selected_tab_) | |
| 151 static_cast<Tab*>(selected_tab_)->OnSelectedStateChanged(false); | |
| 152 selected_tab_ = tab; | |
| 153 static_cast<Tab*>(selected_tab_)->OnSelectedStateChanged(true); | |
| 154 owner_->TabSelectionChanged(tab); | |
| 155 } | |
| 156 | |
| 157 bool IsTabSelected(const View* tab) const { | |
| 158 return tab == selected_tab_; | |
| 159 } | |
| 160 | |
| 161 int GetSelectedIndex() const { | |
| 162 return GetIndexOf(selected_tab_); | |
| 163 } | |
| 164 | |
| 165 View* selected_tab() { return selected_tab_; } | |
| 166 | |
| 167 View* RemoveTabAt(int index) { | |
| 168 View* contents = Tab::GetContents(child_at(index)); | |
| 169 delete child_at(index); | |
| 170 return contents; | |
|
sky
2013/02/06 17:29:55
What if contents == selected_tab_ ?
msw
2013/02/07 00:29:37
Moot.
| |
| 171 } | |
| 172 | |
| 173 // Overridden from View: | |
| 174 virtual gfx::Size GetPreferredSize() OVERRIDE { | |
| 175 return gfx::Size(50, Tab::GetMinimumTabHeight()); | |
| 176 } | |
| 177 virtual void Layout() OVERRIDE { | |
| 178 const int kTabOffset = 18; | |
| 179 int x = kTabOffset; // Layout tabs with an offset to the tabstrip border. | |
| 180 for (int i = 0; i < child_count(); ++i) { | |
| 181 gfx::Size ps = child_at(i)->GetPreferredSize(); | |
| 182 child_at(i)->SetBounds(x, 0, ps.width(), ps.height()); | |
| 183 x = child_at(i)->bounds().right(); | |
| 184 } | |
| 185 } | |
| 186 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { | |
| 187 OnPaintBackground(canvas); | |
| 188 | |
| 189 // Draw the TabStrip border. | |
| 190 SkPaint paint; | |
| 191 paint.setColor(kTabBorderColor); | |
| 192 paint.setStrokeWidth(kTabBorderThickness); | |
| 193 SkScalar line_y = SkIntToScalar(height()) - kTabBorderThickness; | |
| 194 SkScalar line_width = SkIntToScalar(width()); | |
| 195 canvas->sk_canvas()->drawLine(0, line_y, line_width, line_y, paint); | |
| 196 } | |
| 197 | |
| 198 private: | |
| 199 TabbedPane* owner_; | |
| 200 View* selected_tab_; | |
| 201 | |
| 202 DISALLOW_COPY_AND_ASSIGN(TabStrip); | |
| 203 }; | |
| 204 | |
| 205 void Tab::OnSelectedStateChanged(bool selected) { | |
| 206 SetTitleColor(selected ? kTabTitleColor_Active : kTabTitleColor_Inactive); | |
| 207 } | |
| 208 | |
| 209 void Tab::OnPaint(gfx::Canvas* canvas) { | |
| 210 bool selected = tab_strip_->IsTabSelected(this); | |
| 211 if (selected) { | |
| 212 PaintTabBackground(canvas); | |
| 213 PaintTabBorder(canvas); | |
| 214 } | |
| 215 PaintTabTitle(canvas, selected); | |
| 216 } | |
| 217 | |
| 218 bool Tab::OnMousePressed(const ui::MouseEvent& event) { | |
| 219 SetTitleColor(kTabTitleColor_Pressed); | |
| 220 return true; | |
| 221 } | |
| 222 | |
| 223 void Tab::OnMouseReleased(const ui::MouseEvent& event) { | |
| 224 SetTitleColor(kTabTitleColor_Hovered); | |
| 225 tab_strip_->SelectTab(this); | |
|
sky
2013/02/06 17:29:55
Only does this if this contains the location in ev
msw
2013/02/07 00:29:37
Done.
| |
| 226 } | |
| 227 | |
| 228 void Tab::OnGestureEvent(ui::GestureEvent* event) { | |
| 229 switch (event->type()) { | |
| 230 case ui::ET_GESTURE_TAP_DOWN: | |
| 231 SetTitleColor(kTabTitleColor_Pressed); | |
| 232 break; | |
| 233 case ui::ET_GESTURE_TAP: | |
| 234 // SelectTab also sets the right tab color. | |
| 235 tab_strip_->SelectTab(this); | |
| 236 break; | |
| 237 case ui::ET_GESTURE_TAP_CANCEL: | |
| 238 SetTitleColor(tab_strip_->IsTabSelected(this) ? kTabTitleColor_Active : | |
| 239 kTabTitleColor_Inactive); | |
| 240 break; | |
| 241 default: | |
| 242 break; | |
| 243 } | |
| 244 event->SetHandled(); | |
| 245 } | |
| 246 | |
| 247 void Tab::OnMouseCaptureLost() { | |
| 248 SetTitleColor(kTabTitleColor_Inactive); | |
| 249 } | |
| 250 | |
| 251 void Tab::OnMouseEntered(const ui::MouseEvent& event) { | |
| 252 SetTitleColor(tab_strip_->IsTabSelected(this) ? kTabTitleColor_Active : | |
| 253 kTabTitleColor_Hovered); | |
| 254 } | |
| 255 | |
| 256 void Tab::OnMouseExited(const ui::MouseEvent& event) { | |
| 257 SetTitleColor(tab_strip_->IsTabSelected(this) ? kTabTitleColor_Active : | |
| 258 kTabTitleColor_Inactive); | |
| 259 } | |
| 260 | |
| 261 // Custom layout manager that takes care of sizing and displaying the tab pages. | |
| 262 class TabLayout : public LayoutManager { | |
| 263 public: | |
| 264 TabLayout() {} | |
| 265 | |
| 266 // Switches to the tab page identified. | |
| 267 void SwitchToPage(View* host, View* page) { | |
| 268 for (int i = 0; i < host->child_count(); ++i) { | |
| 269 View* child = host->child_at(i); | |
| 270 // The child might not have been laid out yet. | |
| 271 if (child == page) | |
| 272 child->SetBoundsRect(host->GetContentsBounds()); | |
| 273 child->SetVisible(child == page); | |
| 274 } | |
| 275 | |
| 276 FocusManager* focus_manager = page->GetFocusManager(); | |
| 277 if (focus_manager) { | |
| 278 const View* focused_view = focus_manager->GetFocusedView(); | |
| 279 if (focused_view && host->Contains(focused_view) && | |
| 280 !page->Contains(focused_view)) | |
| 281 focus_manager->SetFocusedView(page); | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 private: | |
| 286 // LayoutManager overrides: | |
| 287 virtual void Layout(View* host) OVERRIDE { | |
| 288 gfx::Rect bounds(host->GetContentsBounds()); | |
| 289 for (int i = 0; i < host->child_count(); ++i) { | |
| 290 View* child = host->child_at(i); | |
| 291 // We only layout visible children, since it may be expensive. | |
| 292 if (child->visible() && child->bounds() != bounds) | |
| 293 child->SetBoundsRect(bounds); | |
| 294 } | |
| 295 } | |
| 296 | |
| 297 virtual gfx::Size GetPreferredSize(View* host) OVERRIDE { | |
| 298 // First, query the preferred sizes to determine a good width. | |
| 299 int width = 0; | |
| 300 for (int i = 0; i < host->child_count(); ++i) { | |
| 301 View* page = host->child_at(i); | |
| 302 width = std::max(width, page->GetPreferredSize().width()); | |
| 303 } | |
| 304 // After we know the width, decide on the height. | |
| 305 return gfx::Size(width, GetPreferredHeightForWidth(host, width)); | |
| 306 } | |
| 307 | |
| 308 virtual int GetPreferredHeightForWidth(View* host, int width) OVERRIDE { | |
| 309 int height = 0; | |
| 310 for (int i = 0; i < host->child_count(); ++i) { | |
| 311 View* page = host->child_at(i); | |
| 312 height = std::max(height, page->GetHeightForWidth(width)); | |
| 313 } | |
| 314 return height; | |
| 315 } | |
| 316 | |
| 317 DISALLOW_COPY_AND_ASSIGN(TabLayout); | |
| 318 }; | |
| 319 | |
| 37 // static | 320 // static |
| 38 const char TabbedPane::kViewClassName[] = "views/TabbedPane"; | 321 const char TabbedPane::kViewClassName[] = "views/TabbedPane"; |
| 39 | 322 |
| 40 TabbedPane::TabbedPane() | 323 TabbedPane::TabbedPane() |
| 41 : native_tabbed_pane_(NULL), | 324 : listener_(NULL), |
| 42 #if defined(OS_WIN) && !defined(USE_AURA) | 325 tab_layout_manager_(new TabLayout), |
| 43 use_native_win_control_(false), | 326 ALLOW_THIS_IN_INITIALIZER_LIST(tab_strip_(new TabStrip(this))), |
| 44 #endif | 327 content_view_(new views::View) { |
| 45 listener_(NULL) { | |
| 46 set_focusable(true); | 328 set_focusable(true); |
| 329 AddChildView(tab_strip_); | |
| 330 AddChildView(content_view_); | |
| 331 content_view_->SetLayoutManager(tab_layout_manager_); | |
| 47 } | 332 } |
| 48 | 333 |
| 49 TabbedPane::~TabbedPane() { | 334 TabbedPane::~TabbedPane() { |
| 50 } | 335 } |
| 51 | 336 |
| 52 int TabbedPane::GetTabCount() { | 337 int TabbedPane::GetTabCount() { |
| 53 return native_tabbed_pane_->GetTabCount(); | 338 return tab_strip_->child_count(); |
| 54 } | 339 } |
| 55 | 340 |
| 56 int TabbedPane::GetSelectedTabIndex() { | 341 int TabbedPane::GetSelectedTabIndex() { |
| 57 return native_tabbed_pane_->GetSelectedTabIndex(); | 342 return tab_strip_->GetSelectedIndex(); |
| 58 } | 343 } |
| 59 | 344 |
| 60 View* TabbedPane::GetSelectedTab() { | 345 View* TabbedPane::GetSelectedTab() { |
| 61 return native_tabbed_pane_->GetSelectedTab(); | 346 return content_view_->child_at(GetSelectedTabIndex()); |
| 347 } | |
| 348 | |
| 349 void TabbedPane::TabSelectionChanged(View* selected) { | |
| 350 tab_layout_manager_->SwitchToPage(content_view_, Tab::GetContents(selected)); | |
| 351 if (listener()) | |
| 352 listener()->TabSelectedAt(tab_strip_->GetIndexOf(selected)); | |
| 62 } | 353 } |
| 63 | 354 |
| 64 void TabbedPane::AddTab(const string16& title, View* contents) { | 355 void TabbedPane::AddTab(const string16& title, View* contents) { |
| 65 native_tabbed_pane_->AddTab(title, contents); | 356 AddTabAtIndex(tab_strip_->child_count(), title, contents, true); |
| 66 PreferredSizeChanged(); | |
| 67 } | 357 } |
| 68 | 358 |
| 69 void TabbedPane::AddTabAtIndex(int index, | 359 void TabbedPane::AddTabAtIndex(int index, |
| 70 const string16& title, | 360 const string16& title, |
| 71 View* contents, | 361 View* contents, |
| 72 bool select_if_first_tab) { | 362 bool select_if_first_tab) { |
| 73 native_tabbed_pane_->AddTabAtIndex(index, title, contents, | 363 DCHECK(index <= static_cast<int>(tab_strip_->child_count())); |
| 74 select_if_first_tab); | 364 contents->set_owned_by_client(); |
| 365 contents->SetVisible(false); | |
| 366 | |
| 367 tab_strip_->AddChildViewAt(new Tab(tab_strip_, title, contents), index); | |
| 368 content_view_->AddChildViewAt(contents, index); | |
| 369 | |
| 370 // Switch to the newly added tab if requested; | |
| 371 if (tab_strip_->child_count() == 1 && select_if_first_tab) | |
| 372 tab_layout_manager_->SwitchToPage(content_view_, contents); | |
| 373 if (!tab_strip_->selected_tab()) | |
| 374 tab_strip_->SelectTab(tab_strip_->child_at(0)); | |
| 75 PreferredSizeChanged(); | 375 PreferredSizeChanged(); |
| 76 } | 376 } |
| 77 | 377 |
| 78 View* TabbedPane::RemoveTabAtIndex(int index) { | 378 View* TabbedPane::RemoveTabAtIndex(int index) { |
| 79 View* tab = native_tabbed_pane_->RemoveTabAtIndex(index); | 379 DCHECK(index >= 0 && index < tab_strip_->child_count()); |
| 380 | |
| 381 if (index < (tab_strip_->child_count() - 1)) { | |
| 382 // Select the next tab. | |
| 383 SelectTabAt(index + 1); | |
| 384 } else { | |
| 385 // We are the last tab, select the previous one. | |
| 386 if (index > 0) { | |
| 387 SelectTabAt(index - 1); | |
| 388 } else { | |
| 389 // That was the last tab. Remove the contents. | |
| 390 content_view_->RemoveAllChildViews(false); | |
| 391 } | |
| 392 } | |
| 393 View* tab = tab_strip_->RemoveTabAt(index); | |
| 80 PreferredSizeChanged(); | 394 PreferredSizeChanged(); |
| 81 return tab; | 395 return tab; |
| 82 } | 396 } |
| 83 | 397 |
| 84 void TabbedPane::SelectTabAt(int index) { | 398 void TabbedPane::SelectTabAt(int index) { |
| 85 native_tabbed_pane_->SelectTabAt(index); | 399 DCHECK((index >= 0) && (index < tab_strip_->child_count())); |
| 400 tab_strip_->SelectTab(tab_strip_->child_at(index)); | |
| 86 } | 401 } |
| 87 | 402 |
| 88 void TabbedPane::SetAccessibleName(const string16& name) { | 403 void TabbedPane::SetAccessibleName(const string16& name) { |
| 89 accessible_name_ = name; | 404 accessible_name_ = name; |
| 90 } | 405 } |
| 91 | 406 |
| 92 gfx::Size TabbedPane::GetPreferredSize() { | 407 gfx::Size TabbedPane::GetPreferredSize() { |
| 93 return native_tabbed_pane_ ? | 408 gfx::Size content_size = content_view_->GetPreferredSize(); |
| 94 native_tabbed_pane_->GetPreferredSize() : gfx::Size(); | 409 return gfx::Size( |
| 410 content_size.width(), | |
| 411 tab_strip_->GetPreferredSize().height() + content_size.height()); | |
| 95 } | 412 } |
| 96 | 413 |
| 97 void TabbedPane::LoadAccelerators() { | 414 void TabbedPane::LoadAccelerators() { |
| 98 // Ctrl+Shift+Tab | 415 // Ctrl+Shift+Tab |
| 99 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, | 416 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, |
| 100 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN)); | 417 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN)); |
| 101 // Ctrl+Tab | 418 // Ctrl+Tab |
| 102 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, ui::EF_CONTROL_DOWN)); | 419 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, ui::EF_CONTROL_DOWN)); |
| 103 } | 420 } |
| 104 | 421 |
| 105 void TabbedPane::Layout() { | 422 void TabbedPane::Layout() { |
| 106 if (native_tabbed_pane_) | 423 gfx::Size ps = tab_strip_->GetPreferredSize(); |
| 107 native_tabbed_pane_->GetView()->SetBounds(0, 0, width(), height()); | 424 tab_strip_->SetBounds(0, 0, width(), ps.height()); |
| 425 content_view_->SetBounds(0, tab_strip_->bounds().bottom(), width(), | |
| 426 std::max(0, height() - ps.height())); | |
| 108 } | 427 } |
| 109 | 428 |
| 110 void TabbedPane::ViewHierarchyChanged(bool is_add, View* parent, View* child) { | 429 void TabbedPane::ViewHierarchyChanged(bool is_add, View* parent, View* child) { |
| 111 if (is_add && !native_tabbed_pane_) { | 430 if (is_add) |
| 112 // The native wrapper's lifetime will be managed by the view hierarchy after | |
| 113 // we call AddChildView. | |
| 114 native_tabbed_pane_ = CreateNativeWrapper(this); | |
| 115 AddChildView(native_tabbed_pane_->GetView()); | |
| 116 LoadAccelerators(); | 431 LoadAccelerators(); |
| 117 } | |
| 118 } | 432 } |
| 119 | 433 |
| 120 bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) { | 434 bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) { |
| 121 // We only accept Ctrl+Tab keyboard events. | 435 // We only accept Ctrl+Tab keyboard events. |
| 122 DCHECK(accelerator.key_code() == ui::VKEY_TAB && accelerator.IsCtrlDown()); | 436 DCHECK(accelerator.key_code() == ui::VKEY_TAB && accelerator.IsCtrlDown()); |
| 123 | 437 |
| 124 int tab_count = GetTabCount(); | 438 int tab_count = GetTabCount(); |
| 125 if (tab_count <= 1) | 439 if (tab_count <= 1) |
| 126 return false; | 440 return false; |
| 127 int selected_tab_index = GetSelectedTabIndex(); | 441 int selected_tab_index = GetSelectedTabIndex(); |
| 128 int next_tab_index = accelerator.IsShiftDown() ? | 442 int next_tab_index = accelerator.IsShiftDown() ? |
| 129 (selected_tab_index - 1) % tab_count : | 443 (selected_tab_index - 1) % tab_count : |
| 130 (selected_tab_index + 1) % tab_count; | 444 (selected_tab_index + 1) % tab_count; |
| 131 // Wrap around. | 445 // Wrap around. |
| 132 if (next_tab_index < 0) | 446 if (next_tab_index < 0) |
| 133 next_tab_index += tab_count; | 447 next_tab_index += tab_count; |
| 134 SelectTabAt(next_tab_index); | 448 SelectTabAt(next_tab_index); |
| 135 return true; | 449 return true; |
| 136 } | 450 } |
| 137 | 451 |
| 138 std::string TabbedPane::GetClassName() const { | 452 std::string TabbedPane::GetClassName() const { |
| 139 return kViewClassName; | 453 return kViewClassName; |
| 140 } | 454 } |
| 141 | 455 |
| 142 void TabbedPane::OnFocus() { | 456 void TabbedPane::OnFocus() { |
| 143 // Forward the focus to the wrapper. | 457 View::OnFocus(); |
| 144 if (native_tabbed_pane_) { | |
| 145 native_tabbed_pane_->SetFocus(); | |
| 146 | 458 |
| 147 View* selected_tab = GetSelectedTab(); | 459 View* selected_tab = GetSelectedTab(); |
| 148 if (selected_tab) { | 460 if (selected_tab) { |
| 149 selected_tab->GetWidget()->NotifyAccessibilityEvent( | 461 selected_tab->GetWidget()->NotifyAccessibilityEvent( |
| 150 selected_tab, ui::AccessibilityTypes::EVENT_FOCUS, true); | 462 selected_tab, ui::AccessibilityTypes::EVENT_FOCUS, true); |
| 151 } | |
| 152 } else { | |
| 153 View::OnFocus(); // Will focus the RootView window (so we still get | |
| 154 // keyboard messages). | |
| 155 } | 463 } |
| 156 } | 464 } |
| 157 | 465 |
| 158 void TabbedPane::OnPaintFocusBorder(gfx::Canvas* canvas) { | |
| 159 if (NativeViewHost::kRenderNativeControlFocus) | |
| 160 View::OnPaintFocusBorder(canvas); | |
| 161 } | |
| 162 | |
| 163 void TabbedPane::GetAccessibleState(ui::AccessibleViewState* state) { | 466 void TabbedPane::GetAccessibleState(ui::AccessibleViewState* state) { |
| 164 state->role = ui::AccessibilityTypes::ROLE_PAGETABLIST; | 467 state->role = ui::AccessibilityTypes::ROLE_PAGETABLIST; |
| 165 state->name = accessible_name_; | 468 state->name = accessible_name_; |
| 166 } | 469 } |
| 167 | 470 |
| 168 } // namespace views | 471 } // namespace views |
| OLD | NEW |