Commit a375bb24 authored by wutao's avatar wutao Committed by Commit Bot

Add side tabs layout.

This cl implements the side tabs layout.
Major changes:
1. Allow choosing tab alignment upon init.
2. Support MD for vertical tab alignment.
3. Draw boarder for vertical tab alignment.

Bug: 793870
Test: Run in linux build. Screenshots are attached in the bug.
Change-Id: Ie39f6693ffb5271388f977e280e03d28c1957db9
Reviewed-on: https://chromium-review.googlesource.com/872050Reviewed-by: default avatarMichael Wasserman <msw@chromium.org>
Reviewed-by: default avatarAhmed Fakhry <afakhry@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Commit-Queue: Tao Wu <wutao@chromium.org>
Cr-Commit-Position: refs/heads/master@{#530702}
parent 31318191
...@@ -29,7 +29,13 @@ class VIEWS_EXPORT TabbedPane : public View { ...@@ -29,7 +29,13 @@ class VIEWS_EXPORT TabbedPane : public View {
// Internal class name. // Internal class name.
static const char kViewClassName[]; static const char kViewClassName[];
TabbedPane(); // The orientation of the tab alignment.
enum class Orientation {
kHorizontal,
kVertical,
};
explicit TabbedPane(Orientation orientation = Orientation::kHorizontal);
~TabbedPane() override; ~TabbedPane() override;
TabbedPaneListener* listener() const { return listener_; } TabbedPaneListener* listener() const { return listener_; }
...@@ -62,6 +68,9 @@ class VIEWS_EXPORT TabbedPane : public View { ...@@ -62,6 +68,9 @@ class VIEWS_EXPORT TabbedPane : public View {
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
const char* GetClassName() const override; const char* GetClassName() const override;
// Returns true if the tab alignment is horizontal.
bool IsHorizontal() const;
private: private:
friend class FocusTraversalTest; friend class FocusTraversalTest;
friend class Tab; friend class Tab;
...@@ -154,13 +163,13 @@ class Tab : public View { ...@@ -154,13 +163,13 @@ class Tab : public View {
DISALLOW_COPY_AND_ASSIGN(Tab); DISALLOW_COPY_AND_ASSIGN(Tab);
}; };
// The tab strip shown above the tab contents. // The tab strip shown above/left of the tab contents.
class TabStrip : public View { class TabStrip : public View {
public: public:
// Internal class name. // Internal class name.
static const char kViewClassName[]; static const char kViewClassName[];
TabStrip(); explicit TabStrip(TabbedPane::Orientation orientation);
~TabStrip() override; ~TabStrip() override;
// Called by TabStrip when the selected tab changes. This function is only // Called by TabStrip when the selected tab changes. This function is only
...@@ -177,7 +186,15 @@ class TabStrip : public View { ...@@ -177,7 +186,15 @@ class TabStrip : public View {
Tab* GetTabAtIndex(int index) const; Tab* GetTabAtIndex(int index) const;
int GetSelectedTabIndex() const; int GetSelectedTabIndex() const;
// Returns true if the tab alignment is horizontal.
bool IsHorizontal() const {
return orientation_ == TabbedPane::Orientation::kHorizontal;
}
private: private:
// The orientation of the tab alignment.
const TabbedPane::Orientation orientation_;
DISALLOW_COPY_AND_ASSIGN(TabStrip); DISALLOW_COPY_AND_ASSIGN(TabStrip);
}; };
......
...@@ -38,6 +38,11 @@ class TabbedPaneTest : public ViewsTestBase { ...@@ -38,6 +38,11 @@ class TabbedPaneTest : public ViewsTestBase {
} }
protected: protected:
void MakeTabbedPaneForOrientation(TabbedPane::Orientation orientation) {
tabbed_pane_ = std::make_unique<TabbedPane>(orientation);
tabbed_pane_->set_owned_by_client();
}
Tab* GetTabAt(int index) { Tab* GetTabAt(int index) {
return static_cast<Tab*>(tabbed_pane_->tab_strip_->child_at(index)); return static_cast<Tab*>(tabbed_pane_->tab_strip_->child_at(index));
} }
...@@ -58,7 +63,19 @@ class TabbedPaneTest : public ViewsTestBase { ...@@ -58,7 +63,19 @@ class TabbedPaneTest : public ViewsTestBase {
DISALLOW_COPY_AND_ASSIGN(TabbedPaneTest); DISALLOW_COPY_AND_ASSIGN(TabbedPaneTest);
}; };
// Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout(). // Tests tab orientation.
TEST_F(TabbedPaneTest, HorizontalOrientation) {
EXPECT_EQ(tabbed_pane_->IsHorizontal(), true);
}
// Tests tab orientation.
TEST_F(TabbedPaneTest, VerticalOrientation) {
MakeTabbedPaneForOrientation(TabbedPane::Orientation::kVertical);
EXPECT_EQ(tabbed_pane_->IsHorizontal(), false);
}
// Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout() when tabs
// aligned in horizontal orientation.
TEST_F(TabbedPaneTest, SizeAndLayout) { TEST_F(TabbedPaneTest, SizeAndLayout) {
View* child1 = new StaticSizedView(gfx::Size(20, 10)); View* child1 = new StaticSizedView(gfx::Size(20, 10));
tabbed_pane_->AddTab(ASCIIToUTF16("tab1"), child1); tabbed_pane_->AddTab(ASCIIToUTF16("tab1"), child1);
...@@ -90,6 +107,40 @@ TEST_F(TabbedPaneTest, SizeAndLayout) { ...@@ -90,6 +107,40 @@ TEST_F(TabbedPaneTest, SizeAndLayout) {
EXPECT_EQ(bounds, child2->bounds()); EXPECT_EQ(bounds, child2->bounds());
} }
// Tests TabbedPane::GetPreferredSize() and TabbedPane::Layout() when tabs
// aligned in vertical orientation.
TEST_F(TabbedPaneTest, SizeAndLayoutInVerticalOrientation) {
MakeTabbedPaneForOrientation(TabbedPane::Orientation::kVertical);
View* child1 = new StaticSizedView(gfx::Size(20, 10));
tabbed_pane_->AddTab(ASCIIToUTF16("tab1"), child1);
View* child2 = new StaticSizedView(gfx::Size(5, 5));
tabbed_pane_->AddTab(ASCIIToUTF16("tab2"), child2);
tabbed_pane_->SelectTabAt(0);
// The |tabbed_pane_| implementation of Views has no border by default.
// Therefore it should be as high as the highest tab. The native Windows
// tabbed pane has a border that used up extra space. Therefore the preferred
// height is larger than the largest child.
gfx::Size pref(tabbed_pane_->GetPreferredSize());
EXPECT_GT(pref.width(), 20);
EXPECT_GE(pref.height(), 10);
// The bounds of our children should be smaller than the tabbed pane's bounds.
tabbed_pane_->SetBounds(0, 0, 100, 200);
RunPendingMessages();
gfx::Rect bounds(child1->bounds());
EXPECT_GT(bounds.width(), 0);
EXPECT_LT(bounds.width(), 100);
EXPECT_GT(bounds.height(), 0);
// The |tabbed_pane_| has no border. Therefore the children should be as high
// as the |tabbed_pane_|.
EXPECT_LE(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());
}
TEST_F(TabbedPaneTest, AddAndSelect) { TEST_F(TabbedPaneTest, AddAndSelect) {
// Add several tabs; only the first should be selected automatically. // Add several tabs; only the first should be selected automatically.
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment