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/scroll_view.h" 6 7 #include "testing/gtest/include/gtest/gtest.h" 8 9 namespace views { 10 11 namespace { 12 13 // View implementation that allows setting the preferred size. 14 class CustomView : public View { 15 public: 16 CustomView() {} 17 18 void SetPreferredSize(const gfx::Size& size) { 19 preferred_size_ = size; 20 PreferredSizeChanged(); 21 } 22 23 virtual gfx::Size GetPreferredSize() OVERRIDE { 24 return preferred_size_; 25 } 26 27 virtual void Layout() OVERRIDE { 28 gfx::Size pref = GetPreferredSize(); 29 int width = pref.width(); 30 int height = pref.height(); 31 if (parent()) { 32 width = std::max(parent()->width(), width); 33 height = std::max(parent()->height(), height); 34 } 35 SetBounds(x(), y(), width, height); 36 } 37 38 private: 39 gfx::Size preferred_size_; 40 41 DISALLOW_COPY_AND_ASSIGN(CustomView); 42 }; 43 44 } // namespace 45 46 // Verifies the viewport is sized to fit the available space. 47 TEST(ScrollViewTest, ViewportSizedToFit) { 48 ScrollView scroll_view; 49 View* contents = new View; 50 scroll_view.SetContents(contents); 51 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 52 scroll_view.Layout(); 53 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); 54 } 55 56 // Verifies the scrollbars are added as necessary. 57 TEST(ScrollViewTest, ScrollBars) { 58 ScrollView scroll_view; 59 View* contents = new View; 60 scroll_view.SetContents(contents); 61 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 62 63 // Size the contents such that vertical scrollbar is needed. 64 contents->SetBounds(0, 0, 50, 400); 65 scroll_view.Layout(); 66 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); 67 EXPECT_EQ(100, contents->parent()->height()); 68 EXPECT_TRUE(!scroll_view.horizontal_scroll_bar() || 69 !scroll_view.horizontal_scroll_bar()->visible()); 70 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); 71 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); 72 73 // Size the contents such that horizontal scrollbar is needed. 74 contents->SetBounds(0, 0, 400, 50); 75 scroll_view.Layout(); 76 EXPECT_EQ(100, contents->parent()->width()); 77 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight(), 78 contents->parent()->height()); 79 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); 80 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); 81 EXPECT_TRUE(!scroll_view.vertical_scroll_bar() || 82 !scroll_view.vertical_scroll_bar()->visible()); 83 84 // Both horizontal and vertical. 85 contents->SetBounds(0, 0, 300, 400); 86 scroll_view.Layout(); 87 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); 88 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight(), 89 contents->parent()->height()); 90 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); 91 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); 92 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); 93 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); 94 } 95 96 // Assertions around adding a header. 97 TEST(ScrollViewTest, Header) { 98 ScrollView scroll_view; 99 View* contents = new View; 100 CustomView* header = new CustomView; 101 scroll_view.SetHeader(header); 102 View* header_parent = header->parent(); 103 scroll_view.SetContents(contents); 104 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 105 scroll_view.Layout(); 106 // |header|s preferred size is empty, which should result in all space going 107 // to contents. 108 EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString()); 109 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); 110 111 // Get the header a height of 20. 112 header->SetPreferredSize(gfx::Size(10, 20)); 113 EXPECT_EQ("0,0 100x20", header->parent()->bounds().ToString()); 114 EXPECT_EQ("0,20 100x80", contents->parent()->bounds().ToString()); 115 116 // Remove the header. 117 scroll_view.SetHeader(NULL); 118 // SetHeader(NULL) deletes header. 119 header = NULL; 120 EXPECT_EQ("0,0 100x0", header_parent->bounds().ToString()); 121 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); 122 } 123 124 // Verifies the scrollbars are added as necessary when a header is present. 125 TEST(ScrollViewTest, ScrollBarsWithHeader) { 126 ScrollView scroll_view; 127 View* contents = new View; 128 scroll_view.SetContents(contents); 129 CustomView* header = new CustomView; 130 scroll_view.SetHeader(header); 131 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 132 133 header->SetPreferredSize(gfx::Size(10, 20)); 134 135 // Size the contents such that vertical scrollbar is needed. 136 contents->SetBounds(0, 0, 50, 400); 137 scroll_view.Layout(); 138 EXPECT_EQ(0, contents->parent()->x()); 139 EXPECT_EQ(20, contents->parent()->y()); 140 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); 141 EXPECT_EQ(80, contents->parent()->height()); 142 EXPECT_EQ(0, header->parent()->x()); 143 EXPECT_EQ(0, header->parent()->y()); 144 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), header->parent()->width()); 145 EXPECT_EQ(20, header->parent()->height()); 146 EXPECT_TRUE(!scroll_view.horizontal_scroll_bar() || 147 !scroll_view.horizontal_scroll_bar()->visible()); 148 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); 149 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); 150 151 152 // Size the contents such that horizontal scrollbar is needed. 153 contents->SetBounds(0, 0, 400, 50); 154 scroll_view.Layout(); 155 EXPECT_EQ(0, contents->parent()->x()); 156 EXPECT_EQ(20, contents->parent()->y()); 157 EXPECT_EQ(100, contents->parent()->width()); 158 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight() - 20, 159 contents->parent()->height()); 160 EXPECT_EQ(0, header->parent()->x()); 161 EXPECT_EQ(0, header->parent()->y()); 162 EXPECT_EQ(100, header->parent()->width()); 163 EXPECT_EQ(20, header->parent()->height()); 164 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); 165 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); 166 EXPECT_TRUE(!scroll_view.vertical_scroll_bar() || 167 !scroll_view.vertical_scroll_bar()->visible()); 168 169 // Both horizontal and vertical. 170 contents->SetBounds(0, 0, 300, 400); 171 scroll_view.Layout(); 172 EXPECT_EQ(0, contents->parent()->x()); 173 EXPECT_EQ(20, contents->parent()->y()); 174 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); 175 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight() - 20, 176 contents->parent()->height()); 177 EXPECT_EQ(0, header->parent()->x()); 178 EXPECT_EQ(0, header->parent()->y()); 179 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), header->parent()->width()); 180 EXPECT_EQ(20, header->parent()->height()); 181 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); 182 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); 183 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); 184 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); 185 } 186 187 // Verifies the header scrolls horizontally with the content. 188 TEST(ScrollViewTest, HeaderScrollsWithContent) { 189 ScrollView scroll_view; 190 CustomView* contents = new CustomView; 191 scroll_view.SetContents(contents); 192 contents->SetPreferredSize(gfx::Size(500, 500)); 193 194 CustomView* header = new CustomView; 195 scroll_view.SetHeader(header); 196 header->SetPreferredSize(gfx::Size(500, 20)); 197 198 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 199 EXPECT_EQ("0,0", contents->bounds().origin().ToString()); 200 EXPECT_EQ("0,0", header->bounds().origin().ToString()); 201 202 // Scroll the horizontal scrollbar. 203 ASSERT_TRUE(scroll_view.horizontal_scroll_bar()); 204 scroll_view.ScrollToPosition( 205 const_cast<ScrollBar*>(scroll_view.horizontal_scroll_bar()), 1); 206 EXPECT_EQ("-1,0", contents->bounds().origin().ToString()); 207 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); 208 209 // Scrolling the vertical scrollbar shouldn't effect the header. 210 ASSERT_TRUE(scroll_view.vertical_scroll_bar()); 211 scroll_view.ScrollToPosition( 212 const_cast<ScrollBar*>(scroll_view.vertical_scroll_bar()), 1); 213 EXPECT_EQ("-1,-1", contents->bounds().origin().ToString()); 214 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); 215 } 216 217 218 // Verifies ScrollRectToVisible() on the child works. 219 TEST(ScrollViewTest, ScrollRectToVisible) { 220 ScrollView scroll_view; 221 CustomView* contents = new CustomView; 222 scroll_view.SetContents(contents); 223 contents->SetPreferredSize(gfx::Size(500, 1000)); 224 225 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); 226 scroll_view.Layout(); 227 EXPECT_EQ("0,0", contents->bounds().origin().ToString()); 228 229 // Scroll to y=405 height=10, this should make the y position of the content 230 // at (405 + 10) - viewport_height (scroll region bottom aligned). 231 contents->ScrollRectToVisible(gfx::Rect(0, 405, 10, 10)); 232 const int viewport_height = contents->parent()->height(); 233 EXPECT_EQ(-(415 - viewport_height), contents->y()); 234 235 // Scroll to the current y-location and 10x10; should do nothing. 236 contents->ScrollRectToVisible(gfx::Rect(0, -contents->y(), 10, 10)); 237 EXPECT_EQ(-(415 - viewport_height), contents->y()); 238 } 239 240 } // namespace views 241