| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright (c) 2006-2008 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 "views/controls/tabbed_pane.h" |  | 
|    6  |  | 
|    7 #include <vssym32.h> |  | 
|    8  |  | 
|    9 #include "app/gfx/canvas.h" |  | 
|   10 #include "app/gfx/font.h" |  | 
|   11 #include "app/l10n_util_win.h" |  | 
|   12 #include "app/resource_bundle.h" |  | 
|   13 #include "base/gfx/native_theme.h" |  | 
|   14 #include "base/logging.h" |  | 
|   15 #include "base/stl_util-inl.h" |  | 
|   16 #include "skia/ext/skia_utils_win.h" |  | 
|   17 #include "third_party/skia/include/core/SkColor.h" |  | 
|   18 #include "views/background.h" |  | 
|   19 #include "views/fill_layout.h" |  | 
|   20 #include "views/widget/root_view.h" |  | 
|   21 #include "views/widget/widget_win.h" |  | 
|   22  |  | 
|   23 namespace views { |  | 
|   24  |  | 
|   25 // A background object that paints the tab panel background which may be |  | 
|   26 // rendered by the system visual styles system. |  | 
|   27 class TabBackground : public Background { |  | 
|   28  public: |  | 
|   29   explicit TabBackground() { |  | 
|   30     // TMT_FILLCOLORHINT returns a color value that supposedly |  | 
|   31     // approximates the texture drawn by PaintTabPanelBackground. |  | 
|   32     SkColor tab_page_color = |  | 
|   33         gfx::NativeTheme::instance()->GetThemeColorWithDefault( |  | 
|   34             gfx::NativeTheme::TAB, TABP_BODY, 0, TMT_FILLCOLORHINT, |  | 
|   35             COLOR_3DFACE); |  | 
|   36     SetNativeControlColor(tab_page_color); |  | 
|   37   } |  | 
|   38   virtual ~TabBackground() {} |  | 
|   39  |  | 
|   40   virtual void Paint(gfx::Canvas* canvas, View* view) const { |  | 
|   41     HDC dc = canvas->beginPlatformPaint(); |  | 
|   42     RECT r = {0, 0, view->width(), view->height()}; |  | 
|   43     gfx::NativeTheme::instance()->PaintTabPanelBackground(dc, &r); |  | 
|   44     canvas->endPlatformPaint(); |  | 
|   45   } |  | 
|   46  |  | 
|   47  private: |  | 
|   48   DISALLOW_EVIL_CONSTRUCTORS(TabBackground); |  | 
|   49 }; |  | 
|   50  |  | 
|   51 TabbedPane::TabbedPane() : content_window_(NULL), listener_(NULL) { |  | 
|   52 } |  | 
|   53  |  | 
|   54 TabbedPane::~TabbedPane() { |  | 
|   55   // We own the tab views, let's delete them. |  | 
|   56   STLDeleteContainerPointers(tab_views_.begin(), tab_views_.end()); |  | 
|   57 } |  | 
|   58  |  | 
|   59 void TabbedPane::SetListener(Listener* listener) { |  | 
|   60   listener_ = listener; |  | 
|   61 } |  | 
|   62  |  | 
|   63 void TabbedPane::AddTab(const std::wstring& title, View* contents) { |  | 
|   64   AddTabAtIndex(static_cast<int>(tab_views_.size()), title, contents, true); |  | 
|   65 } |  | 
|   66  |  | 
|   67 void TabbedPane::AddTabAtIndex(int index, |  | 
|   68                                const std::wstring& title, |  | 
|   69                                View* contents, |  | 
|   70                                bool select_if_first_tab) { |  | 
|   71   DCHECK(index <= static_cast<int>(tab_views_.size())); |  | 
|   72   contents->SetParentOwned(false); |  | 
|   73   tab_views_.insert(tab_views_.begin() + index, contents); |  | 
|   74  |  | 
|   75   TCITEM tcitem; |  | 
|   76   tcitem.mask = TCIF_TEXT; |  | 
|   77  |  | 
|   78   // If the locale is RTL, we set the TCIF_RTLREADING so that BiDi text is |  | 
|   79   // rendered properly on the tabs. |  | 
|   80   if (UILayoutIsRightToLeft()) { |  | 
|   81     tcitem.mask |= TCIF_RTLREADING; |  | 
|   82   } |  | 
|   83  |  | 
|   84   tcitem.pszText = const_cast<wchar_t*>(title.c_str()); |  | 
|   85   int result = TabCtrl_InsertItem(tab_control_, index, &tcitem); |  | 
|   86   DCHECK(result != -1); |  | 
|   87  |  | 
|   88   if (!contents->background()) { |  | 
|   89     contents->set_background(new TabBackground); |  | 
|   90   } |  | 
|   91  |  | 
|   92   if (tab_views_.size() == 1 && select_if_first_tab) { |  | 
|   93     // If this is the only tab displayed, make sure the contents is set. |  | 
|   94     content_window_->GetRootView()->AddChildView(contents); |  | 
|   95   } |  | 
|   96  |  | 
|   97   // The newly added tab may have made the contents window smaller. |  | 
|   98   ResizeContents(tab_control_); |  | 
|   99 } |  | 
|  100  |  | 
|  101 View* TabbedPane::RemoveTabAtIndex(int index) { |  | 
|  102   int tab_count = static_cast<int>(tab_views_.size()); |  | 
|  103   DCHECK(index >= 0 && index < tab_count); |  | 
|  104  |  | 
|  105   if (index < (tab_count - 1)) { |  | 
|  106     // Select the next tab. |  | 
|  107     SelectTabAt(index + 1); |  | 
|  108   } else { |  | 
|  109     // We are the last tab, select the previous one. |  | 
|  110     if (index > 0) { |  | 
|  111       SelectTabAt(index - 1); |  | 
|  112     } else { |  | 
|  113       // That was the last tab. Remove the contents. |  | 
|  114       content_window_->GetRootView()->RemoveAllChildViews(false); |  | 
|  115     } |  | 
|  116   } |  | 
|  117   TabCtrl_DeleteItem(tab_control_, index); |  | 
|  118  |  | 
|  119   // The removed tab may have made the contents window bigger. |  | 
|  120   ResizeContents(tab_control_); |  | 
|  121  |  | 
|  122   std::vector<View*>::iterator iter = tab_views_.begin() + index; |  | 
|  123   View* removed_tab = *iter; |  | 
|  124   tab_views_.erase(iter); |  | 
|  125  |  | 
|  126   return removed_tab; |  | 
|  127 } |  | 
|  128  |  | 
|  129 void TabbedPane::SelectTabAt(int index) { |  | 
|  130   DCHECK((index >= 0) && (index < static_cast<int>(tab_views_.size()))); |  | 
|  131   TabCtrl_SetCurSel(tab_control_, index); |  | 
|  132   DoSelectTabAt(index); |  | 
|  133 } |  | 
|  134  |  | 
|  135 void TabbedPane::SelectTabForContents(const View* contents) { |  | 
|  136   SelectTabAt(GetIndexForContents(contents)); |  | 
|  137 } |  | 
|  138  |  | 
|  139 int TabbedPane::GetTabCount() { |  | 
|  140   return TabCtrl_GetItemCount(tab_control_); |  | 
|  141 } |  | 
|  142  |  | 
|  143 HWND TabbedPane::CreateNativeControl(HWND parent_container) { |  | 
|  144   // Create the tab control. |  | 
|  145   // |  | 
|  146   // Note that we don't follow the common convention for NativeControl |  | 
|  147   // subclasses and we don't pass the value returned from |  | 
|  148   // NativeControl::GetAdditionalExStyle() as the dwExStyle parameter. Here is |  | 
|  149   // why: on RTL locales, if we pass NativeControl::GetAdditionalExStyle() when |  | 
|  150   // we basically tell Windows to create our HWND with the WS_EX_LAYOUTRTL. If |  | 
|  151   // we do that, then the HWND we create for |content_window_| below will |  | 
|  152   // inherit the WS_EX_LAYOUTRTL property and this will result in the contents |  | 
|  153   // being flipped, which is not what we want (because we handle mirroring in |  | 
|  154   // views without the use of Windows' support for mirroring). Therefore, |  | 
|  155   // we initially create our HWND without the aforementioned property and we |  | 
|  156   // explicitly set this property our child is created. This way, on RTL |  | 
|  157   // locales, our tabs will be nicely rendered from right to left (by virtue of |  | 
|  158   // Windows doing the right thing with the TabbedPane HWND) and each tab |  | 
|  159   // contents will use an RTL layout correctly (by virtue of the mirroring |  | 
|  160   // infrastructure in views doing the right thing with each View we put |  | 
|  161   // in the tab). |  | 
|  162   tab_control_ = ::CreateWindowEx(0, |  | 
|  163                                   WC_TABCONTROL, |  | 
|  164                                   L"", |  | 
|  165                                   WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, |  | 
|  166                                   0, 0, width(), height(), |  | 
|  167                                   parent_container, NULL, NULL, NULL); |  | 
|  168  |  | 
|  169   HFONT font = ResourceBundle::GetSharedInstance(). |  | 
|  170       GetFont(ResourceBundle::BaseFont).hfont(); |  | 
|  171   SendMessage(tab_control_, WM_SETFONT, reinterpret_cast<WPARAM>(font), FALSE); |  | 
|  172  |  | 
|  173   // Create the view container which is a child of the TabControl. |  | 
|  174   content_window_ = new WidgetWin(); |  | 
|  175   content_window_->Init(tab_control_, gfx::Rect()); |  | 
|  176  |  | 
|  177   // Explicitly setting the WS_EX_LAYOUTRTL property for the HWND (see above |  | 
|  178   // for a thorough explanation regarding why we waited until |content_window_| |  | 
|  179   // if created before we set this property for the tabbed pane's HWND). |  | 
|  180   if (UILayoutIsRightToLeft()) { |  | 
|  181     l10n_util::HWNDSetRTLLayout(tab_control_); |  | 
|  182   } |  | 
|  183  |  | 
|  184   RootView* root_view = content_window_->GetRootView(); |  | 
|  185   root_view->SetLayoutManager(new FillLayout()); |  | 
|  186   DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT); |  | 
|  187   SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color), |  | 
|  188                                 GetBValue(sys_color)); |  | 
|  189   root_view->set_background(Background::CreateSolidBackground(color)); |  | 
|  190  |  | 
|  191   content_window_->SetFocusTraversableParentView(this); |  | 
|  192   ResizeContents(tab_control_); |  | 
|  193   return tab_control_; |  | 
|  194 } |  | 
|  195  |  | 
|  196 LRESULT TabbedPane::OnNotify(int w_param, LPNMHDR l_param) { |  | 
|  197   if (static_cast<LPNMHDR>(l_param)->code == TCN_SELCHANGE) { |  | 
|  198     int selected_tab = TabCtrl_GetCurSel(tab_control_); |  | 
|  199     DCHECK(selected_tab != -1); |  | 
|  200     DoSelectTabAt(selected_tab); |  | 
|  201     return TRUE; |  | 
|  202   } |  | 
|  203   return FALSE; |  | 
|  204 } |  | 
|  205  |  | 
|  206 void TabbedPane::DoSelectTabAt(int index) { |  | 
|  207   RootView* content_root = content_window_->GetRootView(); |  | 
|  208  |  | 
|  209   // Clear the focus if the focused view was on the tab. |  | 
|  210   FocusManager* focus_manager = GetFocusManager(); |  | 
|  211   DCHECK(focus_manager); |  | 
|  212   View* focused_view = focus_manager->GetFocusedView(); |  | 
|  213   if (focused_view && content_root->IsParentOf(focused_view)) |  | 
|  214     focus_manager->ClearFocus(); |  | 
|  215  |  | 
|  216   content_root->RemoveAllChildViews(false); |  | 
|  217   content_root->AddChildView(tab_views_[index]); |  | 
|  218   content_root->Layout(); |  | 
|  219   if (listener_) |  | 
|  220     listener_->TabSelectedAt(index); |  | 
|  221 } |  | 
|  222  |  | 
|  223 int TabbedPane::GetIndexForContents(const View* contents) const { |  | 
|  224   std::vector<View*>::const_iterator i = |  | 
|  225       std::find(tab_views_.begin(), tab_views_.end(), contents); |  | 
|  226   DCHECK(i != tab_views_.end()); |  | 
|  227   return static_cast<int>(i - tab_views_.begin()); |  | 
|  228 } |  | 
|  229  |  | 
|  230 void TabbedPane::Layout() { |  | 
|  231   NativeControl::Layout(); |  | 
|  232   ResizeContents(GetNativeControlHWND()); |  | 
|  233 } |  | 
|  234  |  | 
|  235 RootView* TabbedPane::GetContentsRootView() { |  | 
|  236   return content_window_->GetRootView(); |  | 
|  237 } |  | 
|  238  |  | 
|  239 FocusTraversable* TabbedPane::GetFocusTraversable() { |  | 
|  240   return content_window_; |  | 
|  241 } |  | 
|  242  |  | 
|  243 void TabbedPane::ViewHierarchyChanged(bool is_add, View *parent, View *child) { |  | 
|  244   NativeControl::ViewHierarchyChanged(is_add, parent, child); |  | 
|  245  |  | 
|  246   if (is_add && (child == this) && content_window_) { |  | 
|  247     // We have been added to a view hierarchy, update the FocusTraversable |  | 
|  248     // parent. |  | 
|  249     content_window_->SetFocusTraversableParent(GetRootView()); |  | 
|  250   } |  | 
|  251 } |  | 
|  252  |  | 
|  253 void TabbedPane::ResizeContents(HWND tab_control) { |  | 
|  254   DCHECK(tab_control); |  | 
|  255   CRect content_bounds; |  | 
|  256   if (!GetClientRect(tab_control, &content_bounds)) |  | 
|  257     return; |  | 
|  258   TabCtrl_AdjustRect(tab_control, FALSE, &content_bounds); |  | 
|  259   content_window_->MoveWindow(content_bounds.left, content_bounds.top, |  | 
|  260                               content_bounds.Width(), content_bounds.Height(), |  | 
|  261                               TRUE); |  | 
|  262 } |  | 
|  263  |  | 
|  264 }  // namespace views |  | 
| OLD | NEW |