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 |