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/view_targeter.h" |
| 16 #include "ui/views/view_targeter_delegate.h" |
15 #include "ui/views/controls/progress_bar.h" | 17 #include "ui/views/controls/progress_bar.h" |
16 #include "ui/views/controls/scroll_view.h" | 18 #include "ui/views/controls/scroll_view.h" |
17 #include "ui/views/controls/separator.h" | 19 #include "ui/views/controls/separator.h" |
18 #include "ui/views/layout/box_layout.h" | 20 #include "ui/views/layout/box_layout.h" |
19 | 21 |
20 namespace ash { | 22 namespace ash { |
21 namespace { | 23 namespace { |
22 | 24 |
| 25 const int kHeaderRowId = 1000; |
| 26 const int kHeaderRowSeparatorThickness = 1; |
| 27 const SkColor kHeaderRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F); |
| 28 |
| 29 // A view that is used as ScrollView contents. It supports designating some of |
| 30 // the children as sticky header rows. The sticky header rows are not scrolled |
| 31 // above the top of the visible viewport and are painted above other children. |
| 32 // To indicate that a child is a sticky header row use set_id(kHeaderRowId). |
| 33 class ScrollContentsView : public views::View, |
| 34 public views::ViewTargeterDelegate { |
| 35 public: |
| 36 ScrollContentsView(ash::TrayDetailsView* tray_details_view) { |
| 37 SetEventTargeter(base::MakeUnique<views::ViewTargeter>(this)); |
| 38 } |
| 39 ~ScrollContentsView() override {} |
| 40 |
| 41 protected: |
| 42 // views::View. |
| 43 void OnBoundsChanged(const gfx::Rect& previous_bounds) override { |
| 44 ScrollChildren(); |
| 45 } |
| 46 |
| 47 void PaintChildren(const ui::PaintContext& context) override { |
| 48 for (int i = 0, count = child_count(); i < count; ++i) { |
| 49 if (child_at(i)->id() != kHeaderRowId && !child_at(i)->layer()) |
| 50 child_at(i)->Paint(context); |
| 51 } |
| 52 // Paint header rows above other children in Z-order. |
| 53 for (auto& header : headers_) { |
| 54 if (!header.view->layer()) |
| 55 header.view->Paint(context); |
| 56 } |
| 57 } |
| 58 |
| 59 void Layout() override { |
| 60 views::View::Layout(); |
| 61 headers_.clear(); |
| 62 for (int i = 0, count = child_count(); i < count; ++i) { |
| 63 views::View* header = child_at(i); |
| 64 if (header->id() == kHeaderRowId) |
| 65 headers_.push_back(Header(header)); |
| 66 } |
| 67 ScrollChildren(); |
| 68 } |
| 69 |
| 70 void ViewHierarchyChanged( |
| 71 const ViewHierarchyChangedDetails& details) override { |
| 72 if (!details.is_add && details.parent == this) { |
| 73 auto header = std::find(headers_.begin(), headers_.end(), details.child); |
| 74 if (header != headers_.end()) |
| 75 headers_.erase(header); |
| 76 } |
| 77 } |
| 78 |
| 79 View* TargetForRect(View* root, const gfx::Rect& rect) override { |
| 80 // Give header rows first dibs on events. |
| 81 for (auto& header : headers_) { |
| 82 views::View* view = header.view; |
| 83 gfx::Rect local_to_header = rect; |
| 84 local_to_header.Offset(-view->x(), -view->y()); |
| 85 if (ViewTargeterDelegate::DoesIntersectRect(view, local_to_header)) |
| 86 return ViewTargeterDelegate::TargetForRect(view, local_to_header); |
| 87 } |
| 88 return ViewTargeterDelegate::TargetForRect(root, rect); |
| 89 } |
| 90 |
| 91 private: |
| 92 class Header { |
| 93 public: |
| 94 Header(views::View* header) : view(header), offset(header->bounds().y()) {} |
| 95 bool operator==(views::View* other) { return view == other; } |
| 96 |
| 97 views::View* view; |
| 98 int offset; |
| 99 }; |
| 100 |
| 101 // Sets decorations on a header row to indicate whether it is sticky. |
| 102 static void ShowHeaderSticky(views::View* header, bool show_sticky) { |
| 103 if (show_sticky) { |
| 104 header->SetBorder(views::Border::CreateSolidSidedBorder( |
| 105 0, 0, kHeaderRowSeparatorThickness, 0, kHeaderRowSeparatorColor)); |
| 106 } else { |
| 107 header->SetBorder(views::Border::CreateSolidSidedBorder( |
| 108 kHeaderRowSeparatorThickness, 0, 0, 0, kHeaderRowSeparatorColor)); |
| 109 } |
| 110 } |
| 111 |
| 112 // Adjusts y-position of header rows allowing one or two rows to stick to the |
| 113 // top of the visible viewport. |
| 114 void ScrollChildren() { |
| 115 const int scroll_offset = -bounds().y(); |
| 116 Header* previous_header = nullptr; |
| 117 for (auto& header : headers_) { |
| 118 gfx::Rect header_bounds = header.view->bounds(); |
| 119 if (scroll_offset > header.offset) { |
| 120 header_bounds.set_y(scroll_offset); |
| 121 header.view->SetBoundsRect(header_bounds); |
| 122 ShowHeaderSticky(header.view, true); |
| 123 header.view->Layout(); |
| 124 header.view->SchedulePaint(); |
| 125 if (previous_header) { |
| 126 header_bounds = previous_header->view->bounds(); |
| 127 header_bounds.set_y(previous_header->offset); |
| 128 previous_header->view->SetBoundsRect(header_bounds); |
| 129 ShowHeaderSticky(previous_header->view, false); |
| 130 } |
| 131 previous_header = &header; |
| 132 } else if (previous_header && |
| 133 header_bounds.y() < previous_header->view->bounds().bottom()) { |
| 134 gfx::Rect previous_header_bounds = previous_header->view->bounds(); |
| 135 previous_header_bounds.set_y(header_bounds.y() - |
| 136 previous_header->view->bounds().height()); |
| 137 previous_header->view->SetBoundsRect(previous_header_bounds); |
| 138 ShowHeaderSticky(previous_header->view, false); |
| 139 ShowHeaderSticky(header.view, false); |
| 140 } else { |
| 141 ShowHeaderSticky(header.view, false); |
| 142 } |
| 143 } |
| 144 } |
| 145 |
| 146 // Header child views that stick to the top of visible viewport when scrolled. |
| 147 std::vector<Header> headers_; |
| 148 |
| 149 DISALLOW_COPY_AND_ASSIGN(ScrollContentsView); |
| 150 }; |
| 151 |
23 // Constants for the title row in material design. | 152 // Constants for the title row in material design. |
24 const int kTitleRowVerticalPadding = 4; | 153 const int kTitleRowVerticalPadding = 4; |
25 const int kTitleRowSeparatorBorderHeight = 1; | 154 const int kTitleRowSeparatorBorderHeight = 1; |
26 const int kTitleRowProgressBarHeight = 2; | 155 const int kTitleRowProgressBarHeight = 2; |
27 // The separator's height should be same as kTitleRowProgressBarHeight, and | 156 // The separator's height should be same as kTitleRowProgressBarHeight, and |
28 // should not be larger than kTitleRowSeparatorBorderHeight. | 157 // should not be larger than kTitleRowSeparatorBorderHeight. |
29 const int kTitleRowSeparatorHeight = kTitleRowProgressBarHeight; | 158 const int kTitleRowSeparatorHeight = kTitleRowProgressBarHeight; |
30 const int kTitleRowPaddingTop = kTitleRowVerticalPadding; | 159 const int kTitleRowPaddingTop = kTitleRowVerticalPadding; |
31 const int kTitleRowPaddingBottom = | 160 const int kTitleRowPaddingBottom = |
32 kTitleRowVerticalPadding - kTitleRowSeparatorHeight; | 161 kTitleRowVerticalPadding - kTitleRowSeparatorHeight; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 | 196 |
68 } // namespace | 197 } // namespace |
69 | 198 |
70 class ScrollSeparator : public views::View { | 199 class ScrollSeparator : public views::View { |
71 public: | 200 public: |
72 ScrollSeparator() {} | 201 ScrollSeparator() {} |
73 | 202 |
74 ~ScrollSeparator() override {} | 203 ~ScrollSeparator() override {} |
75 | 204 |
76 private: | 205 private: |
77 // Overriden from views::View. | 206 // views::View. |
78 void OnPaint(gfx::Canvas* canvas) override { | 207 void OnPaint(gfx::Canvas* canvas) override { |
79 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor); | 208 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), |
| 209 ash::kBorderLightColor); |
80 } | 210 } |
81 gfx::Size GetPreferredSize() const override { | 211 gfx::Size GetPreferredSize() const override { |
82 return gfx::Size(1, kTrayPopupScrollSeparatorHeight); | 212 return gfx::Size(1, ash::kTrayPopupScrollSeparatorHeight); |
83 } | 213 } |
84 | 214 |
85 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); | 215 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); |
86 }; | 216 }; |
87 | 217 |
| 218 } // namespace |
| 219 |
| 220 namespace ash { |
| 221 |
88 class ScrollBorder : public views::Border { | 222 class ScrollBorder : public views::Border { |
89 public: | 223 public: |
90 ScrollBorder() {} | 224 ScrollBorder() {} |
91 ~ScrollBorder() override {} | 225 ~ScrollBorder() override {} |
92 | 226 |
93 void set_visible(bool visible) { visible_ = visible; } | 227 void set_visible(bool visible) { visible_ = visible; } |
94 | 228 |
95 private: | 229 private: |
96 // Overridden from views::Border. | 230 // views::Border. |
97 void Paint(const views::View& view, gfx::Canvas* canvas) override { | 231 void Paint(const views::View& view, gfx::Canvas* canvas) override { |
98 if (!visible_) | 232 if (!visible_) |
99 return; | 233 return; |
100 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), | 234 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), |
101 kBorderLightColor); | 235 kBorderLightColor); |
102 } | 236 } |
103 | 237 |
104 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } | 238 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } |
105 | 239 |
106 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } | 240 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } |
107 | 241 |
108 bool visible_; | 242 bool visible_ = false; |
109 | 243 |
110 DISALLOW_COPY_AND_ASSIGN(ScrollBorder); | 244 DISALLOW_COPY_AND_ASSIGN(ScrollBorder); |
111 }; | 245 }; |
112 | 246 |
113 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) | 247 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) |
114 : owner_(owner), | 248 : owner_(owner), |
115 title_row_(nullptr), | 249 title_row_(nullptr), |
116 scroller_(nullptr), | 250 scroller_(nullptr), |
117 scroll_content_(nullptr), | 251 scroll_content_(nullptr), |
118 progress_bar_(nullptr), | 252 progress_bar_(nullptr), |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 CreateExtraTitleRowButtons(); | 308 CreateExtraTitleRowButtons(); |
175 | 309 |
176 if (MaterialDesignController::IsSystemTrayMenuMaterial()) | 310 if (MaterialDesignController::IsSystemTrayMenuMaterial()) |
177 back_button_ = title_row_->AddBackButton(this); | 311 back_button_ = title_row_->AddBackButton(this); |
178 | 312 |
179 Layout(); | 313 Layout(); |
180 } | 314 } |
181 | 315 |
182 void TrayDetailsView::CreateScrollableList() { | 316 void TrayDetailsView::CreateScrollableList() { |
183 DCHECK(!scroller_); | 317 DCHECK(!scroller_); |
184 scroll_content_ = new views::View; | 318 scroll_content_ = new ScrollContentsView(this); |
185 scroll_content_->SetLayoutManager( | 319 scroll_content_->SetLayoutManager( |
186 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); | 320 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1)); |
187 scroller_ = new FixedSizedScrollView; | 321 scroller_ = new FixedSizedScrollView; |
188 scroller_->SetContentsView(scroll_content_); | 322 scroller_->SetContentsView(scroll_content_); |
189 | 323 |
190 // Note: |scroller_| takes ownership of |scroll_border_|. | 324 // Note: |scroller_| takes ownership of |scroll_border_|. |
191 scroll_border_ = new ScrollBorder; | 325 scroll_border_ = new ScrollBorder; |
192 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); | 326 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); |
193 | 327 |
194 AddChildView(scroller_); | 328 AddChildView(scroller_); |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
279 if (index < child_count() - 1 && child_at(index + 1) != title_row_) | 413 if (index < child_count() - 1 && child_at(index + 1) != title_row_) |
280 scroll_border_->set_visible(true); | 414 scroll_border_->set_visible(true); |
281 else | 415 else |
282 scroll_border_->set_visible(false); | 416 scroll_border_->set_visible(false); |
283 } | 417 } |
284 | 418 |
285 views::View::OnPaintBorder(canvas); | 419 views::View::OnPaintBorder(canvas); |
286 } | 420 } |
287 | 421 |
288 } // namespace ash | 422 } // namespace ash |
OLD | NEW |