| Index: ash/common/system/tray/tray_details_view.cc
|
| diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc
|
| index c34c81bafa848cf0048dcb592ba386d6921b76bd..a0d694d490c64fb3d54594fe13dafa8b531ec709 100644
|
| --- a/ash/common/system/tray/tray_details_view.cc
|
| +++ b/ash/common/system/tray/tray_details_view.cc
|
| @@ -15,7 +15,119 @@
|
| #include "ui/views/controls/scroll_view.h"
|
| #include "ui/views/layout/box_layout.h"
|
|
|
| -namespace ash {
|
| +namespace {
|
| +
|
| +const int kHeaderRowId = 1000;
|
| +const int kHeaderRowSeparatorThickness = 1;
|
| +const SkColor kHeaderRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
|
| +
|
| +// A view that is used as ScrollView contents. It supports designating some of
|
| +// the children as sticky header rows. The sticky header rows are not scrolled
|
| +// above the top of the visible viewport and are painted above other children.
|
| +// To indicate that a child is a sticky header row use set_id(kHeaderRowId).
|
| +class ScrollContentsView : public views::View {
|
| + public:
|
| + ScrollContentsView(ash::TrayDetailsView* tray_details_view) {}
|
| + ~ScrollContentsView() override {}
|
| +
|
| + protected:
|
| + // views::View.
|
| + void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
|
| + ScrollChildren();
|
| + }
|
| +
|
| + void PaintChildren(const ui::PaintContext& context) override {
|
| + for (int i = 0, count = child_count(); i < count; ++i) {
|
| + if (child_at(i)->id() != kHeaderRowId && !child_at(i)->layer())
|
| + child_at(i)->Paint(context);
|
| + }
|
| + // Paint header rows above other children in Z-order.
|
| + for (auto& header : headers_) {
|
| + if (!header.view->layer())
|
| + header.view->Paint(context);
|
| + }
|
| + }
|
| +
|
| + void Layout() override {
|
| + views::View::Layout();
|
| + headers_.clear();
|
| + for (int i = 0, count = child_count(); i < count; ++i) {
|
| + views::View* header = child_at(i);
|
| + if (header->id() == kHeaderRowId)
|
| + headers_.push_back(Header(header));
|
| + }
|
| + ScrollChildren();
|
| + }
|
| +
|
| + void ViewHierarchyChanged(
|
| + const ViewHierarchyChangedDetails& details) override {
|
| + if (!details.is_add && details.parent == this) {
|
| + auto header = std::find(headers_.begin(), headers_.end(), details.child);
|
| + if (header != headers_.end())
|
| + headers_.erase(header);
|
| + }
|
| + }
|
| +
|
| + private:
|
| + class Header {
|
| + public:
|
| + Header(views::View* header) : view(header), offset(header->bounds().y()) {}
|
| + bool operator==(views::View* other) { return view == other; }
|
| +
|
| + views::View* view;
|
| + int offset;
|
| + };
|
| +
|
| + // Sets decorations on a header row to indicate whether it is sticky.
|
| + static void ShowHeaderSticky(views::View* header, bool show_sticky) {
|
| + if (show_sticky) {
|
| + header->SetBorder(views::Border::CreateSolidSidedBorder(
|
| + 0, 0, kHeaderRowSeparatorThickness, 0, kHeaderRowSeparatorColor));
|
| + } else {
|
| + header->SetBorder(views::Border::CreateSolidSidedBorder(
|
| + kHeaderRowSeparatorThickness, 0, 0, 0, kHeaderRowSeparatorColor));
|
| + }
|
| + }
|
| +
|
| + // Adjusts y-position of header rows allowing one or two rows to stick to the
|
| + // top of the visible viewport.
|
| + void ScrollChildren() {
|
| + const int scroll_offset = -bounds().y();
|
| + Header* previous_header = nullptr;
|
| + for (auto& header : headers_) {
|
| + gfx::Rect header_bounds = header.view->bounds();
|
| + if (scroll_offset > header.offset) {
|
| + header_bounds.set_y(scroll_offset);
|
| + header.view->SetBoundsRect(header_bounds);
|
| + ShowHeaderSticky(header.view, true);
|
| + header.view->Layout();
|
| + header.view->SchedulePaint();
|
| + if (previous_header) {
|
| + header_bounds = previous_header->view->bounds();
|
| + header_bounds.set_y(previous_header->offset);
|
| + previous_header->view->SetBoundsRect(header_bounds);
|
| + ShowHeaderSticky(previous_header->view, false);
|
| + }
|
| + previous_header = &header;
|
| + } else if (previous_header &&
|
| + header_bounds.y() < previous_header->view->bounds().bottom()) {
|
| + gfx::Rect previous_header_bounds = previous_header->view->bounds();
|
| + previous_header_bounds.set_y(header_bounds.y() -
|
| + previous_header->view->bounds().height());
|
| + previous_header->view->SetBoundsRect(previous_header_bounds);
|
| + ShowHeaderSticky(previous_header->view, false);
|
| + ShowHeaderSticky(header.view, false);
|
| + } else {
|
| + ShowHeaderSticky(header.view, false);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Header child views that stick to the top of visible viewport when scrolled.
|
| + std::vector<Header> headers_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ScrollContentsView);
|
| +};
|
|
|
| class ScrollSeparator : public views::View {
|
| public:
|
| @@ -24,17 +136,22 @@ class ScrollSeparator : public views::View {
|
| ~ScrollSeparator() override {}
|
|
|
| private:
|
| - // Overriden from views::View.
|
| + // views::View.
|
| void OnPaint(gfx::Canvas* canvas) override {
|
| - canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor);
|
| + canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1),
|
| + ash::kBorderLightColor);
|
| }
|
| gfx::Size GetPreferredSize() const override {
|
| - return gfx::Size(1, kTrayPopupScrollSeparatorHeight);
|
| + return gfx::Size(1, ash::kTrayPopupScrollSeparatorHeight);
|
| }
|
|
|
| DISALLOW_COPY_AND_ASSIGN(ScrollSeparator);
|
| };
|
|
|
| +} // namespace
|
| +
|
| +namespace ash {
|
| +
|
| class ScrollBorder : public views::Border {
|
| public:
|
| ScrollBorder() {}
|
| @@ -43,7 +160,7 @@ class ScrollBorder : public views::Border {
|
| void set_visible(bool visible) { visible_ = visible; }
|
|
|
| private:
|
| - // Overridden from views::Border.
|
| + // views::Border.
|
| void Paint(const views::View& view, gfx::Canvas* canvas) override {
|
| if (!visible_)
|
| return;
|
| @@ -55,7 +172,7 @@ class ScrollBorder : public views::Border {
|
|
|
| gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); }
|
|
|
| - bool visible_;
|
| + bool visible_ = false;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(ScrollBorder);
|
| };
|
| @@ -113,7 +230,7 @@ void TrayDetailsView::CreateTitleRow(int string_id) {
|
|
|
| void TrayDetailsView::CreateScrollableList() {
|
| DCHECK(!scroller_);
|
| - scroll_content_ = new views::View;
|
| + scroll_content_ = new ScrollContentsView(this);
|
| scroll_content_->SetLayoutManager(
|
| new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
|
| scroller_ = new FixedSizedScrollView;
|
|
|