summaryrefslogtreecommitdiffstats
path: root/views
diff options
context:
space:
mode:
authormnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-05 07:57:10 +0000
committermnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-05 07:57:10 +0000
commitf861719588545d92ba979f491f4cd10cbf544016 (patch)
tree5f5a64d4ba48a8d884ee360a562fb08371404ed6 /views
parent84aa957953cf6eb36c4e8886a28aede5fd98f748 (diff)
downloadchromium_src-f861719588545d92ba979f491f4cd10cbf544016.zip
chromium_src-f861719588545d92ba979f491f4cd10cbf544016.tar.gz
chromium_src-f861719588545d92ba979f491f4cd10cbf544016.tar.bz2
Re-land r51526
Auto-size the views version of the options dialog. This adds support for auto-sizing tab controls, adjusts the options dialog to use it and takes care of any fallout due to the new layout handling. Also fixes a couple of small bugs in the views Layout() machinery and sanitizes layouting of options pages. BUG=36497 TEST=unit tests in tabbed_pane_unittest.cc and grid_layout_unittest.cc, as well as checking the options dialog in any supported language. original issuse: http://codereview.chromium.org/2812026/show Review URL: http://codereview.chromium.org/2883022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@51628 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'views')
-rw-r--r--views/controls/button/native_button_win.cc17
-rw-r--r--views/controls/button/native_button_win.h10
-rw-r--r--views/controls/menu/menu_scroll_view_container.cc1
-rw-r--r--views/controls/native_control.cc2
-rw-r--r--views/controls/scrollbar/native_scroll_bar_win.cc34
-rw-r--r--views/controls/scrollbar/native_scroll_bar_win.h10
-rw-r--r--views/controls/tabbed_pane/native_tabbed_pane_gtk.cc23
-rw-r--r--views/controls/tabbed_pane/native_tabbed_pane_gtk.h3
-rw-r--r--views/controls/tabbed_pane/native_tabbed_pane_win.cc102
-rw-r--r--views/controls/tabbed_pane/native_tabbed_pane_win.h7
-rw-r--r--views/controls/tabbed_pane/native_tabbed_pane_wrapper.h5
-rw-r--r--views/controls/tabbed_pane/tabbed_pane.cc9
-rw-r--r--views/controls/tabbed_pane/tabbed_pane.h2
-rw-r--r--views/controls/tabbed_pane/tabbed_pane_unittest.cc83
-rw-r--r--views/controls/table/table_view.cc14
-rw-r--r--views/controls/table/table_view.h8
-rw-r--r--views/examples/tabbed_pane_example.h3
-rw-r--r--views/grid_layout.cc23
-rw-r--r--views/grid_layout.h3
-rw-r--r--views/grid_layout_unittest.cc60
-rw-r--r--views/view.cc9
-rw-r--r--views/widget/widget_gtk.cc14
-rw-r--r--views/widget/widget_gtk.h1
23 files changed, 362 insertions, 81 deletions
diff --git a/views/controls/button/native_button_win.cc b/views/controls/button/native_button_win.cc
index c485c71..9e24fc3 100644
--- a/views/controls/button/native_button_win.cc
+++ b/views/controls/button/native_button_win.cc
@@ -19,7 +19,8 @@ namespace views {
// NativeButtonWin, public:
NativeButtonWin::NativeButtonWin(NativeButton* native_button)
- : native_button_(native_button) {
+ : native_button_(native_button),
+ button_size_valid_(false) {
// Associates the actual HWND with the native_button so the native_button is
// the one considered as having the focus (not the wrapper) when the HWND is
// focused directly (with a click for example).
@@ -43,12 +44,14 @@ void NativeButtonWin::UpdateLabel() {
}
SetWindowText(native_view(), native_button_->label().c_str());
+ button_size_valid_ = false;
}
void NativeButtonWin::UpdateFont() {
SendMessage(native_view(), WM_SETFONT,
reinterpret_cast<WPARAM>(native_button_->font().hfont()),
FALSE);
+ button_size_valid_ = false;
}
void NativeButtonWin::UpdateEnabled() {
@@ -60,6 +63,7 @@ void NativeButtonWin::UpdateDefault() {
SendMessage(native_view(), BM_SETSTYLE,
native_button_->is_default() ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON,
true);
+ button_size_valid_ = false;
}
}
@@ -88,10 +92,13 @@ gfx::NativeView NativeButtonWin::GetTestingHandle() const {
// NativeButtonWin, View overrides:
gfx::Size NativeButtonWin::GetPreferredSize() {
- SIZE sz = {0};
- SendMessage(native_view(), BCM_GETIDEALSIZE, 0, reinterpret_cast<LPARAM>(&sz));
-
- return gfx::Size(sz.cx, sz.cy);
+ if (!button_size_valid_) {
+ SIZE sz = {0};
+ Button_GetIdealSize(native_view(), reinterpret_cast<LPARAM>(&sz));
+ button_size_.SetSize(sz.cx, sz.cy);
+ button_size_valid_ = true;
+ }
+ return button_size_;
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/views/controls/button/native_button_win.h b/views/controls/button/native_button_win.h
index 20ce575..95b8a5ac 100644
--- a/views/controls/button/native_button_win.h
+++ b/views/controls/button/native_button_win.h
@@ -1,6 +1,6 @@
-// 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.
+// Copyright (c) 2010 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_BUTTON_NATIVE_BUTTON_WIN_H_
#define VIEWS_CONTROLS_BUTTON_NATIVE_BUTTON_WIN_H_
@@ -49,6 +49,10 @@ class NativeButtonWin : public NativeControlWin,
// The NativeButton we are bound to.
NativeButton* native_button_;
+ // It's expensive to find the size of a button on windows, so we cache it.
+ mutable gfx::Size button_size_;
+ mutable bool button_size_valid_;
+
DISALLOW_COPY_AND_ASSIGN(NativeButtonWin);
};
diff --git a/views/controls/menu/menu_scroll_view_container.cc b/views/controls/menu/menu_scroll_view_container.cc
index cb92284..532366c 100644
--- a/views/controls/menu/menu_scroll_view_container.cc
+++ b/views/controls/menu/menu_scroll_view_container.cc
@@ -257,6 +257,7 @@ void MenuScrollViewContainer::DidChangeBounds(const gfx::Rect& previous,
gfx::Size content_pref = scroll_view_->GetContents()->GetPreferredSize();
scroll_up_button_->SetVisible(content_pref.height() > height());
scroll_down_button_->SetVisible(content_pref.height() > height());
+ Layout();
}
gfx::Size MenuScrollViewContainer::GetPreferredSize() {
diff --git a/views/controls/native_control.cc b/views/controls/native_control.cc
index f714382..0792b29 100644
--- a/views/controls/native_control.cc
+++ b/views/controls/native_control.cc
@@ -201,7 +201,7 @@ void NativeControl::ValidateNativeControl() {
void NativeControl::ViewHierarchyChanged(bool is_add, View *parent,
View *child) {
- if (is_add && child == this && GetWidget()) {
+ if (is_add && parent != this && !container_ && GetWidget()) {
ValidateNativeControl();
Layout();
}
diff --git a/views/controls/scrollbar/native_scroll_bar_win.cc b/views/controls/scrollbar/native_scroll_bar_win.cc
index e434b99..65350e0 100644
--- a/views/controls/scrollbar/native_scroll_bar_win.cc
+++ b/views/controls/scrollbar/native_scroll_bar_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -200,15 +200,15 @@ NativeScrollBarWin::NativeScrollBarWin(NativeScrollBar* scroll_bar)
: native_scroll_bar_(scroll_bar),
sb_container_(NULL) {
set_focus_view(scroll_bar);
+ memset(&scroll_info_, 0, sizeof(scroll_info_));
}
NativeScrollBarWin::~NativeScrollBarWin() {
- if (sb_container_) {
+ if (sb_container_.get()) {
// We always destroy the scrollbar container explicitly to cover all
// cases including when the container is no longer connected to a
// widget tree.
DestroyWindow(sb_container_->hwnd());
- delete sb_container_;
}
}
@@ -227,7 +227,7 @@ gfx::Size NativeScrollBarWin::GetPreferredSize() {
}
bool NativeScrollBarWin::OnKeyPressed(const KeyEvent& event) {
- if (!sb_container_)
+ if (!sb_container_.get())
return false;
int code = -1;
switch (event.GetKeyCode()) {
@@ -270,7 +270,7 @@ bool NativeScrollBarWin::OnKeyPressed(const KeyEvent& event) {
}
bool NativeScrollBarWin::OnMouseWheel(const MouseWheelEvent& e) {
- if (!sb_container_)
+ if (!sb_container_.get())
return false;
sb_container_->ScrollWithOffset(e.GetOffset());
return true;
@@ -280,8 +280,12 @@ bool NativeScrollBarWin::OnMouseWheel(const MouseWheelEvent& e) {
// NativeScrollBarWin, NativeControlWin overrides:
void NativeScrollBarWin::CreateNativeControl() {
- sb_container_ = new ScrollBarContainer(native_scroll_bar_);
+ sb_container_.reset(new ScrollBarContainer(native_scroll_bar_));
NativeControlCreated(sb_container_->hwnd());
+ // Reinstall scroll state if we have valid information.
+ if (scroll_info_.cbSize)
+ SetScrollInfo(sb_container_->GetScrollBarHWND(), SB_CTL, &scroll_info_,
+ TRUE);
}
////////////////////////////////////////////////////////////////////////////////
@@ -302,7 +306,7 @@ View* NativeScrollBarWin::GetView() {
void NativeScrollBarWin::Update(int viewport_size,
int content_size,
int current_pos) {
- if (!sb_container_)
+ if (!sb_container_.get())
return;
if (content_size < 0)
@@ -314,14 +318,13 @@ void NativeScrollBarWin::Update(int viewport_size,
if (current_pos > content_size)
current_pos = content_size;
- SCROLLINFO si;
- si.cbSize = sizeof(si);
- si.fMask = SIF_DISABLENOSCROLL | SIF_POS | SIF_RANGE | SIF_PAGE;
- si.nMin = 0;
- si.nMax = content_size;
- si.nPos = current_pos;
- si.nPage = viewport_size;
- SetScrollInfo(sb_container_->GetScrollBarHWND(), SB_CTL, &si, TRUE);
+ scroll_info_.cbSize = sizeof(scroll_info_);
+ scroll_info_.fMask = SIF_DISABLENOSCROLL | SIF_POS | SIF_RANGE | SIF_PAGE;
+ scroll_info_.nMin = 0;
+ scroll_info_.nMax = content_size;
+ scroll_info_.nPos = current_pos;
+ scroll_info_.nPage = viewport_size;
+ SetScrollInfo(sb_container_->GetScrollBarHWND(), SB_CTL, &scroll_info_, TRUE);
}
////////////////////////////////////////////////////////////////////////////////
@@ -344,4 +347,3 @@ int NativeScrollBarWrapper::GetVerticalScrollBarWidth() {
}
} // namespace views
-
diff --git a/views/controls/scrollbar/native_scroll_bar_win.h b/views/controls/scrollbar/native_scroll_bar_win.h
index 566f036..ba7dc25 100644
--- a/views/controls/scrollbar/native_scroll_bar_win.h
+++ b/views/controls/scrollbar/native_scroll_bar_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -51,7 +51,12 @@ class NativeScrollBarWin : public NativeControlWin,
// sb_container_ is a custom hwnd that we use to wrap the real
// windows scrollbar. We need to do this to get the scroll events
// without having to do anything special in the high level hwnd.
- ScrollBarContainer* sb_container_;
+ scoped_ptr<ScrollBarContainer> sb_container_;
+
+ // Last scrollbar state we wrote to the scrollbar. We keep it here, so we can
+ // reinitialize the scrollbar to its previous state in case it gets hidden and
+ // recreated.
+ SCROLLINFO scroll_info_;
DISALLOW_COPY_AND_ASSIGN(NativeScrollBarWin);
};
@@ -59,4 +64,3 @@ class NativeScrollBarWin : public NativeControlWin,
} // namespace views
#endif // #ifndef VIEWS_CONTROLS_SCROLLBAR_NATIVE_SCROLL_BAR_WIN_H_
-
diff --git a/views/controls/tabbed_pane/native_tabbed_pane_gtk.cc b/views/controls/tabbed_pane/native_tabbed_pane_gtk.cc
index 8900de3..25705fc 100644
--- a/views/controls/tabbed_pane/native_tabbed_pane_gtk.cc
+++ b/views/controls/tabbed_pane/native_tabbed_pane_gtk.cc
@@ -75,6 +75,11 @@ View* NativeTabbedPaneGtk::RemoveTabAtIndex(int index) {
// widget delete itself when native_view is deleted.
gtk_notebook_remove_page(GTK_NOTEBOOK(native_view()), index);
+ // Removing a tab might change the size of the tabbed pane.
+ RootView* root_view = GetRootView();
+ if (root_view)
+ GetRootView()->Layout();
+
return removed_tab;
}
@@ -103,6 +108,19 @@ void NativeTabbedPaneGtk::SetFocus() {
Focus();
}
+gfx::Size NativeTabbedPaneGtk::GetPreferredSize() {
+ if (!native_view())
+ return gfx::Size();
+
+ // For some strange reason (or maybe it's a bug), the requisition is not
+ // returned in the passed requisition parameter, but instead written to the
+ // widget's requisition field.
+ GtkRequisition requisition = { 0, 0 };
+ gtk_widget_size_request(GTK_WIDGET(native_view()), &requisition);
+ GtkRequisition& size(GTK_WIDGET(native_view())->requisition);
+ return gfx::Size(size.width, size.height);
+}
+
gfx::NativeView NativeTabbedPaneGtk::GetTestingHandle() const {
return native_view();
}
@@ -166,6 +184,11 @@ void NativeTabbedPaneGtk::DoAddTabAtIndex(int index, const std::wstring& title,
if (tab_count == 0 && select_if_first_tab)
gtk_notebook_set_current_page(GTK_NOTEBOOK(native_view()), 0);
+
+ // Relayout the hierarchy, since the added tab might require more space.
+ RootView* root_view = GetRootView();
+ if (root_view)
+ GetRootView()->Layout();
}
WidgetGtk* NativeTabbedPaneGtk::GetWidgetAt(int index) {
diff --git a/views/controls/tabbed_pane/native_tabbed_pane_gtk.h b/views/controls/tabbed_pane/native_tabbed_pane_gtk.h
index d586e74..229faa5 100644
--- a/views/controls/tabbed_pane/native_tabbed_pane_gtk.h
+++ b/views/controls/tabbed_pane/native_tabbed_pane_gtk.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -31,6 +31,7 @@ class NativeTabbedPaneGtk : public NativeControlGtk,
virtual View* GetSelectedTab();
virtual View* GetView();
virtual void SetFocus();
+ virtual gfx::Size GetPreferredSize();
virtual gfx::NativeView GetTestingHandle() const;
// NativeControlGtk overrides.
diff --git a/views/controls/tabbed_pane/native_tabbed_pane_win.cc b/views/controls/tabbed_pane/native_tabbed_pane_win.cc
index 388cb56..838991f 100644
--- a/views/controls/tabbed_pane/native_tabbed_pane_win.cc
+++ b/views/controls/tabbed_pane/native_tabbed_pane_win.cc
@@ -46,12 +46,64 @@ class TabBackground : public Background {
DISALLOW_COPY_AND_ASSIGN(TabBackground);
};
+// Custom layout manager that takes care of sizing and displaying the tab pages.
+class TabLayout : public LayoutManager {
+ public:
+ TabLayout() {}
+
+ // Switches to the tab page identified by the given index.
+ void SwitchToPage(View* host, View* page) {
+ for (int i = 0; i < host->GetChildViewCount(); ++i) {
+ View* child = host->GetChildViewAt(i);
+ // The child might not have been laid out yet.
+ if (child == page)
+ child->SetBounds(gfx::Rect(host->size()));
+ child->SetVisible(child == page);
+ }
+ }
+
+ private:
+ // LayoutManager overrides:
+ virtual void Layout(View* host) {
+ gfx::Rect bounds(host->size());
+ for (int i = 0; i < host->GetChildViewCount(); ++i) {
+ View* child = host->GetChildViewAt(i);
+ // We only layout visible children, since it may be expensive.
+ if (child->IsVisible() && child->bounds() != bounds)
+ child->SetBounds(bounds);
+ }
+ }
+
+ virtual gfx::Size GetPreferredSize(View* host) {
+ // First, query the preferred sizes to determine a good width.
+ int width = 0;
+ for (int i = 0; i < host->GetChildViewCount(); ++i) {
+ View* page = host->GetChildViewAt(i);
+ width = std::max(width, page->GetPreferredSize().width());
+ }
+ // After we know the width, decide on the height.
+ return gfx::Size(width, GetPreferredHeightForWidth(host, width));
+ }
+
+ virtual int GetPreferredHeightForWidth(View* host, int width) {
+ int height = 0;
+ for (int i = 0; i < host->GetChildViewCount(); ++i) {
+ View* page = host->GetChildViewAt(i);
+ height = std::max(height, page->GetHeightForWidth(width));
+ }
+ return height;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TabLayout);
+};
+
////////////////////////////////////////////////////////////////////////////////
// NativeTabbedPaneWin, public:
NativeTabbedPaneWin::NativeTabbedPaneWin(TabbedPane* tabbed_pane)
: NativeControlWin(),
tabbed_pane_(tabbed_pane),
+ tab_layout_manager_(NULL),
content_window_(NULL),
selected_index_(-1) {
// Associates the actual HWND with the tabbed-pane so the tabbed-pane is
@@ -77,31 +129,32 @@ void NativeTabbedPaneWin::AddTabAtIndex(int index, const std::wstring& title,
bool select_if_first_tab) {
DCHECK(index <= static_cast<int>(tab_views_.size()));
contents->set_parent_owned(false);
+ contents->SetVisible(false);
tab_views_.insert(tab_views_.begin() + index, contents);
tab_titles_.insert(tab_titles_.begin() + index, title);
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.
+ if (tab_views_.size() == 1 && select_if_first_tab)
selected_index_ = 0;
- if (content_window_)
- content_window_->GetRootView()->AddChildView(contents);
- }
// Add native tab only if the native control is alreay created.
if (content_window_) {
- AddNativeTab(index, title, contents);
-
+ AddNativeTab(index, title);
// The newly added tab may have made the contents window smaller.
ResizeContents();
+
+ RootView* content_root = content_window_->GetRootView();
+ content_root->AddChildView(contents);
+ // Switch to the newly added tab if requested;
+ if (tab_views_.size() == 1 && select_if_first_tab)
+ tab_layout_manager_->SwitchToPage(content_root, contents);
}
}
void NativeTabbedPaneWin::AddNativeTab(int index,
- const std::wstring &title,
- views::View* contents) {
+ const std::wstring &title) {
TCITEM tcitem;
tcitem.mask = TCIF_TEXT;
@@ -140,6 +193,8 @@ View* NativeTabbedPaneWin::RemoveTabAtIndex(int index) {
std::vector<View*>::iterator iter = tab_views_.begin() + index;
View* removed_tab = *iter;
+ if (content_window_)
+ content_window_->GetRootView()->RemoveChildView(removed_tab);
tab_views_.erase(iter);
tab_titles_.erase(tab_titles_.begin() + index);
@@ -176,6 +231,17 @@ void NativeTabbedPaneWin::SetFocus() {
Focus();
}
+gfx::Size NativeTabbedPaneWin::GetPreferredSize() {
+ if (!native_view())
+ return gfx::Size();
+
+ gfx::Rect contentSize(content_window_->GetRootView()->GetPreferredSize());
+ RECT paneSize = { 0, 0, contentSize.width(), contentSize.height() };
+ TabCtrl_AdjustRect(native_view(), TRUE, &paneSize);
+ return gfx::Size(paneSize.right - paneSize.left,
+ paneSize.bottom - paneSize.top);
+}
+
gfx::NativeView NativeTabbedPaneWin::GetTestingHandle() const {
return native_view();
}
@@ -225,7 +291,8 @@ void NativeTabbedPaneWin::CreateNativeControl() {
l10n_util::HWNDSetRTLLayout(tab_control);
RootView* root_view = content_window_->GetRootView();
- root_view->SetLayoutManager(new FillLayout());
+ tab_layout_manager_ = new TabLayout();
+ root_view->SetLayoutManager(tab_layout_manager_);
DWORD sys_color = ::GetSysColor(COLOR_3DHILIGHT);
SkColor color = SkColorSetRGB(GetRValue(sys_color), GetGValue(sys_color),
GetBValue(sys_color));
@@ -287,9 +354,13 @@ void NativeTabbedPaneWin::ViewHierarchyChanged(bool is_add,
// NativeTabbedPaneWin, private:
void NativeTabbedPaneWin::InitializeTabs() {
- for (size_t i = 0; i < tab_views_.size(); ++i) {
- AddNativeTab(i, tab_titles_[i], tab_views_[i]);
- }
+ for (size_t i = 0; i < tab_titles_.size(); ++i)
+ AddNativeTab(i, tab_titles_[i]);
+
+ RootView* content_root = content_window_->GetRootView();
+ for (std::vector<View*>::iterator tab(tab_views_.begin());
+ tab != tab_views_.end(); ++tab)
+ content_root->AddChildView(*tab);
}
void NativeTabbedPaneWin::DoSelectTabAt(int index, boolean invoke_listener) {
@@ -303,10 +374,7 @@ void NativeTabbedPaneWin::DoSelectTabAt(int index, boolean invoke_listener) {
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();
+ tab_layout_manager_->SwitchToPage(content_root, tab_views_.at(index));
}
if (invoke_listener && tabbed_pane_->listener())
tabbed_pane_->listener()->TabSelectedAt(index);
diff --git a/views/controls/tabbed_pane/native_tabbed_pane_win.h b/views/controls/tabbed_pane/native_tabbed_pane_win.h
index c3dcaed..4e4cc2a 100644
--- a/views/controls/tabbed_pane/native_tabbed_pane_win.h
+++ b/views/controls/tabbed_pane/native_tabbed_pane_win.h
@@ -13,6 +13,7 @@
namespace views {
class WidgetWin;
+class TabLayout;
class NativeTabbedPaneWin : public NativeControlWin,
public NativeTabbedPaneWrapper {
@@ -33,6 +34,7 @@ class NativeTabbedPaneWin : public NativeControlWin,
virtual View* GetSelectedTab();
virtual View* GetView();
virtual void SetFocus();
+ virtual gfx::Size GetPreferredSize();
virtual gfx::NativeView GetTestingHandle() const;
// NativeControlWin overrides.
@@ -57,7 +59,7 @@ class NativeTabbedPaneWin : public NativeControlWin,
void InitializeTabs();
// Adds a tab with the given content to native control at the given index.
- void AddNativeTab(int index, const std::wstring& title, View* contents);
+ void AddNativeTab(int index, const std::wstring& title);
// Changes the contents view to the view associated with the tab at |index|.
// |invoke_listener| controls if this methold should invoke the
@@ -70,6 +72,9 @@ class NativeTabbedPaneWin : public NativeControlWin,
// The tabbed-pane we are bound to.
TabbedPane* tabbed_pane_;
+ // The layout manager we use for managing our tabs.
+ TabLayout* tab_layout_manager_;
+
// The views associated with the different tabs.
std::vector<View*> tab_views_;
diff --git a/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h b/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h
index a051898..97c5fba 100644
--- a/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h
+++ b/views/controls/tabbed_pane/native_tabbed_pane_wrapper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -56,6 +56,9 @@ class NativeTabbedPaneWrapper {
// Sets the focus to the tabbed pane native view.
virtual void SetFocus() = 0;
+ // Gets the preferred size of the tabbed pane.
+ virtual gfx::Size GetPreferredSize() = 0;
+
// Returns a handle to the underlying native view for testing.
virtual gfx::NativeView GetTestingHandle() const = 0;
diff --git a/views/controls/tabbed_pane/tabbed_pane.cc b/views/controls/tabbed_pane/tabbed_pane.cc
index 5cb570a..1a7b0f0 100644
--- a/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/views/controls/tabbed_pane/tabbed_pane.cc
@@ -102,10 +102,8 @@ void TabbedPane::LoadAccelerators() {
}
void TabbedPane::Layout() {
- if (native_tabbed_pane_) {
+ if (native_tabbed_pane_)
native_tabbed_pane_->GetView()->SetBounds(0, 0, width(), height());
- native_tabbed_pane_->GetView()->Layout();
- }
}
void TabbedPane::Focus() {
@@ -129,4 +127,9 @@ bool TabbedPane::GetAccessibleRole(AccessibilityTypes::Role* role) {
return true;
}
+gfx::Size TabbedPane::GetPreferredSize() {
+ return native_tabbed_pane_ ?
+ native_tabbed_pane_->GetPreferredSize() : gfx::Size();
+}
+
} // namespace views
diff --git a/views/controls/tabbed_pane/tabbed_pane.h b/views/controls/tabbed_pane/tabbed_pane.h
index 2fe503e..36026a0 100644
--- a/views/controls/tabbed_pane/tabbed_pane.h
+++ b/views/controls/tabbed_pane/tabbed_pane.h
@@ -13,7 +13,6 @@ 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:
@@ -72,6 +71,7 @@ class TabbedPane : public View {
virtual void Focus();
virtual void PaintFocusBorder(gfx::Canvas* canvas);
virtual bool GetAccessibleRole(AccessibilityTypes::Role* role);
+ virtual gfx::Size GetPreferredSize();
NativeTabbedPaneWrapper* native_wrapper() const {
return native_tabbed_pane_;
diff --git a/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/views/controls/tabbed_pane/tabbed_pane_unittest.cc
new file mode 100644
index 0000000..51a4acb
--- /dev/null
+++ b/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2010 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 "base/message_loop.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "views/controls/tabbed_pane/tabbed_pane.h"
+#include "views/window/window.h"
+#include "views/window/window_delegate.h"
+
+namespace views {
+
+// A view for testing that takes a fixed preferred size upon construction.
+class FixedSizeView : public View {
+ public:
+ FixedSizeView(const gfx::Size& size)
+ : size_(size) {}
+
+ virtual gfx::Size GetPreferredSize() {
+ return size_;
+ }
+
+ private:
+ const gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(FixedSizeView);
+};
+
+class TabbedPaneTest : public testing::Test, WindowDelegate {
+ public:
+ TabbedPaneTest() {}
+
+ TabbedPane* tabbed_pane_;
+
+ private:
+ virtual void SetUp() {
+ tabbed_pane_ = new TabbedPane();
+ window_ = Window::CreateChromeWindow(NULL, gfx::Rect(0, 0, 100, 100), this);
+ window_->Show();
+ }
+
+ virtual void TearDown() {
+ window_->Close();
+ message_loop_.RunAllPending();
+ }
+
+ virtual views::View* GetContentsView() {
+ return tabbed_pane_;
+ }
+
+ MessageLoopForUI message_loop_;
+ Window* window_;
+
+ DISALLOW_COPY_AND_ASSIGN(TabbedPaneTest);
+};
+
+// Tests that TabbedPane::GetPreferredSize() and TabbedPane::Layout().
+TEST_F(TabbedPaneTest, SizeAndLayout) {
+ View* child1 = new FixedSizeView(gfx::Size(20, 10));
+ tabbed_pane_->AddTab(L"tab1", child1);
+ View* child2 = new FixedSizeView(gfx::Size(5, 5));
+ tabbed_pane_->AddTab(L"tab2", child2);
+ tabbed_pane_->SelectTabAt(0);
+
+ // Check that the preferred size is larger than the largest child.
+ gfx::Size pref(tabbed_pane_->GetPreferredSize());
+ EXPECT_GT(pref.width(), 20);
+ EXPECT_GT(pref.height(), 10);
+
+ // The bounds of our children should be smaller than the tabbed pane's bounds.
+ tabbed_pane_->SetBounds(0, 0, 100, 200);
+ gfx::Rect bounds(child1->bounds());
+ EXPECT_GT(bounds.width(), 0);
+ EXPECT_LT(bounds.width(), 100);
+ EXPECT_GT(bounds.height(), 0);
+ EXPECT_LT(bounds.height(), 200);
+
+ // If we switch to the other tab, it should get assigned the same bounds.
+ tabbed_pane_->SelectTabAt(1);
+ EXPECT_EQ(bounds, child2->bounds());
+}
+
+} // namespace views
diff --git a/views/controls/table/table_view.cc b/views/controls/table/table_view.cc
index 8b86a6e..7ab4c91 100644
--- a/views/controls/table/table_view.cc
+++ b/views/controls/table/table_view.cc
@@ -64,7 +64,6 @@ TableView::TableView(TableModel* model,
single_selection_(single_selection),
ignore_listview_change_(false),
custom_colors_enabled_(false),
- sized_columns_(false),
autosize_columns_(autosize_columns),
resizable_columns_(resizable_columns),
list_view_(NULL),
@@ -133,10 +132,8 @@ void TableView::DidChangeBounds(const gfx::Rect& previous,
return;
SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(FALSE), 0);
Layout();
- if ((!sized_columns_ || autosize_columns_) && width() > 0) {
- sized_columns_ = true;
+ if (autosize_columns_ && width() > 0)
ResetColumnSizes();
- }
UpdateContentOffset();
SendMessage(list_view_, WM_SETREDRAW, static_cast<WPARAM>(TRUE), 0);
}
@@ -1551,6 +1548,15 @@ gfx::Font TableView::GetAltTextFont() {
return ResourceBundle::GetSharedInstance().GetFont(ResourceBundle::BaseFont);
}
+void TableView::VisibilityChanged(View* starting_from, bool is_visible) {
+ // GetClientRect as used by ResetColumnSize to obtain the total width
+ // available to the columns only works when the native control is visible, so
+ // update the column sizes in case we become visible. This depends on
+ // VisibilityChanged() being called in post order on the view tree.
+ if (is_visible && autosize_columns_)
+ ResetColumnSizes();
+}
+
//
// TableSelectionIterator
diff --git a/views/controls/table/table_view.h b/views/controls/table/table_view.h
index f237df2..28d877e 100644
--- a/views/controls/table/table_view.h
+++ b/views/controls/table/table_view.h
@@ -407,6 +407,10 @@ class TableView : public NativeControl,
// Returns the font used for alt text.
gfx::Font GetAltTextFont();
+ // Overriden in order to update the column sizes, which can only be sized
+ // accurately when the native control is available.
+ virtual void VisibilityChanged(View* starting_from, bool is_visible);
+
TableModel* model_;
TableTypes table_type_;
TableViewObserver* table_view_observer_;
@@ -432,10 +436,6 @@ class TableView : public NativeControl,
// Reflects the value passed to SetCustomColorsEnabled.
bool custom_colors_enabled_;
- // Whether or not the columns have been sized in the ListView. This is
- // set to true the first time Layout() is invoked and we have a valid size.
- bool sized_columns_;
-
// Whether or not columns should automatically be resized to fill the
// the available width when the list view is resized.
bool autosize_columns_;
diff --git a/views/examples/tabbed_pane_example.h b/views/examples/tabbed_pane_example.h
index 4b4bdfc..1b712a8 100644
--- a/views/examples/tabbed_pane_example.h
+++ b/views/examples/tabbed_pane_example.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -109,4 +109,3 @@ class TabbedPaneExample : public ExampleBase,
} // namespace examples
#endif // VIEWS_EXAMPLES_TABBED_PANE_EXAMPLE_H_
-
diff --git a/views/grid_layout.cc b/views/grid_layout.cc
index b3f0625..5e685ac 100644
--- a/views/grid_layout.cc
+++ b/views/grid_layout.cc
@@ -844,22 +844,26 @@ void GridLayout::SizeRowsAndColumns(bool layout, int width, int height,
if (rows_.empty())
return;
- // Calculate the size of each of the columns. Some views preferred heights are
- // derived from their width, as such we need to calculate the size of the
- // columns first.
+ // Calculate the preferred width of each of the columns. Some views'
+ // preferred heights are derived from their width, as such we need to
+ // calculate the size of the columns first.
for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
i != column_sets_.end(); ++i) {
(*i)->CalculateSize();
- if (layout || width > 0) {
- // We're doing a layout, divy up any extra space.
- (*i)->Resize(width - (*i)->LayoutWidth() - left_inset_ - right_inset_);
- // And reset the x coordinates.
- (*i)->ResetColumnXCoordinates();
- }
pref->set_width(std::max(pref->width(), (*i)->LayoutWidth()));
}
pref->set_width(pref->width() + left_inset_ + right_inset_);
+ // Go over the columns again and set them all to the size we settled for.
+ width = width ? width : pref->width();
+ for (std::vector<ColumnSet*>::iterator i = column_sets_.begin();
+ i != column_sets_.end(); ++i) {
+ // We're doing a layout, divy up any extra space.
+ (*i)->Resize(width - (*i)->LayoutWidth() - left_inset_ - right_inset_);
+ // And reset the x coordinates.
+ (*i)->ResetColumnXCoordinates();
+ }
+
// Reset the height of each row.
LayoutElement::ResetSizes(&rows_);
@@ -1063,4 +1067,3 @@ views::GridLayout* CreatePanelGridLayout(views::View* host) {
kPanelVertMargin, kPanelHorizMargin);
return layout;
}
-
diff --git a/views/grid_layout.h b/views/grid_layout.h
index 6d6c61c..bb882ad 100644
--- a/views/grid_layout.h
+++ b/views/grid_layout.h
@@ -183,8 +183,7 @@ class GridLayout : public LayoutManager {
// they both call into this method. This sizes the Columns/Rows as
// appropriate. If layout is true, width/height give the width/height the
// of the host, otherwise they are ignored.
- void SizeRowsAndColumns(bool layout, int width, int height,
- gfx::Size* pref);
+ void SizeRowsAndColumns(bool layout, int width, int height, gfx::Size* pref);
// Calculates the master columns of all the column sets. See Column for
// a description of what a master column is.
diff --git a/views/grid_layout_unittest.cc b/views/grid_layout_unittest.cc
index c5e56fd..a70ae5f 100644
--- a/views/grid_layout_unittest.cc
+++ b/views/grid_layout_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -32,6 +32,25 @@ class SettableSizeView : public View {
gfx::Size pref_;
};
+// A view with fixed circumference that trades height for width.
+class FlexibleView : public View {
+ public:
+ explicit FlexibleView(int circumference) {
+ circumference_ = circumference;
+ }
+
+ virtual gfx::Size GetPreferredSize() {
+ return gfx::Size(0, circumference_ / 2);
+ }
+
+ virtual int GetHeightForWidth(int width) {
+ return std::max(0, circumference_ / 2 - width);
+ }
+
+ private:
+ int circumference_;
+};
+
class GridLayoutTest : public testing::Test {
public:
virtual void SetUp() {
@@ -548,3 +567,42 @@ TEST_F(GridLayoutTest, ColumnSpanResizing) {
// 4 + (6 * 4 / 6).
ExpectViewBoundsEquals(4, 40, 8, 40, view2);
}
+
+// Check that GetPreferredSize() takes resizing of columns into account when
+// there is additional space in the case we have column sets of different
+// preferred sizes.
+TEST_F(GridLayoutTest, ColumnResizingOnGetPreferredSize) {
+ views::ColumnSet* set = layout->AddColumnSet(0);
+ set->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
+ 1, views::GridLayout::USE_PREF, 0, 0);
+
+ set = layout->AddColumnSet(1);
+ set->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
+ 1, views::GridLayout::USE_PREF, 0, 0);
+
+ set = layout->AddColumnSet(2);
+ set->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
+ 1, views::GridLayout::USE_PREF, 0, 0);
+
+ // Make a row containing a flexible view that trades width for height.
+ layout->StartRow(0, 0);
+ View* view1 = new FlexibleView(100);
+ layout->AddView(view1, 1, 1, GridLayout::FILL, GridLayout::LEADING);
+
+ // The second row contains a view of fixed size that will enforce a column
+ // width of 20 pixels.
+ layout->StartRow(0, 1);
+ View* view2 = new SettableSizeView(gfx::Size(20, 20));
+ layout->AddView(view2, 1, 1, GridLayout::FILL, GridLayout::LEADING);
+
+ // Add another flexible view in row three in order to ensure column set
+ // ordering doesn't influence sizing behaviour.
+ layout->StartRow(0, 2);
+ View* view3 = new FlexibleView(40);
+ layout->AddView(view3, 1, 1, GridLayout::FILL, GridLayout::LEADING);
+
+ // We expect a height of 50: 30 from the variable width view in the first row
+ // plus 20 from the statically sized view in the second row. The flexible
+ // view in the third row should contribute no height.
+ EXPECT_EQ(gfx::Size(20, 50), layout->GetPreferredSize(&host));
+}
diff --git a/views/view.cc b/views/view.cc
index 90fb2bc..22b048b 100644
--- a/views/view.cc
+++ b/views/view.cc
@@ -218,17 +218,14 @@ void View::ScrollRectToVisible(const gfx::Rect& rect) {
/////////////////////////////////////////////////////////////////////////////
void View::Layout() {
- // Layout child Views
+ // If we have a layout manager, let it handle the layout for us.
if (layout_manager_.get()) {
layout_manager_->Layout(this);
SchedulePaint();
- // TODO(beng): We believe the right thing to do here is return since the
- // layout manager should be handling things, but it causes
- // regressions (missing options from Options dialog and a hang
- // in interactive_ui_tests).
+ return;
}
- // Lay out contents of child Views
+ // Otherwise, just pass on to the child views.
for (int i = 0, count = GetChildViewCount(); i < count; ++i) {
View* child = GetChildViewAt(i);
child->Layout();
diff --git a/views/widget/widget_gtk.cc b/views/widget/widget_gtk.cc
index 1e73e38..c9144d7 100644
--- a/views/widget/widget_gtk.cc
+++ b/views/widget/widget_gtk.cc
@@ -500,6 +500,8 @@ void WidgetGtk::Init(GtkWidget* parent,
GDK_KEY_RELEASE_MASK);
SetRootViewForWidget(widget_, root_view_.get());
+ g_signal_connect_after(G_OBJECT(window_contents_), "size_request",
+ G_CALLBACK(&OnSizeRequestThunk), this);
g_signal_connect_after(G_OBJECT(window_contents_), "size_allocate",
G_CALLBACK(&OnSizeAllocateThunk), this);
gtk_widget_set_app_paintable(window_contents_, true);
@@ -883,6 +885,18 @@ int WidgetGtk::GetFlagsForEventButton(const GdkEventButton& event) {
return flags;
}
+void WidgetGtk::OnSizeRequest(GtkWidget* widget, GtkRequisition* requisition) {
+ // Do only return the preferred size for child windows. GtkWindow interprets
+ // the requisition as a minimum size for top level windows, returning a
+ // preferred size for these would prevents us from setting smaller window
+ // sizes.
+ if (type_ == TYPE_CHILD) {
+ gfx::Size size(root_view_->GetPreferredSize());
+ requisition->width = size.width();
+ requisition->height = size.height();
+ }
+}
+
void WidgetGtk::OnSizeAllocate(GtkWidget* widget, GtkAllocation* allocation) {
// See comment next to size_ as to why we do this. Also note, it's tempting
// to put this in the static method so subclasses don't need to worry about
diff --git a/views/widget/widget_gtk.h b/views/widget/widget_gtk.h
index 816a263..3700aa3 100644
--- a/views/widget/widget_gtk.h
+++ b/views/widget/widget_gtk.h
@@ -223,6 +223,7 @@ class WidgetGtk
// Event handlers:
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnButtonPress, GdkEventButton*);
+ CHROMEGTK_CALLBACK_1(WidgetGtk, void, OnSizeRequest, GtkRequisition*);
CHROMEGTK_CALLBACK_1(WidgetGtk, void, OnSizeAllocate, GtkAllocation*);
CHROMEGTK_CALLBACK_1(WidgetGtk, gboolean, OnPaint, GdkEventExpose*);
CHROMEGTK_CALLBACK_4(WidgetGtk, void, OnDragDataGet,