Home | History | Annotate | Download | only in controls
      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