| OLD | NEW |
| (Empty) |
| 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 #include "ui/views/controls/scrollbar/overlay_scroll_bar.h" | |
| 9 #include "ui/views/test/test_views.h" | |
| 10 | |
| 11 namespace views { | |
| 12 | |
| 13 namespace { | |
| 14 | |
| 15 const int kWidth = 100; | |
| 16 const int kMinHeight = 50; | |
| 17 const int kMaxHeight = 100; | |
| 18 | |
| 19 // View implementation that allows setting the preferred size. | |
| 20 class CustomView : public View { | |
| 21 public: | |
| 22 CustomView() {} | |
| 23 | |
| 24 void SetPreferredSize(const gfx::Size& size) { | |
| 25 preferred_size_ = size; | |
| 26 PreferredSizeChanged(); | |
| 27 } | |
| 28 | |
| 29 virtual gfx::Size GetPreferredSize() const override { | |
| 30 return preferred_size_; | |
| 31 } | |
| 32 | |
| 33 virtual void Layout() override { | |
| 34 gfx::Size pref = GetPreferredSize(); | |
| 35 int width = pref.width(); | |
| 36 int height = pref.height(); | |
| 37 if (parent()) { | |
| 38 width = std::max(parent()->width(), width); | |
| 39 height = std::max(parent()->height(), height); | |
| 40 } | |
| 41 SetBounds(x(), y(), width, height); | |
| 42 } | |
| 43 | |
| 44 private: | |
| 45 gfx::Size preferred_size_; | |
| 46 | |
| 47 DISALLOW_COPY_AND_ASSIGN(CustomView); | |
| 48 }; | |
| 49 | |
| 50 } // namespace | |
| 51 | |
| 52 // Verifies the viewport is sized to fit the available space. | |
| 53 TEST(ScrollViewTest, ViewportSizedToFit) { | |
| 54 ScrollView scroll_view; | |
| 55 View* contents = new View; | |
| 56 scroll_view.SetContents(contents); | |
| 57 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | |
| 58 scroll_view.Layout(); | |
| 59 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); | |
| 60 } | |
| 61 | |
| 62 // Verifies the scrollbars are added as necessary. | |
| 63 TEST(ScrollViewTest, ScrollBars) { | |
| 64 ScrollView scroll_view; | |
| 65 View* contents = new View; | |
| 66 scroll_view.SetContents(contents); | |
| 67 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | |
| 68 | |
| 69 // Size the contents such that vertical scrollbar is needed. | |
| 70 contents->SetBounds(0, 0, 50, 400); | |
| 71 scroll_view.Layout(); | |
| 72 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); | |
| 73 EXPECT_EQ(100, contents->parent()->height()); | |
| 74 EXPECT_TRUE(!scroll_view.horizontal_scroll_bar() || | |
| 75 !scroll_view.horizontal_scroll_bar()->visible()); | |
| 76 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); | |
| 77 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); | |
| 78 | |
| 79 // Size the contents such that horizontal scrollbar is needed. | |
| 80 contents->SetBounds(0, 0, 400, 50); | |
| 81 scroll_view.Layout(); | |
| 82 EXPECT_EQ(100, contents->parent()->width()); | |
| 83 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight(), | |
| 84 contents->parent()->height()); | |
| 85 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); | |
| 86 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); | |
| 87 EXPECT_TRUE(!scroll_view.vertical_scroll_bar() || | |
| 88 !scroll_view.vertical_scroll_bar()->visible()); | |
| 89 | |
| 90 // Both horizontal and vertical. | |
| 91 contents->SetBounds(0, 0, 300, 400); | |
| 92 scroll_view.Layout(); | |
| 93 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); | |
| 94 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight(), | |
| 95 contents->parent()->height()); | |
| 96 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); | |
| 97 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); | |
| 98 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); | |
| 99 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); | |
| 100 } | |
| 101 | |
| 102 // Assertions around adding a header. | |
| 103 TEST(ScrollViewTest, Header) { | |
| 104 ScrollView scroll_view; | |
| 105 View* contents = new View; | |
| 106 CustomView* header = new CustomView; | |
| 107 scroll_view.SetHeader(header); | |
| 108 View* header_parent = header->parent(); | |
| 109 scroll_view.SetContents(contents); | |
| 110 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | |
| 111 scroll_view.Layout(); | |
| 112 // |header|s preferred size is empty, which should result in all space going | |
| 113 // to contents. | |
| 114 EXPECT_EQ("0,0 100x0", header->parent()->bounds().ToString()); | |
| 115 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); | |
| 116 | |
| 117 // Get the header a height of 20. | |
| 118 header->SetPreferredSize(gfx::Size(10, 20)); | |
| 119 EXPECT_EQ("0,0 100x20", header->parent()->bounds().ToString()); | |
| 120 EXPECT_EQ("0,20 100x80", contents->parent()->bounds().ToString()); | |
| 121 | |
| 122 // Remove the header. | |
| 123 scroll_view.SetHeader(NULL); | |
| 124 // SetHeader(NULL) deletes header. | |
| 125 header = NULL; | |
| 126 EXPECT_EQ("0,0 100x0", header_parent->bounds().ToString()); | |
| 127 EXPECT_EQ("0,0 100x100", contents->parent()->bounds().ToString()); | |
| 128 } | |
| 129 | |
| 130 // Verifies the scrollbars are added as necessary when a header is present. | |
| 131 TEST(ScrollViewTest, ScrollBarsWithHeader) { | |
| 132 ScrollView scroll_view; | |
| 133 View* contents = new View; | |
| 134 scroll_view.SetContents(contents); | |
| 135 CustomView* header = new CustomView; | |
| 136 scroll_view.SetHeader(header); | |
| 137 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | |
| 138 | |
| 139 header->SetPreferredSize(gfx::Size(10, 20)); | |
| 140 | |
| 141 // Size the contents such that vertical scrollbar is needed. | |
| 142 contents->SetBounds(0, 0, 50, 400); | |
| 143 scroll_view.Layout(); | |
| 144 EXPECT_EQ(0, contents->parent()->x()); | |
| 145 EXPECT_EQ(20, contents->parent()->y()); | |
| 146 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); | |
| 147 EXPECT_EQ(80, contents->parent()->height()); | |
| 148 EXPECT_EQ(0, header->parent()->x()); | |
| 149 EXPECT_EQ(0, header->parent()->y()); | |
| 150 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), header->parent()->width()); | |
| 151 EXPECT_EQ(20, header->parent()->height()); | |
| 152 EXPECT_TRUE(!scroll_view.horizontal_scroll_bar() || | |
| 153 !scroll_view.horizontal_scroll_bar()->visible()); | |
| 154 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); | |
| 155 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); | |
| 156 | |
| 157 // Size the contents such that horizontal scrollbar is needed. | |
| 158 contents->SetBounds(0, 0, 400, 50); | |
| 159 scroll_view.Layout(); | |
| 160 EXPECT_EQ(0, contents->parent()->x()); | |
| 161 EXPECT_EQ(20, contents->parent()->y()); | |
| 162 EXPECT_EQ(100, contents->parent()->width()); | |
| 163 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight() - 20, | |
| 164 contents->parent()->height()); | |
| 165 EXPECT_EQ(0, header->parent()->x()); | |
| 166 EXPECT_EQ(0, header->parent()->y()); | |
| 167 EXPECT_EQ(100, header->parent()->width()); | |
| 168 EXPECT_EQ(20, header->parent()->height()); | |
| 169 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); | |
| 170 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); | |
| 171 EXPECT_TRUE(!scroll_view.vertical_scroll_bar() || | |
| 172 !scroll_view.vertical_scroll_bar()->visible()); | |
| 173 | |
| 174 // Both horizontal and vertical. | |
| 175 contents->SetBounds(0, 0, 300, 400); | |
| 176 scroll_view.Layout(); | |
| 177 EXPECT_EQ(0, contents->parent()->x()); | |
| 178 EXPECT_EQ(20, contents->parent()->y()); | |
| 179 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), contents->parent()->width()); | |
| 180 EXPECT_EQ(100 - scroll_view.GetScrollBarHeight() - 20, | |
| 181 contents->parent()->height()); | |
| 182 EXPECT_EQ(0, header->parent()->x()); | |
| 183 EXPECT_EQ(0, header->parent()->y()); | |
| 184 EXPECT_EQ(100 - scroll_view.GetScrollBarWidth(), header->parent()->width()); | |
| 185 EXPECT_EQ(20, header->parent()->height()); | |
| 186 ASSERT_TRUE(scroll_view.horizontal_scroll_bar() != NULL); | |
| 187 EXPECT_TRUE(scroll_view.horizontal_scroll_bar()->visible()); | |
| 188 ASSERT_TRUE(scroll_view.vertical_scroll_bar() != NULL); | |
| 189 EXPECT_TRUE(scroll_view.vertical_scroll_bar()->visible()); | |
| 190 } | |
| 191 | |
| 192 // Verifies the header scrolls horizontally with the content. | |
| 193 TEST(ScrollViewTest, HeaderScrollsWithContent) { | |
| 194 ScrollView scroll_view; | |
| 195 CustomView* contents = new CustomView; | |
| 196 scroll_view.SetContents(contents); | |
| 197 contents->SetPreferredSize(gfx::Size(500, 500)); | |
| 198 | |
| 199 CustomView* header = new CustomView; | |
| 200 scroll_view.SetHeader(header); | |
| 201 header->SetPreferredSize(gfx::Size(500, 20)); | |
| 202 | |
| 203 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | |
| 204 EXPECT_EQ("0,0", contents->bounds().origin().ToString()); | |
| 205 EXPECT_EQ("0,0", header->bounds().origin().ToString()); | |
| 206 | |
| 207 // Scroll the horizontal scrollbar. | |
| 208 ASSERT_TRUE(scroll_view.horizontal_scroll_bar()); | |
| 209 scroll_view.ScrollToPosition( | |
| 210 const_cast<ScrollBar*>(scroll_view.horizontal_scroll_bar()), 1); | |
| 211 EXPECT_EQ("-1,0", contents->bounds().origin().ToString()); | |
| 212 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); | |
| 213 | |
| 214 // Scrolling the vertical scrollbar shouldn't effect the header. | |
| 215 ASSERT_TRUE(scroll_view.vertical_scroll_bar()); | |
| 216 scroll_view.ScrollToPosition( | |
| 217 const_cast<ScrollBar*>(scroll_view.vertical_scroll_bar()), 1); | |
| 218 EXPECT_EQ("-1,-1", contents->bounds().origin().ToString()); | |
| 219 EXPECT_EQ("-1,0", header->bounds().origin().ToString()); | |
| 220 } | |
| 221 | |
| 222 // Verifies ScrollRectToVisible() on the child works. | |
| 223 TEST(ScrollViewTest, ScrollRectToVisible) { | |
| 224 ScrollView scroll_view; | |
| 225 CustomView* contents = new CustomView; | |
| 226 scroll_view.SetContents(contents); | |
| 227 contents->SetPreferredSize(gfx::Size(500, 1000)); | |
| 228 | |
| 229 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | |
| 230 scroll_view.Layout(); | |
| 231 EXPECT_EQ("0,0", contents->bounds().origin().ToString()); | |
| 232 | |
| 233 // Scroll to y=405 height=10, this should make the y position of the content | |
| 234 // at (405 + 10) - viewport_height (scroll region bottom aligned). | |
| 235 contents->ScrollRectToVisible(gfx::Rect(0, 405, 10, 10)); | |
| 236 const int viewport_height = contents->parent()->height(); | |
| 237 EXPECT_EQ(-(415 - viewport_height), contents->y()); | |
| 238 | |
| 239 // Scroll to the current y-location and 10x10; should do nothing. | |
| 240 contents->ScrollRectToVisible(gfx::Rect(0, -contents->y(), 10, 10)); | |
| 241 EXPECT_EQ(-(415 - viewport_height), contents->y()); | |
| 242 } | |
| 243 | |
| 244 // Verifies ClipHeightTo() uses the height of the content when it is between the | |
| 245 // minimum and maximum height values. | |
| 246 TEST(ScrollViewTest, ClipHeightToNormalContentHeight) { | |
| 247 ScrollView scroll_view; | |
| 248 | |
| 249 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); | |
| 250 | |
| 251 const int kNormalContentHeight = 75; | |
| 252 scroll_view.SetContents( | |
| 253 new views::StaticSizedView(gfx::Size(kWidth, kNormalContentHeight))); | |
| 254 | |
| 255 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), | |
| 256 scroll_view.GetPreferredSize()); | |
| 257 | |
| 258 scroll_view.SizeToPreferredSize(); | |
| 259 scroll_view.Layout(); | |
| 260 | |
| 261 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), | |
| 262 scroll_view.contents()->size()); | |
| 263 EXPECT_EQ(gfx::Size(kWidth, kNormalContentHeight), scroll_view.size()); | |
| 264 } | |
| 265 | |
| 266 // Verifies ClipHeightTo() uses the minimum height when the content is shorter | |
| 267 // thamn the minimum height value. | |
| 268 TEST(ScrollViewTest, ClipHeightToShortContentHeight) { | |
| 269 ScrollView scroll_view; | |
| 270 | |
| 271 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); | |
| 272 | |
| 273 const int kShortContentHeight = 10; | |
| 274 scroll_view.SetContents( | |
| 275 new views::StaticSizedView(gfx::Size(kWidth, kShortContentHeight))); | |
| 276 | |
| 277 EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.GetPreferredSize()); | |
| 278 | |
| 279 scroll_view.SizeToPreferredSize(); | |
| 280 scroll_view.Layout(); | |
| 281 | |
| 282 EXPECT_EQ(gfx::Size(kWidth, kShortContentHeight), | |
| 283 scroll_view.contents()->size()); | |
| 284 EXPECT_EQ(gfx::Size(kWidth, kMinHeight), scroll_view.size()); | |
| 285 } | |
| 286 | |
| 287 // Verifies ClipHeightTo() uses the maximum height when the content is longer | |
| 288 // thamn the maximum height value. | |
| 289 TEST(ScrollViewTest, ClipHeightToTallContentHeight) { | |
| 290 ScrollView scroll_view; | |
| 291 | |
| 292 // Use a scrollbar that is disabled by default, so the width of the content is | |
| 293 // not affected. | |
| 294 scroll_view.SetVerticalScrollBar(new views::OverlayScrollBar(false)); | |
| 295 | |
| 296 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); | |
| 297 | |
| 298 const int kTallContentHeight = 1000; | |
| 299 scroll_view.SetContents( | |
| 300 new views::StaticSizedView(gfx::Size(kWidth, kTallContentHeight))); | |
| 301 | |
| 302 EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view.GetPreferredSize()); | |
| 303 | |
| 304 scroll_view.SizeToPreferredSize(); | |
| 305 scroll_view.Layout(); | |
| 306 | |
| 307 EXPECT_EQ(gfx::Size(kWidth, kTallContentHeight), | |
| 308 scroll_view.contents()->size()); | |
| 309 EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view.size()); | |
| 310 } | |
| 311 | |
| 312 // Verifies that when ClipHeightTo() produces a scrollbar, it reduces the width | |
| 313 // of the inner content of the ScrollView. | |
| 314 TEST(ScrollViewTest, ClipHeightToScrollbarUsesWidth) { | |
| 315 ScrollView scroll_view; | |
| 316 | |
| 317 scroll_view.ClipHeightTo(kMinHeight, kMaxHeight); | |
| 318 | |
| 319 // Create a view that will be much taller than it is wide. | |
| 320 scroll_view.SetContents(new views::ProportionallySizedView(1000)); | |
| 321 | |
| 322 // Without any width, it will default to 0,0 but be overridden by min height. | |
| 323 scroll_view.SizeToPreferredSize(); | |
| 324 EXPECT_EQ(gfx::Size(0, kMinHeight), scroll_view.GetPreferredSize()); | |
| 325 | |
| 326 gfx::Size new_size(kWidth, scroll_view.GetHeightForWidth(kWidth)); | |
| 327 scroll_view.SetSize(new_size); | |
| 328 scroll_view.Layout(); | |
| 329 | |
| 330 int scroll_bar_width = scroll_view.GetScrollBarWidth(); | |
| 331 int expected_width = kWidth - scroll_bar_width; | |
| 332 EXPECT_EQ(scroll_view.contents()->size().width(), expected_width); | |
| 333 EXPECT_EQ(scroll_view.contents()->size().height(), 1000 * expected_width); | |
| 334 EXPECT_EQ(gfx::Size(kWidth, kMaxHeight), scroll_view.size()); | |
| 335 } | |
| 336 | |
| 337 TEST(ScrollViewTest, CornerViewVisibility) { | |
| 338 ScrollView scroll_view; | |
| 339 View* contents = new View; | |
| 340 scroll_view.SetContents(contents); | |
| 341 scroll_view.SetBoundsRect(gfx::Rect(0, 0, 100, 100)); | |
| 342 View* corner_view = scroll_view.corner_view_; | |
| 343 | |
| 344 // Corner view should be visible when both scrollbars are visible. | |
| 345 contents->SetBounds(0, 0, 200, 200); | |
| 346 scroll_view.Layout(); | |
| 347 EXPECT_EQ(&scroll_view, corner_view->parent()); | |
| 348 EXPECT_TRUE(corner_view->visible()); | |
| 349 | |
| 350 // Corner view should be aligned to the scrollbars. | |
| 351 EXPECT_EQ(scroll_view.vertical_scroll_bar()->x(), corner_view->x()); | |
| 352 EXPECT_EQ(scroll_view.horizontal_scroll_bar()->y(), corner_view->y()); | |
| 353 EXPECT_EQ(scroll_view.GetScrollBarWidth(), corner_view->width()); | |
| 354 EXPECT_EQ(scroll_view.GetScrollBarHeight(), corner_view->height()); | |
| 355 | |
| 356 // Corner view should be removed when only the vertical scrollbar is visible. | |
| 357 contents->SetBounds(0, 0, 50, 200); | |
| 358 scroll_view.Layout(); | |
| 359 EXPECT_FALSE(corner_view->parent()); | |
| 360 | |
| 361 // ... or when only the horizontal scrollbar is visible. | |
| 362 contents->SetBounds(0, 0, 200, 50); | |
| 363 scroll_view.Layout(); | |
| 364 EXPECT_FALSE(corner_view->parent()); | |
| 365 | |
| 366 // ... or when no scrollbar is visible. | |
| 367 contents->SetBounds(0, 0, 50, 50); | |
| 368 scroll_view.Layout(); | |
| 369 EXPECT_FALSE(corner_view->parent()); | |
| 370 | |
| 371 // Corner view should reappear when both scrollbars reappear. | |
| 372 contents->SetBounds(0, 0, 200, 200); | |
| 373 scroll_view.Layout(); | |
| 374 EXPECT_EQ(&scroll_view, corner_view->parent()); | |
| 375 EXPECT_TRUE(corner_view->visible()); | |
| 376 } | |
| 377 | |
| 378 } // namespace views | |
| OLD | NEW |