From 35f83a463a8cb26f2862fc1d051fac6e18eb582a Mon Sep 17 00:00:00 2001 From: "jcampan@chromium.org" Date: Tue, 21 Jul 2009 17:57:46 +0000 Subject: Refactoring of tabbed-pane component so it can be ported to Linux toolkit_view. BUG=None TEST=Make sure the Options dialog still works as expected (tab selection, focus traversal...) Review URL: http://codereview.chromium.org/155668 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21189 0039d316-1c4b-4281-b951-d872f2087c98 --- views/controls/tabbed_pane.cc | 264 ------------------ views/controls/tabbed_pane.h | 94 ------- .../controls/tabbed_pane/native_tabbed_pane_win.cc | 300 +++++++++++++++++++++ .../controls/tabbed_pane/native_tabbed_pane_win.h | 69 +++++ .../tabbed_pane/native_tabbed_pane_wrapper.h | 68 +++++ views/controls/tabbed_pane/tabbed_pane.cc | 89 ++++++ views/controls/tabbed_pane/tabbed_pane.h | 92 +++++++ 7 files changed, 618 insertions(+), 358 deletions(-) delete mode 100644 views/controls/tabbed_pane.cc delete mode 100644 views/controls/tabbed_pane.h create mode 100644 views/controls/tabbed_pane/native_tabbed_pane_win.cc create mode 100644 views/controls/tabbed_pane/native_tabbed_pane_win.h create mode 100644 views/controls/tabbed_pane/native_tabbed_pane_wrapper.h create mode 100644 views/controls/tabbed_pane/tabbed_pane.cc create mode 100644 views/controls/tabbed_pane/tabbed_pane.h (limited to 'views/controls') diff --git a/views/controls/tabbed_pane.cc b/views/controls/tabbed_pane.cc deleted file mode 100644 index b7c41bc..0000000 --- a/views/controls/tabbed_pane.cc +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "views/controls/tabbed_pane.h" - -#include - -#include "app/gfx/canvas.h" -#include "app/gfx/font.h" -#include "app/l10n_util_win.h" -#include "app/resource_bundle.h" -#include "base/gfx/native_theme.h" -#include "base/logging.h" -#include "base/stl_util-inl.h" -#include "skia/ext/skia_utils_win.h" -#include "third_party/skia/include/core/SkColor.h" -#include "views/background.h" -#include "views/fill_layout.h" -#include "views/widget/root_view.h" -#include "views/widget/widget_win.h" - -namespace views { - -// A background object that paints the tab panel background which may be -// rendered by the system visual styles system. -class TabBackground : public Background { - public: - explicit TabBackground() { - // TMT_FILLCOLORHINT returns a color value that supposedly - // approximates the texture drawn by PaintTabPanelBackground. - SkColor tab_page_color = - gfx::NativeTheme::instance()->GetThemeColorWithDefault( - gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT, - COLOR_3DFACE); - SetNativeControlColor(tab_page_color); - } - virtual ~TabBackground() {} - - virtual void Paint(gfx::Canvas* canvas, View* view) const { - HDC dc = canvas->beginPlatformPaint(); - RECT r = {0, 0, view->width(), view->height()}; - gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r); - canvas->endPlatformPaint(); - } - - private: - DISALLOW_EVIL_CONSTRUCTORS(TabBackground); -}; - -TabbedPane::TabbedPane() : content_window_(NULL), listener_(NULL) { -} - -TabbedPane::~TabbedPane() { - // We own the tab views, let's delete them. - STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end()); -} - -void TabbedPane::SetListener(Listener* listener) { - listener_ = listener; -} - -void TabbedPane::AddTab(const std::wstring& title, View* contents) { - AddTabAtIndex(static_cast(tab_views_.size()), title, contents, true); -} - -void TabbedPane::AddTabAtIndex(int index, - const std::wstring& title, - View* contents, - bool select_if_first_tab) { - DCHECK(index <= static_cast(tab_views_.size())); - contents->SetParentOwned(false); - tab_views_.insert(tab_views_.begin() + index, contents); - - TCITEM tcitem; - tcitem.mask = TCIF_TEXT; - - // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is - // rendered properly on the tabs. - if (UILayoutIsRightToLeft()) { - tcitem.mask |= TCIF_RTLREADING; - } - - tcitem.pszText = const_cast(title.c_str()); - int result = TabCtrl_InsertItem(tab_control_, index, &tcitem); - DCHECK(result != -1); - - if (!contents->background()) { - contents->set_background(new TabBackground); - } - - if (tab_views_.size() == 1 && select_if_first_tab) { - // If this is the only tab displayed, make sure the contents is set. - content_window_->GetRootView()->AddChildView(contents); - } - - // The newly added tab may have made the contents window smaller. - ResizeContents(tab_control_); -} - -View* TabbedPane::RemoveTabAtIndex(int index) { - int tab_count = static_cast(tab_views_.size()); - DCHECK(index >= 0 && index < tab_count); - - if (index < (tab_count - 1)) { - // Select the next tab. - SelectTabAt(index + 1); - } else { - // We are the last tab, select the previous one. - if (index > 0) { - SelectTabAt(index - 1); - } else { - // That was the last tab. Remove the contents. - content_window_->GetRootView()->RemoveAllChildViews(false); - } - } - TabCtrl_DeleteItem(tab_control_, index); - - // The removed tab may have made the contents window bigger. - ResizeContents(tab_control_); - - std::vector::iterator iter = tab_views_.begin() + index; - View* removed_tab = *iter; - tab_views_.erase(iter); - - return removed_tab; -} - -void TabbedPane::SelectTabAt(int index) { - DCHECK((index >= 0) && (index < static_cast(tab_views_.size()))); - TabCtrl_SetCurSel(tab_control_, index); - DoSelectTabAt(index); -} - -void TabbedPane::SelectTabForContents(const View* contents) { - SelectTabAt(GetIndexForContents(contents)); -} - -int TabbedPane::GetTabCount() { - return TabCtrl_GetItemCount(tab_control_); -} - -HWND TabbedPane::CreateNativeControl(HWND parent_container) { - // Create the tab control. - // - // Note that we don't follow the common convention for NativeControl - // subclasses and we don't pass the value returned from - // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is - // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when - // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If - // we do that, then the HWND we create for |content_window_| below will - // inherit the WS_EX_LAYOUTRTL property and this will result in the contents - // being flipped, which is not what we want (because we handle mirroring in - // views without the use of Windows' support for mirroring). Therefore, - // we initially create our HWND without the aforementioned property and we - // explicitly set this property our child is created. This way, on RTL - // locales, our tabs will be nicely rendered from right to left (by virtue of - // Windows doing the right thing with the TabbedPane HWND) and each tab - // contents will use an RTL layout correctly (by virtue of the mirroring - // infrastructure in views doing the right thing with each View we put - // in the tab). - tab_control_ = ::CreateWindowEx(0, - WC_TABCONTROL, - L"", - WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, - 0, 0, width(), height(), - parent_container, NULL, NULL, NULL); - - HFONT font = ResourceBundle::GetSharedInstance(). - GetFont(ResourceBundle::BaseFont).hfont(); - SendMessage(tab_control_, WM_SETFONT, reinterpret_cast(font), FALSE); - - // Create the view container which is a child of the TabControl. - content_window_ = new WidgetWin(); - content_window_->Init(tab_control_, gfx::Rect()); - - // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above - // for a thorough explanation regarding why we waited until |content_window_| - // if created before we set this property for the tabbed pane's HWND). - if (UILayoutIsRightToLeft()) { - l10n_util::HWNDSetRTLLayout(tab_control_); - } - - RootView* root_view = content_window_->GetRootView(); - root_view->SetLayoutManager(new FillLayout()); - DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT); - SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color), - GetBValue(sys_color)); - root_view->set_background(Background::CreateSolidBackground(color)); - - content_window_->SetFocusTraversableParentView(this); - ResizeContents(tab_control_); - return tab_control_; -} - -LRESULT TabbedPane::OnNotify(int w_param, LPNMHDR l_param) { - if (static_cast(l_param)->code == TCN_SELCHANGE) { - int selected_tab = TabCtrl_GetCurSel(tab_control_); - DCHECK(selected_tab != -1); - DoSelectTabAt(selected_tab); - return TRUE; - } - return FALSE; -} - -void TabbedPane::DoSelectTabAt(int index) { - RootView* content_root = content_window_->GetRootView(); - - // Clear the focus if the focused view was on the tab. - FocusManager* focus_manager = GetFocusManager(); - DCHECK(focus_manager); - View* focused_view = focus_manager->GetFocusedView(); - if (focused_view && content_root->IsParentOf(focused_view)) - focus_manager->ClearFocus(); - - content_root->RemoveAllChildViews(false); - content_root->AddChildView(tab_views_[index]); - content_root->Layout(); - if (listener_) - listener_->TabSelectedAt(index); -} - -int TabbedPane::GetIndexForContents(const View* contents) const { - std::vector::const_iterator i = - std::find(tab_views_.begin(), tab_views_.end(), contents); - DCHECK(i != tab_views_.end()); - return static_cast(i - tab_views_.begin()); -} - -void TabbedPane::Layout() { - NativeControl::Layout(); - ResizeContents(GetNativeControlHWND()); -} - -RootView* TabbedPane::GetContentsRootView() { - return content_window_->GetRootView(); -} - -FocusTraversable* TabbedPane::GetFocusTraversable() { - return content_window_; -} - -void TabbedPane::ViewHierarchyChanged(bool is_add, View *parent, View *child) { - NativeControl::ViewHierarchyChanged(is_add, parent, child); - - if (is_add && (child == this) && content_window_) { - // We have been added to a view hierarchy, update the FocusTraversable - // parent. - content_window_->SetFocusTraversableParent(GetRootView()); - } -} - -void TabbedPane::ResizeContents(HWND tab_control) { - DCHECK(tab_control); - CRect content_bounds; - if (!GetClientRect(tab_control, &content_bounds)) - return; - TabCtrl_AdjustRect(tab_control, FALSE, &content_bounds); - content_window_->MoveWindow(content_bounds.left, content_bounds.top, - content_bounds.Width(), content_bounds.Height(), - TRUE); -} - -} // namespace views diff --git a/views/controls/tabbed_pane.h b/views/controls/tabbed_pane.h deleted file mode 100644 index 528a2d5..0000000 --- a/views/controls/tabbed_pane.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef VIEWS_CONTROLS_TABBED_PANE_H_ -#define VIEWS_CONTROLS_TABBED_PANE_H_ - -#include "views/controls/native_control.h" - -namespace views { - -// The TabbedPane class is a view that shows tabs. When the user clicks on a -// tab, the associated view is displayed. -// TODO (jcampan): implement GetPreferredSize(). -class WidgetWin; - -class TabbedPane : public NativeControl { - public: - TabbedPane(); - virtual ~TabbedPane(); - - // An interface an object can implement to be notified about events within - // the TabbedPane. - class Listener { - public: - // Called when the tab at the specified |index| is selected by the user. - virtual void TabSelectedAt(int index) = 0; - }; - void SetListener(Listener* listener); - - // Adds a new tab at the end of this TabbedPane with the specified |title|. - // |contents| is the view displayed when the tab is selected and is owned by - // the TabbedPane. - void AddTab(const std::wstring& title, View* contents); - - // Adds a new tab at the specified |index| with the specified |title|. - // |contents| is the view displayed when the tab is selected and is owned by - // the TabbedPane. If |select_if_first_tab| is true and the tabbed pane is - // currently empty, the new tab is selected. If you pass in false for - // |select_if_first_tab| you need to explicitly invoke SelectTabAt, otherwise - // the tabbed pane will not have a valid selection. - void AddTabAtIndex(int index, - const std::wstring& title, - View* contents, - bool select_if_first_tab); - - // Removes the tab at the specified |index| and returns the associated content - // view. The caller becomes the owner of the returned view. - View* RemoveTabAtIndex(int index); - - // Selects the tab at the specified |index|, which must be valid. - void SelectTabAt(int index); - - // Selects the tab containing the specified |contents|, which must be valid. - void SelectTabForContents(const View* contents); - - // Returns the number of tabs. - int GetTabCount(); - - virtual HWND CreateNativeControl(HWND parent_container); - virtual LRESULT OnNotify(int w_param, LPNMHDR l_param); - - virtual void Layout(); - - virtual RootView* GetContentsRootView(); - virtual FocusTraversable* GetFocusTraversable(); - virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); - - private: - // Changes the contents view to the view associated with the tab at |index|. - void DoSelectTabAt(int index); - - // Returns the index of the tab containing the specified |contents|. - int GetIndexForContents(const View* contents) const; - - void ResizeContents(HWND tab_control); - - HWND tab_control_; - - // The views associated with the different tabs. - std::vector tab_views_; - - // The window displayed in the tab. - WidgetWin* content_window_; - - // The listener we notify about tab selection changes. - Listener* listener_; - - DISALLOW_EVIL_CONSTRUCTORS(TabbedPane); -}; - -} // namespace views - -#endif // #define VIEWS_CONTROLS_TABBED_PANE_H_ diff --git a/views/controls/tabbed_pane/native_tabbed_pane_win.cc b/views/controls/tabbed_pane/native_tabbed_pane_win.cc new file mode 100644 index 0000000..8ae054c --- /dev/null +++ b/views/controls/tabbed_pane/native_tabbed_pane_win.cc @@ -0,0 +1,300 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "views/controls/tabbed_pane/native_tabbed_pane_win.h" + +#include + +#include "app/gfx/canvas.h" +#include "app/gfx/font.h" +#include "app/l10n_util_win.h" +#include "app/resource_bundle.h" +#include "base/gfx/native_theme.h" +#include "base/logging.h" +#include "base/stl_util-inl.h" +#include "views/controls/tabbed_pane/tabbed_pane.h" +#include "views/fill_layout.h" +#include "views/widget/root_view.h" +#include "views/widget/widget_win.h" + +namespace views { + +// A background object that paints the tab panel background which may be +// rendered by the system visual styles system. +class TabBackground : public Background { + public: + explicit TabBackground() { + // TMT_FILLCOLORHINT returns a color value that supposedly + // approximates the texture drawn by PaintTabPanelBackground. + SkColor tab_page_color = + gfx::NativeTheme::instance()->GetThemeColorWithDefault( + gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT, + COLOR_3DFACE); + SetNativeControlColor(tab_page_color); + } + virtual ~TabBackground() {} + + virtual void Paint(gfx::Canvas* canvas, View* view) const { + HDC dc = canvas->beginPlatformPaint(); + RECT r = {0, 0, view->width(), view->height()}; + gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r); + canvas->endPlatformPaint(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(TabBackground); +}; + +//////////////////////////////////////////////////////////////////////////////// +// NativeTabbedPaneWin, public: + +NativeTabbedPaneWin::NativeTabbedPaneWin(TabbedPane* tabbed_pane) + : NativeControlWin(), + tabbed_pane_(tabbed_pane), + content_window_(NULL) { + // Associates the actual HWND with the tabbed-pane so the tabbed-pane is + // the one considered as having the focus (not the wrapper) when the HWND is + // focused directly (with a click for example). + set_focus_view(tabbed_pane); +} + +NativeTabbedPaneWin::~NativeTabbedPaneWin() { + // We own the tab views, let's delete them. + STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end()); +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeTabbedPaneWin, NativeTabbedPaneWrapper implementation: + +void NativeTabbedPaneWin::AddTab(const std::wstring& title, View* contents) { + AddTabAtIndex(static_cast(tab_views_.size()), title, contents, true); +} + +void NativeTabbedPaneWin::AddTabAtIndex(int index, const std::wstring& title, + View* contents, + bool select_if_first_tab) { + DCHECK(index <= static_cast(tab_views_.size())); + contents->SetParentOwned(false); + tab_views_.insert(tab_views_.begin() + index, contents); + + TCITEM tcitem; + tcitem.mask = TCIF_TEXT; + + // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is + // rendered properly on the tabs. + if (UILayoutIsRightToLeft()) { + tcitem.mask |= TCIF_RTLREADING; + } + + tcitem.pszText = const_cast(title.c_str()); + int result = TabCtrl_InsertItem(native_view(), index, &tcitem); + DCHECK(result != -1); + + if (!contents->background()) + contents->set_background(new TabBackground); + + if (tab_views_.size() == 1 && select_if_first_tab) { + // If this is the only tab displayed, make sure the contents is set. + content_window_->GetRootView()->AddChildView(contents); + } + + // The newly added tab may have made the contents window smaller. + ResizeContents(); +} + +View* NativeTabbedPaneWin::RemoveTabAtIndex(int index) { + int tab_count = static_cast(tab_views_.size()); + DCHECK(index >= 0 && index < tab_count); + + if (index < (tab_count - 1)) { + // Select the next tab. + SelectTabAt(index + 1); + } else { + // We are the last tab, select the previous one. + if (index > 0) { + SelectTabAt(index - 1); + } else { + // That was the last tab. Remove the contents. + content_window_->GetRootView()->RemoveAllChildViews(false); + } + } + TabCtrl_DeleteItem(native_view(), index); + + // The removed tab may have made the contents window bigger. + ResizeContents(); + + std::vector::iterator iter = tab_views_.begin() + index; + View* removed_tab = *iter; + tab_views_.erase(iter); + + return removed_tab; +} + +void NativeTabbedPaneWin::SelectTabAt(int index) { + DCHECK((index >= 0) && (index < static_cast(tab_views_.size()))); + TabCtrl_SetCurSel(native_view(), index); + DoSelectTabAt(index); +} + +int NativeTabbedPaneWin::GetTabCount() { + return TabCtrl_GetItemCount(native_view()); +} + +int NativeTabbedPaneWin::GetSelectedTabIndex() { + return TabCtrl_GetCurSel(native_view()); +} + +View* NativeTabbedPaneWin::GetSelectedTab() { + return content_window_->GetRootView()->GetChildViewAt(0); +} + +View* NativeTabbedPaneWin::GetView() { + return this; +} + +void NativeTabbedPaneWin::SetFocus() { + // Focus the associated HWND. + Focus(); +} + +gfx::NativeView NativeTabbedPaneWin::GetTestingHandle() const { + return native_view(); +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeTabbedPaneWin, NativeControlWin override: + +void NativeTabbedPaneWin::CreateNativeControl() { + // Create the tab control. + // + // Note that we don't follow the common convention for NativeControl + // subclasses and we don't pass the value returned from + // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is + // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when + // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If + // we do that, then the HWND we create for |content_window_| below will + // inherit the WS_EX_LAYOUTRTL property and this will result in the contents + // being flipped, which is not what we want (because we handle mirroring in + // views without the use of Windows' support for mirroring). Therefore, + // we initially create our HWND without the aforementioned property and we + // explicitly set this property our child is created. This way, on RTL + // locales, our tabs will be nicely rendered from right to left (by virtue of + // Windows doing the right thing with the TabbedPane HWND) and each tab + // contents will use an RTL layout correctly (by virtue of the mirroring + // infrastructure in views doing the right thing with each View we put + // in the tab). + HWND tab_control = ::CreateWindowEx(0, + WC_TABCONTROL, + L"", + WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, + 0, 0, width(), height(), + GetWidget()->GetNativeView(), NULL, NULL, + NULL); + + HFONT font = ResourceBundle::GetSharedInstance(). + GetFont(ResourceBundle::BaseFont).hfont(); + SendMessage(tab_control, WM_SETFONT, reinterpret_cast(font), FALSE); + + // Create the view container which is a child of the TabControl. + content_window_ = new WidgetWin(); + content_window_->Init(tab_control, gfx::Rect()); + + // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above + // for a thorough explanation regarding why we waited until |content_window_| + // if created before we set this property for the tabbed pane's HWND). + if (UILayoutIsRightToLeft()) + l10n_util::HWNDSetRTLLayout(tab_control); + + RootView* root_view = content_window_->GetRootView(); + root_view->SetLayoutManager(new FillLayout()); + DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT); + SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color), + GetBValue(sys_color)); + root_view->set_background(Background::CreateSolidBackground(color)); + + content_window_->SetFocusTraversableParentView(this); + ResizeContents(); + + NativeControlCreated(tab_control); +} + +bool NativeTabbedPaneWin::ProcessMessage(UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT* result) { + if (message == WM_NOTIFY && + reinterpret_cast(l_param)->code == TCN_SELCHANGE) { + int selected_tab = TabCtrl_GetCurSel(native_view()); + DCHECK(selected_tab != -1); + DoSelectTabAt(selected_tab); + return TRUE; + } + return NativeControlWin::ProcessMessage(message, w_param, l_param, result); +} + +//////////////////////////////////////////////////////////////////////////////// +// View override: + +void NativeTabbedPaneWin::Layout() { + NativeControlWin::Layout(); + ResizeContents(); +} + +FocusTraversable* NativeTabbedPaneWin::GetFocusTraversable() { + return content_window_; +} + +void NativeTabbedPaneWin::ViewHierarchyChanged(bool is_add, + View *parent, + View *child) { + NativeControlWin::ViewHierarchyChanged(is_add, parent, child); + + if (is_add && (child == this) && content_window_) { + // We have been added to a view hierarchy, update the FocusTraversable + // parent. + content_window_->SetFocusTraversableParent(GetRootView()); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeTabbedPaneWin, private: + +void NativeTabbedPaneWin::DoSelectTabAt(int index) { + RootView* content_root = content_window_->GetRootView(); + + // Clear the focus if the focused view was on the tab. + FocusManager* focus_manager = GetFocusManager(); + DCHECK(focus_manager); + View* focused_view = focus_manager->GetFocusedView(); + if (focused_view && content_root->IsParentOf(focused_view)) + focus_manager->ClearFocus(); + + content_root->RemoveAllChildViews(false); + content_root->AddChildView(tab_views_[index]); + content_root->Layout(); + + if (tabbed_pane_->listener()) + tabbed_pane_->listener()->TabSelectedAt(index); +} + +void NativeTabbedPaneWin::ResizeContents() { + CRect content_bounds; + if (!GetClientRect(native_view(), &content_bounds)) + return; + TabCtrl_AdjustRect(native_view(), FALSE, &content_bounds); + content_window_->MoveWindow(content_bounds.left, content_bounds.top, + content_bounds.Width(), content_bounds.Height(), + TRUE); +} + +//////////////////////////////////////////////////////////////////////////////// +// NativeTabbedPaneWrapper, public: + +// static +NativeTabbedPaneWrapper* NativeTabbedPaneWrapper::CreateNativeWrapper( + TabbedPane* tabbed_pane) { + return new NativeTabbedPaneWin(tabbed_pane); +} + +} // namespace views diff --git a/views/controls/tabbed_pane/native_tabbed_pane_win.h b/views/controls/tabbed_pane/native_tabbed_pane_win.h new file mode 100644 index 0000000..be55d15 --- /dev/null +++ b/views/controls/tabbed_pane/native_tabbed_pane_win.h @@ -0,0 +1,69 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef VIEWS_CONTROLS_TABBED_PANE_NATIVE_TABBED_PANE_WIN_H_ +#define VIEWS_CONTROLS_TABBED_PANE_NATIVE_TABBED_PANE_WIN_H_ + +#include "views/controls/native_control_win.h" +#include "views/controls/tabbed_pane/native_tabbed_pane_wrapper.h" + +namespace views { + +class WidgetWin; + +class NativeTabbedPaneWin : public NativeControlWin, + public NativeTabbedPaneWrapper { + public: + explicit NativeTabbedPaneWin(TabbedPane* tabbed_pane); + virtual ~NativeTabbedPaneWin(); + + // NativeTabbedPaneWrapper implementation: + virtual void AddTab(const std::wstring& title, View* contents); + virtual void AddTabAtIndex(int index, + const std::wstring& title, + View* contents, + bool select_if_first_tab); + virtual View* RemoveTabAtIndex(int index); + virtual void SelectTabAt(int index); + virtual int GetTabCount(); + virtual int GetSelectedTabIndex(); + virtual View* GetSelectedTab(); + virtual View* GetView(); + virtual void SetFocus(); + virtual gfx::NativeView GetTestingHandle() const; + + // NativeControlWin overrides. + virtual void CreateNativeControl(); + virtual bool ProcessMessage(UINT message, + WPARAM w_param, + LPARAM l_param, + LRESULT* result); + + // View overrides: + virtual void Layout(); + virtual FocusTraversable* GetFocusTraversable(); + virtual void ViewHierarchyChanged(bool is_add, View *parent, View *child); + + private: + // Changes the contents view to the view associated with the tab at |index|. + void DoSelectTabAt(int index); + + // Resizes the HWND control to macth the size of the containing view. + void ResizeContents(); + + // The tabbed-pane we are bound to. + TabbedPane* tabbed_pane_; + + // The views associated with the different tabs. + std::vector tab_views_; + + // The window displayed in the tab. + WidgetWin* content_window_; + + DISALLOW_COPY_AND_ASSIGN(NativeTabbedPaneWin); +}; + +} // namespace views + +#endif // VIEWS_CONTROLS_TABBED_PANE_NATIVE_TABBED_PANE_WIN_H_ diff --git a/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h b/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h new file mode 100644 index 0000000..a051898 --- /dev/null +++ b/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h @@ -0,0 +1,68 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef VIEWS_CONTROLS_TABBED_PANE_NATIVE_TABBED_PANE_WRAPPER_H_ +#define VIEWS_CONTROLS_TABBED_PANE_NATIVE_TABBED_PANE_WRAPPER_H_ + +namespace views { + +class TabbedPane; +class View; + +// An interface implemented by an object that provides a platform-native +// tabbed-pane. +class NativeTabbedPaneWrapper { + public: + // The TabbedPane calls this when it is destroyed to clean up the wrapper + // object. + virtual ~NativeTabbedPaneWrapper() { } + + // Adds a new tab at the end of this TabbedPane with the specified |title|. + // |contents| is the view displayed when the tab is selected and is owned by + // the TabbedPane. + virtual void AddTab(const std::wstring& title, View* contents) = 0; + + // Adds a new tab at the specified |index| with the specified |title|. + // |contents| is the view displayed when the tab is selected and is owned by + // the TabbedPane. If |select_if_first_tab| is true and the tabbed pane is + // currently empty, the new tab is selected. If you pass in false for + // |select_if_first_tab| you need to explicitly invoke SelectTabAt, otherwise + // the tabbed pane will not have a valid selection. + virtual void AddTabAtIndex(int index, + const std::wstring& title, + View* contents, + bool select_if_first_tab) = 0; + + // Removes the tab at the specified |index| and returns the associated content + // view. The caller becomes the owner of the returned view. + virtual View* RemoveTabAtIndex(int index) = 0; + + // Selects the tab at the specified |index|, which must be valid. + virtual void SelectTabAt(int index) = 0; + + // Returns the number of tabs. + virtual int GetTabCount() = 0; + + // Returns the index of the selected tab. + virtual int GetSelectedTabIndex() = 0; + + // Returns the contents of the selected tab. + virtual View* GetSelectedTab() = 0; + + // Retrieves the views::View that hosts the native control. + virtual View* GetView() = 0; + + // Sets the focus to the tabbed pane native view. + virtual void SetFocus() = 0; + + // Returns a handle to the underlying native view for testing. + virtual gfx::NativeView GetTestingHandle() const = 0; + + // Creates an appropriate NativeTabbedPaneWrapper for the platform. + static NativeTabbedPaneWrapper* CreateNativeWrapper(TabbedPane* tabbed_pane); +}; + +} // namespace views + +#endif // VIEWS_CONTROLS_TABBED_PANE_NATIVE_TABBED_PANE_WRAPPER_H_ diff --git a/views/controls/tabbed_pane/tabbed_pane.cc b/views/controls/tabbed_pane/tabbed_pane.cc new file mode 100644 index 0000000..20a2e7a --- /dev/null +++ b/views/controls/tabbed_pane/tabbed_pane.cc @@ -0,0 +1,89 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "views/controls/tabbed_pane/tabbed_pane.h" + +#include "views/controls/tabbed_pane/native_tabbed_pane_wrapper.h" + +namespace views { + +// static +const char TabbedPane::kViewClassName[] = "views/TabbedPane"; + +TabbedPane::TabbedPane() : native_tabbed_pane_(NULL), listener_(NULL) { + SetFocusable(true); +} + +TabbedPane::~TabbedPane() { +} + +void TabbedPane::SetListener(Listener* listener) { + listener_ = listener; +} + +void TabbedPane::AddTab(const std::wstring& title, View* contents) { + native_tabbed_pane_->AddTab(title, contents); +} + +void TabbedPane::AddTabAtIndex(int index, + const std::wstring& title, + View* contents, + bool select_if_first_tab) { + native_tabbed_pane_->AddTabAtIndex(index, title, contents, + select_if_first_tab); +} + +int TabbedPane::GetSelectedTabIndex() { + return native_tabbed_pane_->GetSelectedTabIndex(); +} + +View* TabbedPane::GetSelectedTab() { + return native_tabbed_pane_->GetSelectedTab(); +} + +View* TabbedPane::RemoveTabAtIndex(int index) { + return native_tabbed_pane_->RemoveTabAtIndex(index); +} + +void TabbedPane::SelectTabAt(int index) { + native_tabbed_pane_->SelectTabAt(index); +} + +int TabbedPane::GetTabCount() { + return native_tabbed_pane_->GetTabCount(); +} + +void TabbedPane::CreateWrapper() { + native_tabbed_pane_ = NativeTabbedPaneWrapper::CreateNativeWrapper(this); +} + +// View overrides: +std::string TabbedPane::GetClassName() const { + return kViewClassName; +} + +void TabbedPane::ViewHierarchyChanged(bool is_add, View* parent, View* child) { + if (is_add && !native_tabbed_pane_ && GetWidget()) { + CreateWrapper(); + AddChildView(native_tabbed_pane_->GetView()); + } +} + +void TabbedPane::Layout() { + if (native_tabbed_pane_) { + native_tabbed_pane_->GetView()->SetBounds(0, 0, width(), height()); + native_tabbed_pane_->GetView()->Layout(); + } +} + +void TabbedPane::Focus() { + // Forward the focus to the wrapper. + if (native_tabbed_pane_) + native_tabbed_pane_->SetFocus(); + else + View::Focus(); // Will focus the RootView window (so we still get keyboard + // messages). +} + +} // namespace views diff --git a/views/controls/tabbed_pane/tabbed_pane.h b/views/controls/tabbed_pane/tabbed_pane.h new file mode 100644 index 0000000..f0eb5a5 --- /dev/null +++ b/views/controls/tabbed_pane/tabbed_pane.h @@ -0,0 +1,92 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef VIEWS_CONTROLS_TABBED_PANE_H_ +#define VIEWS_CONTROLS_TABBED_PANE_H_ + +#include "views/view.h" + +namespace views { + +class NativeTabbedPaneWrapper; + +// The TabbedPane class is a view that shows tabs. When the user clicks on a +// tab, the associated view is displayed. +// TODO (jcampan): implement GetPreferredSize(). + +class TabbedPane : public View { + public: + TabbedPane(); + virtual ~TabbedPane(); + + // An interface an object can implement to be notified about events within + // the TabbedPane. + class Listener { + public: + // Called when the tab at the specified |index| is selected by the user. + virtual void TabSelectedAt(int index) = 0; + }; + void SetListener(Listener* listener); + + // Returns the number of tabs. + int GetTabCount(); + + // Returns the index of the selected tab. + int GetSelectedTabIndex(); + + // Returns the contents of the selected tab. + View* GetSelectedTab(); + + // Adds a new tab at the end of this TabbedPane with the specified |title|. + // |contents| is the view displayed when the tab is selected and is owned by + // the TabbedPane. + void AddTab(const std::wstring& title, View* contents); + + // Adds a new tab at the specified |index| with the specified |title|. + // |contents| is the view displayed when the tab is selected and is owned by + // the TabbedPane. If |select_if_first_tab| is true and the tabbed pane is + // currently empty, the new tab is selected. If you pass in false for + // |select_if_first_tab| you need to explicitly invoke SelectTabAt, otherwise + // the tabbed pane will not have a valid selection. + void AddTabAtIndex(int index, + const std::wstring& title, + View* contents, + bool select_if_first_tab); + + // Removes the tab at the specified |index| and returns the associated content + // view. The caller becomes the owner of the returned view. + View* RemoveTabAtIndex(int index); + + // Selects the tab at the specified |index|, which must be valid. + void SelectTabAt(int index); + + Listener* listener() const { return listener_; } + + // View overrides: + virtual void ViewHierarchyChanged(bool is_add, View* parent, View* child); + virtual std::string GetClassName() const; + virtual void Layout(); + virtual void Focus(); + + protected: + // The object that actually implements the tabbed-pane. + // Protected for tests access. + NativeTabbedPaneWrapper* native_tabbed_pane_; + + private: + // The tabbed-pane's class name. + static const char kViewClassName[]; + + // Creates the native wrapper. + void CreateWrapper(); + + // The listener we notify about tab selection changes. + Listener* listener_; + + DISALLOW_COPY_AND_ASSIGN(TabbedPane); +}; + +} // namespace views + +#endif // VIEWS_CONTROLS_TABBED_PANE_H_ -- cgit v1.1