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

Side by Side Diff: ui/views/controls/tabbed_pane/native_tabbed_pane_views.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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "ui/views/controls/tabbed_pane/native_tabbed_pane_views.h"
6
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "ui/base/resource/resource_bundle.h"
10 #include "ui/gfx/canvas.h"
11 #include "ui/gfx/font.h"
12 #include "ui/views/controls/tabbed_pane/tabbed_pane.h"
13 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
14 #include "ui/views/layout/fill_layout.h"
15 #include "ui/views/widget/widget.h"
16
17 namespace views {
18
19 const SkColor kTabTitleColor_Inactive = SkColorSetRGB(0x66, 0x66, 0x66);
20 const SkColor kTabTitleColor_Active = SkColorSetRGB(0x20, 0x20, 0x20);
21 const SkColor kTabTitleColor_Pressed = SkColorSetRGB(0x33, 0x33, 0x33);
22 const SkColor kTabTitleColor_Hovered = SkColorSetRGB(0x22, 0x22, 0x22);
23 // TODO(markusheintz): The tab background color should be provided by the
24 // NativeTheme.
25 const SkColor kTabBackgroundColor_Active = SK_ColorWHITE;
26 const SkColor kTabBorderColor = SkColorSetRGB(0xCC, 0xCC, 0xCC);
27 const SkScalar kTabBorderThickness = 1.0f;
28 const SkScalar kTabBorderRadius = 2.0f;
29
30 class TabStrip;
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 {
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(NativeTabbedPaneViews* 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) {
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;
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 NativeTabbedPaneViews* 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);
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
320 ////////////////////////////////////////////////////////////////////////////////
321 // NativeTabbedPaneViews, public:
322
323 NativeTabbedPaneViews::NativeTabbedPaneViews(TabbedPane* tabbed_pane)
324 : tabbed_pane_(tabbed_pane),
325 tab_layout_manager_(new TabLayout),
326 ALLOW_THIS_IN_INITIALIZER_LIST(tab_strip_(new TabStrip(this))),
327 content_view_(new views::View) {
328 AddChildView(tab_strip_);
329 AddChildView(content_view_);
330 InitControl();
331 }
332
333 NativeTabbedPaneViews::~NativeTabbedPaneViews() {
334 }
335
336 void NativeTabbedPaneViews::TabSelectionChanged(View* selected) {
337 tab_layout_manager_->SwitchToPage(content_view_, Tab::GetContents(selected));
338 if (tabbed_pane_->listener())
339 tabbed_pane_->listener()->TabSelectedAt(tab_strip_->GetIndexOf(selected));
340 }
341
342 ////////////////////////////////////////////////////////////////////////////////
343 // NativeTabbedPaneViews, NativeTabbedPaneWrapper implementation:
344
345 void NativeTabbedPaneViews::AddTab(const string16& title, View* contents) {
346 AddTabAtIndex(tab_strip_->child_count(), title, contents, true);
347 }
348
349 void NativeTabbedPaneViews::AddTabAtIndex(int index,
350 const string16& title,
351 View* contents,
352 bool select_if_first_tab) {
353 DCHECK(index <= static_cast<int>(tab_strip_->child_count()));
354 contents->set_owned_by_client();
355 contents->SetVisible(false);
356
357 tab_strip_->AddChildViewAt(new Tab(tab_strip_, title, contents), index);
358
359 // Add native tab only if the native control is already created.
360 content_view_->AddChildViewAt(contents, index);
361
362 // Switch to the newly added tab if requested;
363 if (tab_strip_->child_count() == 1 && select_if_first_tab)
364 tab_layout_manager_->SwitchToPage(content_view_, contents);
365 if (!tab_strip_->selected_tab())
366 tab_strip_->SelectTab(tab_strip_->child_at(0));
367 }
368
369 View* NativeTabbedPaneViews::RemoveTabAtIndex(int index) {
370 DCHECK(index >= 0 && index < tab_strip_->child_count());
371
372 if (index < (tab_strip_->child_count() - 1)) {
373 // Select the next tab.
374 SelectTabAt(index + 1);
375 } else {
376 // We are the last tab, select the previous one.
377 if (index > 0) {
378 SelectTabAt(index - 1);
379 } else {
380 // That was the last tab. Remove the contents.
381 content_view_->RemoveAllChildViews(false);
382 }
383 }
384 return tab_strip_->RemoveTabAt(index);
385 }
386
387 void NativeTabbedPaneViews::SelectTabAt(int index) {
388 DCHECK((index >= 0) && (index < tab_strip_->child_count()));
389 tab_strip_->SelectTab(tab_strip_->child_at(index));
390 }
391
392 int NativeTabbedPaneViews::GetTabCount() {
393 return tab_strip_->child_count();
394 }
395
396 int NativeTabbedPaneViews::GetSelectedTabIndex() {
397 return tab_strip_->GetSelectedIndex();
398 }
399
400 View* NativeTabbedPaneViews::GetSelectedTab() {
401 return content_view_->child_at(GetSelectedTabIndex());
402 }
403
404 View* NativeTabbedPaneViews::GetView() {
405 return this;
406 }
407
408 void NativeTabbedPaneViews::SetFocus() {
409 // Focus the associated HWND.
410 OnFocus();
411 }
412
413 gfx::Size NativeTabbedPaneViews::GetPreferredSize() {
414 gfx::Size content_size = content_view_->GetPreferredSize();
415 return gfx::Size(
416 content_size.width(),
417 tab_strip_->GetPreferredSize().height() + content_size.height());
418 }
419
420 gfx::NativeView NativeTabbedPaneViews::GetTestingHandle() const {
421 return NULL;
422 }
423
424 ////////////////////////////////////////////////////////////////////////////////
425 // NativeTabbedPaneViews, View overrides:
426
427 void NativeTabbedPaneViews::Layout() {
428 gfx::Size ps = tab_strip_->GetPreferredSize();
429 tab_strip_->SetBounds(0, 0, width(), ps.height());
430 content_view_->SetBounds(0, tab_strip_->bounds().bottom(), width(),
431 std::max(0, height() - ps.height()));
432 }
433
434 ////////////////////////////////////////////////////////////////////////////////
435 // NativeTabbedPaneViews, private:
436
437 void NativeTabbedPaneViews::InitControl() {
438 content_view_->SetLayoutManager(tab_layout_manager_);
439
440 // Add tabs that are already added if any.
441 if (tab_strip_->has_children())
442 InitializeTabs();
443 }
444
445 void NativeTabbedPaneViews::InitializeTabs() {
446 for (int i = 0; i < tab_strip_->child_count(); ++i)
447 content_view_->AddChildView(Tab::GetContents(tab_strip_->child_at(i)));
448 }
449
450 } // namespace views
OLDNEW
« no previous file with comments | « ui/views/controls/tabbed_pane/native_tabbed_pane_views.h ('k') | ui/views/controls/tabbed_pane/native_tabbed_pane_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698