Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: ui/views/controls/tabbed_pane/tabbed_pane.cc

Issue 12211122: Reland Remove NativeTabbedPane[Win|Wrapper]; promote Views impl. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix leak of tab content Views. Created 7 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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" 12 #include "ui/views/controls/label.h"
13 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h" 13 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
14 #include "ui/views/layout/layout_manager.h"
14 #include "ui/views/widget/widget.h" 15 #include "ui/views/widget/widget.h"
15 16
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 { 17 namespace {
23 18
24 views::NativeTabbedPaneWrapper* CreateNativeWrapper( 19 const char kViewClassName[] = "views/TabbedPane";
25 views::TabbedPane* tabbed_pane) { 20
26 #if defined(OS_WIN) && !defined(USE_AURA) 21 // TODO(markusheintz|msw): Use NativeTheme colors.
27 if (tabbed_pane->use_native_win_control()) 22 const SkColor kTabTitleColor_Inactive = SkColorSetRGB(0x66, 0x66, 0x66);
28 return new views::NativeTabbedPaneWin(tabbed_pane); 23 const SkColor kTabTitleColor_Active = SkColorSetRGB(0x20, 0x20, 0x20);
29 #endif 24 const SkColor kTabTitleColor_Pressed = SkColorSetRGB(0x33, 0x33, 0x33);
30 return new views::NativeTabbedPaneViews(tabbed_pane); 25 const SkColor kTabTitleColor_Hovered = SkColorSetRGB(0x22, 0x22, 0x22);
31 } 26 const SkColor kTabBackgroundColor = SK_ColorWHITE;
27 const SkColor kTabBorderColor = SkColorSetRGB(0xCC, 0xCC, 0xCC);
28 const SkScalar kTabBorderThickness = 1.0f;
29 const SkScalar kTabBorderRadius = 2.0f;
32 30
33 } // namespace 31 } // namespace
34 32
35 namespace views { 33 namespace views {
36 34
37 // static 35 // The tab view shown in the tab strip.
38 const char TabbedPane::kViewClassName[] = "views/TabbedPane"; 36 class Tab : public View {
37 public:
38 Tab(TabbedPane* tabbed_pane, const string16& title, View* contents);
39 virtual ~Tab();
40
41 View* contents() const { return contents_; }
42
43 bool selected() const { return contents_->visible(); }
44 void SetSelected(bool selected);
45
46 // Overridden from View:
47 virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
48 virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE;
49 virtual void OnMouseCaptureLost() OVERRIDE;
50 virtual void OnMouseEntered(const ui::MouseEvent& event) OVERRIDE;
51 virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE;
52 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE;
53 virtual gfx::Size GetPreferredSize() OVERRIDE;
54 virtual void Layout() OVERRIDE;
55 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
56
57 private:
58 void SetTitleColor(SkColor color);
59 void PaintTabBorder(gfx::Canvas* canvas);
60
61 TabbedPane* tabbed_pane_;
62 Label* title_;
63 // The content view associated with this tab.
64 View* contents_;
65
66 DISALLOW_COPY_AND_ASSIGN(Tab);
67 };
68
69 // The tab strip shown above the tab contents.
70 class TabStrip : public View {
71 public:
72 TabStrip();
73 virtual ~TabStrip();
74
75 // Overridden from View:
76 virtual gfx::Size GetPreferredSize() OVERRIDE;
77 virtual void Layout() OVERRIDE;
78 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE;
79
80 private:
81 DISALLOW_COPY_AND_ASSIGN(TabStrip);
82 };
83
84 Tab::Tab(TabbedPane* tabbed_pane, const string16& title, View* contents)
85 : tabbed_pane_(tabbed_pane),
86 title_(new Label(title, gfx::Font().DeriveFont(0, gfx::Font::BOLD))),
87 contents_(contents) {
88 SetTitleColor(kTabTitleColor_Inactive);
89 AddChildView(title_);
90 }
91
92 Tab::~Tab() {}
93
94 void Tab::SetSelected(bool selected) {
95 contents_->SetVisible(selected);
96 SetTitleColor(selected ? kTabTitleColor_Active : kTabTitleColor_Inactive);
97 }
98
99 bool Tab::OnMousePressed(const ui::MouseEvent& event) {
100 SetTitleColor(kTabTitleColor_Pressed);
101 return true;
102 }
103
104 void Tab::OnMouseReleased(const ui::MouseEvent& event) {
105 SetTitleColor(selected() ? kTabTitleColor_Active : kTabTitleColor_Hovered);
106 if (GetLocalBounds().Contains(event.location()))
107 tabbed_pane_->SelectTab(this);
108 }
109
110 void Tab::OnMouseCaptureLost() {
111 SetTitleColor(kTabTitleColor_Inactive);
112 }
113
114 void Tab::OnMouseEntered(const ui::MouseEvent& event) {
115 SetTitleColor(selected() ? kTabTitleColor_Active : kTabTitleColor_Hovered);
116 }
117
118 void Tab::OnMouseExited(const ui::MouseEvent& event) {
119 SetTitleColor(selected() ? kTabTitleColor_Active : kTabTitleColor_Inactive);
120 }
121
122 void Tab::OnGestureEvent(ui::GestureEvent* event) {
123 switch (event->type()) {
124 case ui::ET_GESTURE_TAP_DOWN:
125 SetTitleColor(kTabTitleColor_Pressed);
126 break;
127 case ui::ET_GESTURE_TAP:
128 // SelectTab also sets the right tab color.
129 tabbed_pane_->SelectTab(this);
130 break;
131 case ui::ET_GESTURE_TAP_CANCEL:
132 SetTitleColor(selected() ?
133 kTabTitleColor_Active : kTabTitleColor_Inactive);
134 break;
135 default:
136 break;
137 }
138 event->SetHandled();
139 }
140
141 gfx::Size Tab::GetPreferredSize() {
142 gfx::Size size(title_->GetPreferredSize());
143 size.Enlarge(30, 10);
144 const int kTabMinWidth = 54;
145 if (size.width() < kTabMinWidth)
146 size.set_width(kTabMinWidth);
147 return size;
148 }
149
150 void Tab::Layout() {
151 gfx::Rect bounds = GetLocalBounds();
152 bounds.ClampToCenteredSize(title_->GetPreferredSize());
153 title_->SetBoundsRect(bounds);
154 }
155
156 void Tab::OnPaint(gfx::Canvas* canvas) {
157 if (selected()) {
158 canvas->DrawColor(kTabBackgroundColor);
159 PaintTabBorder(canvas);
160 }
161 View::OnPaint(canvas);
162 }
163
164 void Tab::SetTitleColor(SkColor color) {
165 title_->SetEnabledColor(color);
166 SchedulePaint();
167 }
168
169 void Tab::PaintTabBorder(gfx::Canvas* canvas) {
170 SkPath path;
171 // Clip the bottom of the border by extending its rect height beyond the tab.
172 const int tab_height = height() + kTabBorderThickness;
173 SkRect bounds = { 0, 0, SkIntToScalar(width()), SkIntToScalar(tab_height) };
174 SkScalar radii[8] = { kTabBorderRadius, kTabBorderRadius,
175 kTabBorderRadius, kTabBorderRadius,
176 0, 0,
177 0, 0 };
178 path.addRoundRect(bounds, radii, SkPath::kCW_Direction);
179
180 SkPaint paint;
181 paint.setAntiAlias(true);
182 paint.setStyle(SkPaint::kStroke_Style);
183 paint.setColor(kTabBorderColor);
184 paint.setStrokeWidth(kTabBorderThickness * 2);
185 canvas->DrawPath(path, paint);
186 }
187
188 TabStrip::TabStrip() {
189 const int kCount = 4;
190 // This gradient is designed to mach WebUI tabbed panes.
191 SkColor colors[kCount] = {
192 SkColorSetRGB(0xff, 0xff, 0xff),
193 SkColorSetRGB(0xff, 0xff, 0xff),
194 SkColorSetRGB(0xfa, 0xfa, 0xfa),
195 SkColorSetRGB(0xf2, 0xf2, 0xf2)
196 };
197 SkScalar pos[kCount] = { 0.0f, 0.6f, 0.8f, 1.0f };
198 set_background(Background::CreateVerticalMultiColorGradientBackground(
199 colors, pos, kCount));
200 }
201
202 TabStrip::~TabStrip() {}
203
204 gfx::Size TabStrip::GetPreferredSize() {
205 gfx::Size size;
206 for (int i = 0; i < child_count(); ++i) {
207 const gfx::Size child_size = child_at(i)->GetPreferredSize();
208 size.SetSize(size.width() + child_size.width(),
209 std::max(size.height(), child_size.height()));
210 }
211 return size;
212 }
213
214 void TabStrip::Layout() {
215 const int kTabOffset = 18;
216 int x = kTabOffset; // Layout tabs with an offset to the tabstrip border.
217 for (int i = 0; i < child_count(); ++i) {
218 gfx::Size ps = child_at(i)->GetPreferredSize();
219 child_at(i)->SetBounds(x, 0, ps.width(), ps.height());
220 x = child_at(i)->bounds().right();
221 }
222 }
223
224 void TabStrip::OnPaint(gfx::Canvas* canvas) {
225 OnPaintBackground(canvas);
226
227 // Draw the TabStrip border.
228 SkPaint paint;
229 paint.setColor(kTabBorderColor);
230 paint.setStrokeWidth(kTabBorderThickness);
231 SkScalar line_y = SkIntToScalar(height()) - kTabBorderThickness;
232 SkScalar line_width = SkIntToScalar(width());
233 canvas->sk_canvas()->drawLine(0, line_y, line_width, line_y, paint);
234 }
39 235
40 TabbedPane::TabbedPane() 236 TabbedPane::TabbedPane()
41 : native_tabbed_pane_(NULL), 237 : listener_(NULL),
42 #if defined(OS_WIN) && !defined(USE_AURA) 238 tab_strip_(new TabStrip()),
43 use_native_win_control_(false), 239 contents_(new View()),
44 #endif 240 selected_tab_index_(-1) {
45 listener_(NULL) {
46 set_focusable(true); 241 set_focusable(true);
47 } 242 AddChildView(tab_strip_);
48 243 AddChildView(contents_);
49 TabbedPane::~TabbedPane() { 244 }
50 } 245
246 TabbedPane::~TabbedPane() {}
51 247
52 int TabbedPane::GetTabCount() { 248 int TabbedPane::GetTabCount() {
53 return native_tabbed_pane_->GetTabCount(); 249 DCHECK_EQ(tab_strip_->child_count(), contents_->child_count());
54 } 250 return contents_->child_count();
55
56 int TabbedPane::GetSelectedTabIndex() {
57 return native_tabbed_pane_->GetSelectedTabIndex();
58 } 251 }
59 252
60 View* TabbedPane::GetSelectedTab() { 253 View* TabbedPane::GetSelectedTab() {
61 return native_tabbed_pane_->GetSelectedTab(); 254 return selected_tab_index() < 0 ?
255 NULL : GetTabAt(selected_tab_index())->contents();
62 } 256 }
63 257
64 void TabbedPane::AddTab(const string16& title, View* contents) { 258 void TabbedPane::AddTab(const string16& title, View* contents) {
65 native_tabbed_pane_->AddTab(title, contents); 259 AddTabAtIndex(tab_strip_->child_count(), title, contents);
66 PreferredSizeChanged();
67 } 260 }
68 261
69 void TabbedPane::AddTabAtIndex(int index, 262 void TabbedPane::AddTabAtIndex(int index,
70 const string16& title, 263 const string16& title,
71 View* contents, 264 View* contents) {
72 bool select_if_first_tab) { 265 DCHECK(index >= 0 && index <= GetTabCount());
73 native_tabbed_pane_->AddTabAtIndex(index, title, contents, 266 contents->SetVisible(false);
74 select_if_first_tab); 267
268 tab_strip_->AddChildViewAt(new Tab(this, title, contents), index);
269 contents_->AddChildViewAt(contents, index);
270 if (selected_tab_index() < 0)
271 SelectTabAt(index);
272
75 PreferredSizeChanged(); 273 PreferredSizeChanged();
76 } 274 }
77 275
78 View* TabbedPane::RemoveTabAtIndex(int index) {
79 View* tab = native_tabbed_pane_->RemoveTabAtIndex(index);
80 PreferredSizeChanged();
81 return tab;
82 }
83
84 void TabbedPane::SelectTabAt(int index) { 276 void TabbedPane::SelectTabAt(int index) {
85 native_tabbed_pane_->SelectTabAt(index); 277 DCHECK(index >= 0 && index < GetTabCount());
86 } 278 if (index == selected_tab_index())
87 279 return;
88 void TabbedPane::SetAccessibleName(const string16& name) { 280
89 accessible_name_ = name; 281 if (selected_tab_index() >= 0)
282 GetTabAt(selected_tab_index())->SetSelected(false);
283
284 selected_tab_index_ = index;
285 Tab* tab = GetTabAt(index);
286 tab->SetSelected(true);
287 tab_strip_->SchedulePaint();
288
289 FocusManager* focus_manager = tab->contents()->GetFocusManager();
290 if (focus_manager) {
291 const View* focused_view = focus_manager->GetFocusedView();
292 if (focused_view && contents_->Contains(focused_view) &&
293 !tab->contents()->Contains(focused_view))
294 focus_manager->SetFocusedView(tab->contents());
295 }
296
297 if (listener())
298 listener()->TabSelectedAt(index);
299 }
300
301 void TabbedPane::SelectTab(Tab* tab) {
302 const int index = tab_strip_->GetIndexOf(tab);
303 if (index >= 0)
304 SelectTabAt(index);
90 } 305 }
91 306
92 gfx::Size TabbedPane::GetPreferredSize() { 307 gfx::Size TabbedPane::GetPreferredSize() {
93 return native_tabbed_pane_ ? 308 gfx::Size size;
94 native_tabbed_pane_->GetPreferredSize() : gfx::Size(); 309 for (int i = 0; i < contents_->child_count(); ++i)
95 } 310 size.ClampToMin(contents_->child_at(i)->GetPreferredSize());
96 311 size.Enlarge(0, tab_strip_->GetPreferredSize().height());
97 void TabbedPane::LoadAccelerators() { 312 return size;
98 // Ctrl+Shift+Tab 313 }
99 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, 314
100 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN)); 315 Tab* TabbedPane::GetTabAt(int index) {
101 // Ctrl+Tab 316 return static_cast<Tab*>(tab_strip_->child_at(index));
102 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, ui::EF_CONTROL_DOWN));
103 } 317 }
104 318
105 void TabbedPane::Layout() { 319 void TabbedPane::Layout() {
106 if (native_tabbed_pane_) 320 const gfx::Size size = tab_strip_->GetPreferredSize();
107 native_tabbed_pane_->GetView()->SetBounds(0, 0, width(), height()); 321 tab_strip_->SetBounds(0, 0, width(), size.height());
322 contents_->SetBounds(0, tab_strip_->bounds().bottom(), width(),
323 std::max(0, height() - size.height()));
324 for (int i = 0; i < contents_->child_count(); ++i)
325 contents_->child_at(i)->SetSize(contents_->size());
108 } 326 }
109 327
110 void TabbedPane::ViewHierarchyChanged(bool is_add, View* parent, View* child) { 328 void TabbedPane::ViewHierarchyChanged(bool is_add, View* parent, View* child) {
111 if (is_add && !native_tabbed_pane_) { 329 if (is_add) {
112 // The native wrapper's lifetime will be managed by the view hierarchy after 330 // Support navigating tabs by Ctrl+Tab and Ctrl+Shift+Tab.
113 // we call AddChildView. 331 AddAccelerator(ui::Accelerator(ui::VKEY_TAB,
114 native_tabbed_pane_ = CreateNativeWrapper(this); 332 ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN));
115 AddChildView(native_tabbed_pane_->GetView()); 333 AddAccelerator(ui::Accelerator(ui::VKEY_TAB, ui::EF_CONTROL_DOWN));
116 LoadAccelerators();
117 } 334 }
118 } 335 }
119 336
120 bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) { 337 bool TabbedPane::AcceleratorPressed(const ui::Accelerator& accelerator) {
121 // We only accept Ctrl+Tab keyboard events. 338 // Handle Ctrl+Tab and Ctrl+Shift+Tab navigation of pages.
122 DCHECK(accelerator.key_code() == ui::VKEY_TAB && accelerator.IsCtrlDown()); 339 DCHECK(accelerator.key_code() == ui::VKEY_TAB && accelerator.IsCtrlDown());
123 340 const int tab_count = GetTabCount();
124 int tab_count = GetTabCount();
125 if (tab_count <= 1) 341 if (tab_count <= 1)
126 return false; 342 return false;
127 int selected_tab_index = GetSelectedTabIndex(); 343 const int increment = accelerator.IsShiftDown() ? -1 : 1;
128 int next_tab_index = accelerator.IsShiftDown() ? 344 int next_tab_index = (selected_tab_index() + increment) % tab_count;
129 (selected_tab_index - 1) % tab_count :
130 (selected_tab_index + 1) % tab_count;
131 // Wrap around. 345 // Wrap around.
132 if (next_tab_index < 0) 346 if (next_tab_index < 0)
133 next_tab_index += tab_count; 347 next_tab_index += tab_count;
134 SelectTabAt(next_tab_index); 348 SelectTabAt(next_tab_index);
135 return true; 349 return true;
136 } 350 }
137 351
138 std::string TabbedPane::GetClassName() const { 352 std::string TabbedPane::GetClassName() const {
139 return kViewClassName; 353 return kViewClassName;
140 } 354 }
141 355
142 void TabbedPane::OnFocus() { 356 void TabbedPane::OnFocus() {
143 // Forward the focus to the wrapper. 357 View::OnFocus();
144 if (native_tabbed_pane_) {
145 native_tabbed_pane_->SetFocus();
146 358
147 View* selected_tab = GetSelectedTab(); 359 View* selected_tab = GetSelectedTab();
148 if (selected_tab) { 360 if (selected_tab) {
149 selected_tab->GetWidget()->NotifyAccessibilityEvent( 361 selected_tab->GetWidget()->NotifyAccessibilityEvent(
150 selected_tab, ui::AccessibilityTypes::EVENT_FOCUS, true); 362 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 } 363 }
156 } 364 }
157 365
158 void TabbedPane::OnPaintFocusBorder(gfx::Canvas* canvas) {
159 if (NativeViewHost::kRenderNativeControlFocus)
160 View::OnPaintFocusBorder(canvas);
161 }
162
163 void TabbedPane::GetAccessibleState(ui::AccessibleViewState* state) { 366 void TabbedPane::GetAccessibleState(ui::AccessibleViewState* state) {
164 state->role = ui::AccessibilityTypes::ROLE_PAGETABLIST; 367 state->role = ui::AccessibilityTypes::ROLE_PAGETABLIST;
165 state->name = accessible_name_;
166 } 368 }
167 369
168 } // namespace views 370 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/tabbed_pane/tabbed_pane.h ('k') | ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698