OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/common/system/tray/tray_details_view.h" | 5 #include "ash/common/system/tray/tray_details_view.h" |
6 | 6 |
7 #include "ash/common/material_design/material_design_controller.h" | 7 #include "ash/common/material_design/material_design_controller.h" |
8 #include "ash/common/system/tray/fixed_sized_scroll_view.h" | 8 #include "ash/common/system/tray/fixed_sized_scroll_view.h" |
9 #include "ash/common/system/tray/system_tray.h" | 9 #include "ash/common/system/tray/system_tray.h" |
10 #include "ash/common/system/tray/system_tray_item.h" | 10 #include "ash/common/system/tray/system_tray_item.h" |
11 #include "ash/common/system/tray/tray_constants.h" | 11 #include "ash/common/system/tray/tray_constants.h" |
12 #include "ui/gfx/canvas.h" | 12 #include "ui/gfx/canvas.h" |
13 #include "ui/views/background.h" | 13 #include "ui/views/background.h" |
14 #include "ui/views/border.h" | 14 #include "ui/views/border.h" |
15 #include "ui/views/controls/scroll_view.h" | 15 #include "ui/views/controls/scroll_view.h" |
16 #include "ui/views/layout/box_layout.h" | 16 #include "ui/views/layout/box_layout.h" |
17 | 17 |
18 namespace ash { | 18 namespace { |
| 19 |
| 20 const int kHeaderRowId = 1000; |
| 21 const int kHeaderRowSeparatorThickness = 1; |
| 22 const SkColor kHeaderRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F); |
| 23 |
| 24 // A view that is used as ScrollView contents. It supports designating some of |
| 25 // the children as sticky header rows. The sticky header rows are not scrolled |
| 26 // above the top of the visible viewport and are painted above other children. |
| 27 // To indicate that a child is a sticky header row use set_id(kHeaderRowId). |
| 28 class ScrollContentsView : public views::View { |
| 29 public: |
| 30 ScrollContentsView(ash::TrayDetailsView* tray_details_view) {} |
| 31 ~ScrollContentsView() override {} |
| 32 |
| 33 protected: |
| 34 // views::View. |
| 35 void OnBoundsChanged(const gfx::Rect& previous_bounds) override { |
| 36 ScrollChildren(); |
| 37 } |
| 38 |
| 39 void PaintChildren(const ui::PaintContext& context) override { |
| 40 for (int i = 0, count = child_count(); i < count; ++i) { |
| 41 if (child_at(i)->id() != kHeaderRowId && !child_at(i)->layer()) |
| 42 child_at(i)->Paint(context); |
| 43 } |
| 44 // Paint header rows above other children in Z-order. |
| 45 for (auto& header : headers_) { |
| 46 if (!header.view->layer()) |
| 47 header.view->Paint(context); |
| 48 } |
| 49 } |
| 50 |
| 51 void Layout() override { |
| 52 views::View::Layout(); |
| 53 headers_.clear(); |
| 54 for (int i = 0, count = child_count(); i < count; ++i) { |
| 55 views::View* header = child_at(i); |
| 56 if (header->id() == kHeaderRowId) |
| 57 headers_.push_back(Header(header)); |
| 58 } |
| 59 ScrollChildren(); |
| 60 } |
| 61 |
| 62 void ViewHierarchyChanged( |
| 63 const ViewHierarchyChangedDetails& details) override { |
| 64 if (!details.is_add && details.parent == this) { |
| 65 auto header = std::find(headers_.begin(), headers_.end(), details.child); |
| 66 if (header != headers_.end()) |
| 67 headers_.erase(header); |
| 68 } |
| 69 } |
| 70 |
| 71 private: |
| 72 class Header { |
| 73 public: |
| 74 Header(views::View* header) : view(header), offset(header->bounds().y()) {} |
| 75 bool operator==(views::View* other) { return view == other; } |
| 76 |
| 77 views::View* view; |
| 78 int offset; |
| 79 }; |
| 80 |
| 81 // Sets decorations on a header row to indicate whether it is sticky. |
| 82 static void ShowHeaderSticky(views::View* header, bool show_sticky) { |
| 83 if (show_sticky) { |
| 84 header->SetBorder(views::Border::CreateSolidSidedBorder( |
| 85 0, 0, kHeaderRowSeparatorThickness, 0, kHeaderRowSeparatorColor)); |
| 86 } else { |
| 87 header->SetBorder(views::Border::CreateSolidSidedBorder( |
| 88 kHeaderRowSeparatorThickness, 0, 0, 0, kHeaderRowSeparatorColor)); |
| 89 } |
| 90 } |
| 91 |
| 92 // Adjusts y-position of header rows allowing one or two rows to stick to the |
| 93 // top of the visible viewport. |
| 94 void ScrollChildren() { |
| 95 const int scroll_offset = -bounds().y(); |
| 96 Header* previous_header = nullptr; |
| 97 for (auto& header : headers_) { |
| 98 gfx::Rect header_bounds = header.view->bounds(); |
| 99 if (scroll_offset > header.offset) { |
| 100 header_bounds.set_y(scroll_offset); |
| 101 header.view->SetBoundsRect(header_bounds); |
| 102 ShowHeaderSticky(header.view, true); |
| 103 header.view->Layout(); |
| 104 header.view->SchedulePaint(); |
| 105 if (previous_header) { |
| 106 header_bounds = previous_header->view->bounds(); |
| 107 header_bounds.set_y(previous_header->offset); |
| 108 previous_header->view->SetBoundsRect(header_bounds); |
| 109 ShowHeaderSticky(previous_header->view, false); |
| 110 } |
| 111 previous_header = &header; |
| 112 } else if (previous_header && |
| 113 header_bounds.y() < previous_header->view->bounds().bottom()) { |
| 114 gfx::Rect previous_header_bounds = previous_header->view->bounds(); |
| 115 previous_header_bounds.set_y(header_bounds.y() - |
| 116 previous_header->view->bounds().height()); |
| 117 previous_header->view->SetBoundsRect(previous_header_bounds); |
| 118 ShowHeaderSticky(previous_header->view, false); |
| 119 ShowHeaderSticky(header.view, false); |
| 120 } else { |
| 121 ShowHeaderSticky(header.view, false); |
| 122 } |
| 123 } |
| 124 } |
| 125 |
| 126 // Header child views that stick to the top of visible viewport when scrolled. |
| 127 std::vector<Header> headers_; |
| 128 |
| 129 DISALLOW_COPY_AND_ASSIGN(ScrollContentsView); |
| 130 }; |
19 | 131 |
20 class ScrollSeparator : public views::View { | 132 class ScrollSeparator : public views::View { |
21 public: | 133 public: |
22 ScrollSeparator() {} | 134 ScrollSeparator() {} |
23 | 135 |
24 ~ScrollSeparator() override {} | 136 ~ScrollSeparator() override {} |
25 | 137 |
26 private: | 138 private: |
27 // Overriden from views::View. | 139 // views::View. |
28 void OnPaint(gfx::Canvas* canvas) override { | 140 void OnPaint(gfx::Canvas* canvas) override { |
29 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor); | 141 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), |
| 142 ash::kBorderLightColor); |
30 } | 143 } |
31 gfx::Size GetPreferredSize() const override { | 144 gfx::Size GetPreferredSize() const override { |
32 return gfx::Size(1, kTrayPopupScrollSeparatorHeight); | 145 return gfx::Size(1, ash::kTrayPopupScrollSeparatorHeight); |
33 } | 146 } |
34 | 147 |
35 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); | 148 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); |
36 }; | 149 }; |
37 | 150 |
| 151 } // namespace |
| 152 |
| 153 namespace ash { |
| 154 |
38 class ScrollBorder : public views::Border { | 155 class ScrollBorder : public views::Border { |
39 public: | 156 public: |
40 ScrollBorder() {} | 157 ScrollBorder() {} |
41 ~ScrollBorder() override {} | 158 ~ScrollBorder() override {} |
42 | 159 |
43 void set_visible(bool visible) { visible_ = visible; } | 160 void set_visible(bool visible) { visible_ = visible; } |
44 | 161 |
45 private: | 162 private: |
46 // Overridden from views::Border. | 163 // views::Border. |
47 void Paint(const views::View& view, gfx::Canvas* canvas) override { | 164 void Paint(const views::View& view, gfx::Canvas* canvas) override { |
48 if (!visible_) | 165 if (!visible_) |
49 return; | 166 return; |
50 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), | 167 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), |
51 kBorderLightColor); | 168 kBorderLightColor); |
52 } | 169 } |
53 | 170 |
54 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } | 171 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } |
55 | 172 |
56 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } | 173 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } |
57 | 174 |
58 bool visible_; | 175 bool visible_ = false; |
59 | 176 |
60 DISALLOW_COPY_AND_ASSIGN(ScrollBorder); | 177 DISALLOW_COPY_AND_ASSIGN(ScrollBorder); |
61 }; | 178 }; |
62 | 179 |
63 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) | 180 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) |
64 : owner_(owner), | 181 : owner_(owner), |
65 title_row_(nullptr), | 182 title_row_(nullptr), |
66 scroller_(nullptr), | 183 scroller_(nullptr), |
67 scroll_content_(nullptr), | 184 scroll_content_(nullptr), |
68 scroll_border_(nullptr), | 185 scroll_border_(nullptr), |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
106 CreateExtraTitleRowButtons(); | 223 CreateExtraTitleRowButtons(); |
107 | 224 |
108 if (MaterialDesignController::IsSystemTrayMenuMaterial()) | 225 if (MaterialDesignController::IsSystemTrayMenuMaterial()) |
109 back_button_ = title_row_->AddBackButton(this); | 226 back_button_ = title_row_->AddBackButton(this); |
110 | 227 |
111 Layout(); | 228 Layout(); |
112 } | 229 } |
113 | 230 |
114 void TrayDetailsView::CreateScrollableList() { | 231 void TrayDetailsView::CreateScrollableList() { |
115 DCHECK(!scroller_); | 232 DCHECK(!scroller_); |
116 scroll_content_ = new views::View; | 233 scroll_content_ = new ScrollContentsView(this); |
117 scroll_content_->SetLayoutManager( | 234 scroll_content_->SetLayoutManager( |
118 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); | 235 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); |
119 scroller_ = new FixedSizedScrollView; | 236 scroller_ = new FixedSizedScrollView; |
120 scroller_->SetContentsView(scroll_content_); | 237 scroller_->SetContentsView(scroll_content_); |
121 | 238 |
122 // Note: |scroller_| takes ownership of |scroll_border_|. | 239 // Note: |scroller_| takes ownership of |scroll_border_|. |
123 scroll_border_ = new ScrollBorder; | 240 scroll_border_ = new ScrollBorder; |
124 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); | 241 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); |
125 | 242 |
126 AddChildView(scroller_); | 243 AddChildView(scroller_); |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 if (index < child_count() - 1 && child_at(index + 1) != title_row_) | 318 if (index < child_count() - 1 && child_at(index + 1) != title_row_) |
202 scroll_border_->set_visible(true); | 319 scroll_border_->set_visible(true); |
203 else | 320 else |
204 scroll_border_->set_visible(false); | 321 scroll_border_->set_visible(false); |
205 } | 322 } |
206 | 323 |
207 views::View::OnPaintBorder(canvas); | 324 views::View::OnPaintBorder(canvas); |
208 } | 325 } |
209 | 326 |
210 } // namespace ash | 327 } // namespace ash |
OLD | NEW |