15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/scroll_view.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 8d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "ui/events/event.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/native_theme/native_theme.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/border.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/controls/scrollbar/native_scroll_bar.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/views/widget/root_view.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace views { 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char ScrollView::kViewClassName[] = "ScrollView"; 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Subclass of ScrollView that resets the border when the theme changes. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ScrollViewWithBorder : public views::ScrollView { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScrollViewWithBorder() { 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetThemeSpecificState(); 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // View overrides; 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetThemeSpecificState(); 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void SetThemeSpecificState() { 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) set_border(Border::CreateSolidBorder( 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1, GetNativeTheme()->GetSystemColor( 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ui::NativeTheme::kColorId_UnfocusedBorderColor))); 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(ScrollViewWithBorder); 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Returns the position for the view so that it isn't scrolled off the visible 432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// region. 442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int CheckScrollBounds(int viewport_size, int content_size, int current_pos) { 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int max = std::max(content_size - viewport_size, 0); 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (current_pos < 0) 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (current_pos > max) 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return max; 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return current_pos; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Make sure the content is not scrolled out of bounds 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void CheckScrollBounds(View* viewport, View* view) { 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!view) 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int x = CheckScrollBounds(viewport->width(), view->width(), -view->x()); 592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int y = CheckScrollBounds(viewport->height(), view->height(), -view->y()); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // This is no op if bounds are the same 622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) view->SetBounds(-x, -y, view->width(), view->height()); 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Used by ScrollToPosition() to make sure the new position fits within the 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// allowed scroll range. 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int AdjustPosition(int current_position, 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int new_position, 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int content_size, 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int viewport_size) { 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (-current_position == new_position) 722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return new_position; 732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (new_position < 0) 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return 0; 752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int max_position = std::max(0, content_size - viewport_size); 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return (new_position > max_position) ? max_position : new_position; 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Viewport contains the contents View of the ScrollView. 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class ScrollView::Viewport : public View { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Viewport() {} 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual ~Viewport() {} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 87b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) virtual const char* GetClassName() const OVERRIDE { 88b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return "ScrollView::Viewport"; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) virtual void ScrollRectToVisible(const gfx::Rect& rect) OVERRIDE { 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!has_children() || !parent()) 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) View* contents = child_at(0); 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect scroll_rect(rect); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scroll_rect.Offset(-contents->x(), -contents->y()); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<ScrollView*>(parent())->ScrollContentsRegionToBeVisible( 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scroll_rect); 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) virtual void ChildPreferredSizeChanged(View* child) OVERRIDE { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parent()) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parent()->Layout(); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(Viewport); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ScrollView::ScrollView() 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) : contents_(NULL), 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_(new Viewport()), 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_(NULL), 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_viewport_(new Viewport()), 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb_(new NativeScrollBar(true)), 1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb_(new NativeScrollBar(false)), 118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) resize_corner_(NULL), 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) hide_horizontal_scrollbar_(false) { 1205e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) set_notify_enter_exit_on_child(true); 1215e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) 1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(contents_viewport_); 1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(header_viewport_); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Don't add the scrollbars as children until we discover we need them 1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // (ShowOrHideScrollBar). 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb_->SetVisible(false); 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb_->set_controller(this); 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb_->SetVisible(false); 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb_->set_controller(this); 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (resize_corner_) 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) resize_corner_->SetVisible(false); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScrollView::~ScrollView() { 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The scrollbars may not have been added, delete them to ensure they get 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // deleted. 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete horiz_sb_; 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete vert_sb_; 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resize_corner_ && !resize_corner_->parent()) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) delete resize_corner_; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ScrollView* ScrollView::CreateScrollViewWithBorder() { 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new ScrollViewWithBorder(); 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ScrollView::SetContents(View* a_view) { 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetHeaderOrContents(contents_viewport_, a_view, &contents_); 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::SetHeader(View* header) { 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SetHeaderOrContents(header_viewport_, header, &header_); 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)gfx::Rect ScrollView::GetVisibleRect() const { 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!contents_) 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Rect(); 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return gfx::Rect(-contents_->x(), -contents_->y(), 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->width(), contents_viewport_->height()); 1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ScrollView::GetScrollBarWidth() const { 1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return vert_sb_ ? vert_sb_->GetLayoutSize() : 0; 1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ScrollView::GetScrollBarHeight() const { 1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return horiz_sb_ ? horiz_sb_->GetLayoutSize() : 0; 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::SetHorizontalScrollBar(ScrollBar* horiz_sb) { 1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(horiz_sb); 1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb->SetVisible(horiz_sb_->visible()); 1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete horiz_sb_; 1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb->set_controller(this); 1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb_ = horiz_sb; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::SetVerticalScrollBar(ScrollBar* vert_sb) { 1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) DCHECK(vert_sb); 1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb->SetVisible(vert_sb_->visible()); 1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete vert_sb_; 1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb->set_controller(this); 1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb_ = vert_sb; 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ScrollView::Layout() { 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Most views will want to auto-fit the available space. Most of them want to 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // use all available width (without overflowing) and only overflow in 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // height. Examples are HistoryView, MostVisitedView, DownloadTabView, etc. 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Other views want to fit in both ways. An example is PrintView. To make both 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // happy, assume a vertical scrollbar but no horizontal scrollbar. To override 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this default behavior, the inner view has to calculate the available space, 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // used ComputeScrollBarsVisibility() to use the same calculation that is done 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // here and sets its bound to fit within. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Rect viewport_bounds = GetContentsBounds(); 1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int contents_x = viewport_bounds.x(); 2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int contents_y = viewport_bounds.y(); 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (viewport_bounds.IsEmpty()) { 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There's nothing to layout. 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const int header_height = 2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::min(viewport_bounds.height(), 2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_ ? header_->GetPreferredSize().height() : 0); 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) viewport_bounds.set_height( 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(0, viewport_bounds.height() - header_height)); 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) viewport_bounds.set_y(viewport_bounds.y() + header_height); 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // viewport_size is the total client space available. 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) gfx::Size viewport_size = viewport_bounds.size(); 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Assumes a vertical scrollbar since most of the current views are designed 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for this. 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int horiz_sb_height = GetScrollBarHeight(); 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int vert_sb_width = GetScrollBarWidth(); 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) viewport_bounds.set_width(viewport_bounds.width() - vert_sb_width); 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update the bounds right now so the inner views can fit in it. 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->SetBoundsRect(viewport_bounds); 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Give |contents_| a chance to update its bounds if it depends on the 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // viewport. 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (contents_) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_->Layout(); 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool should_layout_contents = false; 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool horiz_sb_required = false; 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool vert_sb_required = false; 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (contents_) { 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::Size content_size = contents_->size(); 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ComputeScrollBarsVisibility(viewport_size, 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_size, 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &horiz_sb_required, 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &vert_sb_required); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool resize_corner_required = resize_corner_ && horiz_sb_required && 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vert_sb_required; 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Take action. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetControlVisibility(horiz_sb_, horiz_sb_required); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetControlVisibility(vert_sb_, vert_sb_required); 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetControlVisibility(resize_corner_, resize_corner_required); 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Non-default. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (horiz_sb_required) { 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) viewport_bounds.set_height( 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::max(0, viewport_bounds.height() - horiz_sb_height)); 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_layout_contents = true; 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Default. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!vert_sb_required) { 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) viewport_bounds.set_width(viewport_bounds.width() + vert_sb_width); 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) should_layout_contents = true; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (horiz_sb_required) { 2575e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) int height_offset = horiz_sb_->GetContentOverlapSize(); 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) horiz_sb_->SetBounds(0, 2595e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) viewport_bounds.bottom() - height_offset, 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) viewport_bounds.right(), 2615e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) horiz_sb_height + height_offset); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (vert_sb_required) { 2645e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) int width_offset = vert_sb_->GetContentOverlapSize(); 2655e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) vert_sb_->SetBounds(viewport_bounds.right() - width_offset, 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 2675e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) vert_sb_width + width_offset, 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) viewport_bounds.bottom()); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (resize_corner_required) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Show the resize corner. 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) resize_corner_->SetBounds(viewport_bounds.right(), 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) viewport_bounds.bottom(), 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) vert_sb_width, 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) horiz_sb_height); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Update to the real client size with the visible scrollbars. 2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->SetBoundsRect(viewport_bounds); 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (should_layout_contents && contents_) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_->Layout(); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_viewport_->SetBounds(contents_x, contents_y, 2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) viewport_bounds.width(), header_height); 2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_) 2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_->Layout(); 2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CheckScrollBounds(header_viewport_, header_); 2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) CheckScrollBounds(contents_viewport_, contents_); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SchedulePaint(); 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateScrollBarPositions(); 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ScrollView::OnKeyPressed(const ui::KeyEvent& event) { 2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool processed = false; 2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Give vertical scrollbar priority 2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (vert_sb_->visible()) 2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) processed = vert_sb_->OnKeyPressed(event); 3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!processed && horiz_sb_->visible()) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) processed = horiz_sb_->OnKeyPressed(event); 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return processed; 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ScrollView::OnMouseWheel(const ui::MouseWheelEvent& e) { 3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool processed = false; 3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Give vertical scrollbar priority 3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (vert_sb_->visible()) 3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) processed = vert_sb_->OnMouseWheel(e); 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!processed && horiz_sb_->visible()) 3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) processed = horiz_sb_->OnMouseWheel(e); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return processed; 3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3195e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)void ScrollView::OnMouseEntered(const ui::MouseEvent& event) { 3205e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) if (horiz_sb_) 3215e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) horiz_sb_->OnMouseEnteredScrollView(event); 3225e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) if (vert_sb_) 3235e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) vert_sb_->OnMouseEnteredScrollView(event); 3245e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)} 3255e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) 3265e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)void ScrollView::OnMouseExited(const ui::MouseEvent& event) { 3275e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) if (horiz_sb_) 3285e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) horiz_sb_->OnMouseExitedScrollView(event); 3295e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) if (vert_sb_) 3305e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) vert_sb_->OnMouseExitedScrollView(event); 3315e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)} 3325e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles) 3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::OnGestureEvent(ui::GestureEvent* event) { 3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If the event happened on one of the scrollbars, then those events are 3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // sent directly to the scrollbars. Otherwise, only scroll events are sent to 3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the scrollbars. 3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool scroll_event = event->type() == ui::ET_GESTURE_SCROLL_UPDATE || 3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->type() == ui::ET_GESTURE_SCROLL_BEGIN || 3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->type() == ui::ET_GESTURE_SCROLL_END || 3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) event->type() == ui::ET_SCROLL_FLING_START; 3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (vert_sb_->visible()) { 3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (vert_sb_->bounds().Contains(event->location()) || scroll_event) 3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb_->OnGestureEvent(event); 3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!event->handled() && horiz_sb_->visible()) { 3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (horiz_sb_->bounds().Contains(event->location()) || scroll_event) 3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb_->OnGestureEvent(event); 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 352b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)const char* ScrollView::GetClassName() const { 3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return kViewClassName; 3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::ScrollToPosition(ScrollBar* source, int position) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!contents_) 3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (source == horiz_sb_ && horiz_sb_->visible()) { 3612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) position = AdjustPosition(contents_->x(), position, contents_->width(), 3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->width()); 3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (-contents_->x() == position) 3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->SetX(-position); 3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_) { 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_->SetX(-position); 3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_->SchedulePaintInRect(header_->GetVisibleBounds()); 3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (source == vert_sb_ && vert_sb_->visible()) { 3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) position = AdjustPosition(contents_->y(), position, contents_->height(), 3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->height()); 3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (-contents_->y() == position) 3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->SetY(-position); 3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_->SchedulePaintInRect(contents_->GetVisibleBounds()); 3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int ScrollView::GetScrollIncrement(ScrollBar* source, bool is_page, 3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_positive) { 3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool is_horizontal = source->IsHorizontal(); 3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int amount = 0; 3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (contents_) { 3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_page) { 3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) amount = contents_->GetPageScrollIncrement( 3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, is_horizontal, is_positive); 3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) amount = contents_->GetLineScrollIncrement( 3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) this, is_horizontal, is_positive); 3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (amount > 0) 3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return amount; 3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // No view, or the view didn't return a valid amount. 3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (is_page) { 3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return is_horizontal ? contents_viewport_->width() : 3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->height(); 3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return is_horizontal ? contents_viewport_->width() / 5 : 4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->height() / 5; 4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::SetHeaderOrContents(View* parent, 4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) View* new_view, 4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) View** member) { 4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (*member == new_view) 4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) delete *member; 4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *member = new_view; 4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (*member) 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) parent->AddChildView(*member); 4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Layout(); 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ScrollView::ScrollContentsRegionToBeVisible(const gfx::Rect& rect) { 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!contents_ || (!horiz_sb_->visible() && !vert_sb_->visible())) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out the maximums for this scroll view. 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int contents_max_x = 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(contents_viewport_->width(), contents_->width()); 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int contents_max_y = 4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) std::max(contents_viewport_->height(), contents_->height()); 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make sure x and y are within the bounds of [0,contents_max_*]. 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = std::max(0, std::min(contents_max_x, rect.x())); 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = std::max(0, std::min(contents_max_y, rect.y())); 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Figure out how far and down the rectangle will go taking width 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and height into account. This will be "clipped" by the viewport. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_x = std::min(contents_max_x, 4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) x + std::min(rect.width(), contents_viewport_->width())); 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int max_y = std::min(contents_max_y, 4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) y + std::min(rect.height(), contents_viewport_->height())); 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // See if the rect is already visible. Note the width is (max_x - x) 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and the height is (max_y - y) to take into account the clipping of 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // either viewport or the content size. 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect vis_rect = GetVisibleRect(); 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (vis_rect.Contains(gfx::Rect(x, y, max_x - x, max_y - y))) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Shift contents_'s X and Y so that the region is visible. If we 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // need to shift up or left from where we currently are then we need 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to get it so that the content appears in the upper/left 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // corner. This is done by setting the offset to -X or -Y. For down 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or right shifts we need to make sure it appears in the 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // lower/right corner. This is calculated by taking max_x or max_y 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and scaling it back by the size of the viewport. 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int new_x = 4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (vis_rect.x() > x) ? x : std::max(0, max_x - contents_viewport_->width()); 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int new_y = 4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) (vis_rect.y() > y) ? y : std::max(0, max_y - 4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) contents_viewport_->height()); 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_->SetX(-new_x); 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (header_) 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) header_->SetX(-new_x); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) contents_->SetY(-new_y); 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UpdateScrollBarPositions(); 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::ComputeScrollBarsVisibility(const gfx::Size& vp_size, 4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const gfx::Size& content_size, 4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* horiz_is_shown, 4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bool* vert_is_shown) const { 4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Try to fit both ways first, then try vertical bar only, then horizontal 4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // bar only, then defaults to both shown. 4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (content_size.width() <= vp_size.width() && 4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) content_size.height() <= vp_size.height()) { 4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *horiz_is_shown = false; 4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *vert_is_shown = false; 4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (content_size.width() <= vp_size.width() - GetScrollBarWidth()) { 4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *horiz_is_shown = false; 4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *vert_is_shown = true; 4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (content_size.height() <= vp_size.height() - GetScrollBarHeight()) { 4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *horiz_is_shown = true; 4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *vert_is_shown = false; 4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *horiz_is_shown = true; 4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *vert_is_shown = true; 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (hide_horizontal_scrollbar_) 487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) *horiz_is_shown = false; 4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Make sure that a single scrollbar is created and visible as needed 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::SetControlVisibility(View* control, bool should_show) { 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!control) 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return; 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (should_show) { 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (!control->visible()) { 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) AddChildView(control); 4972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) control->SetVisible(true); 4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) RemoveChildView(control); 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) control->SetVisible(false); 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ScrollView::UpdateScrollBarPositions() { 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!contents_) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (horiz_sb_->visible()) { 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int vw = contents_viewport_->width(); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int cw = contents_->width(); 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int origin = contents_->x(); 5132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) horiz_sb_->Update(vw, cw, -origin); 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (vert_sb_->visible()) { 5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int vh = contents_viewport_->height(); 5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int ch = contents_->height(); 5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int origin = contents_->y(); 5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) vert_sb_->Update(vh, ch, -origin); 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// VariableRowHeightScrollHelper ---------------------------------------------- 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VariableRowHeightScrollHelper::VariableRowHeightScrollHelper( 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Controller* controller) : controller_(controller) { 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VariableRowHeightScrollHelper::~VariableRowHeightScrollHelper() { 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int VariableRowHeightScrollHelper::GetPageScrollIncrement( 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScrollView* scroll_view, bool is_horizontal, bool is_positive) { 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_horizontal) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // y coordinate is most likely negative. 5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int y = abs(scroll_view->contents()->y()); 5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int vis_height = scroll_view->contents()->parent()->height(); 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_positive) { 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Align the bottom most row to the top of the view. 5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bottom = std::min(scroll_view->contents()->height() - 1, 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) y + vis_height); 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RowInfo bottom_row_info = GetRowInfo(bottom); 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If 0, ScrollView will provide a default value. 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::max(0, bottom_row_info.origin - y); 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Align the row on the previous page to to the top of the view. 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int last_page_y = y - vis_height; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RowInfo last_page_info = GetRowInfo(std::max(0, last_page_y)); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (last_page_y != last_page_info.origin) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::max(0, y - last_page_info.origin - last_page_info.height); 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::max(0, y - last_page_info.origin); 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int VariableRowHeightScrollHelper::GetLineScrollIncrement( 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScrollView* scroll_view, bool is_horizontal, bool is_positive) { 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_horizontal) 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // y coordinate is most likely negative. 5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int y = abs(scroll_view->contents()->y()); 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RowInfo row = GetRowInfo(y); 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_positive) { 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return row.height - (y - row.origin); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (y == row.origin) { 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) row = GetRowInfo(std::max(0, row.origin - 1)); 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return y - row.origin; 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return y - row.origin; 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VariableRowHeightScrollHelper::RowInfo 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) VariableRowHeightScrollHelper::GetRowInfo(int y) { 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return controller_->GetRowInfo(y); 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// FixedRowHeightScrollHelper ----------------------------------------------- 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FixedRowHeightScrollHelper::FixedRowHeightScrollHelper(int top_margin, 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int row_height) 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : VariableRowHeightScrollHelper(NULL), 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) top_margin_(top_margin), 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) row_height_(row_height) { 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GT(row_height, 0); 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)VariableRowHeightScrollHelper::RowInfo 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FixedRowHeightScrollHelper::GetRowInfo(int y) { 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (y < top_margin_) 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return RowInfo(0, top_margin_); 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return RowInfo((y - top_margin_) / row_height_ * row_height_ + top_margin_, 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) row_height_); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace views 597