Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(208)

Side by Side Diff: ash/common/system/tray/tray_details_view.cc

Issue 2453133002: [ash-md] Makes Wi-Fi header row sticky when network list is scrolled (Closed)
Patch Set: [ash-md] Makes Wi-Fi header row sticky when network list is scrolled (back to range) Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ash/common/system/tray/tray_constants.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "base/containers/adapters.h"
12 #include "ui/gfx/canvas.h" 13 #include "ui/gfx/canvas.h"
13 #include "ui/views/background.h" 14 #include "ui/views/background.h"
14 #include "ui/views/border.h" 15 #include "ui/views/border.h"
15 #include "ui/views/controls/progress_bar.h" 16 #include "ui/views/controls/progress_bar.h"
16 #include "ui/views/controls/scroll_view.h" 17 #include "ui/views/controls/scroll_view.h"
17 #include "ui/views/controls/separator.h" 18 #include "ui/views/controls/separator.h"
18 #include "ui/views/layout/box_layout.h" 19 #include "ui/views/layout/box_layout.h"
20 #include "ui/views/view_targeter.h"
21 #include "ui/views/view_targeter_delegate.h"
19 22
20 namespace ash { 23 namespace ash {
21 namespace { 24 namespace {
22 25
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 until the next one "pushes" it up and
32 // are painted above other children. To indicate that a child is a sticky header
33 // row use set_id(kHeaderRowId).
34 class ScrollContentsView : public views::View,
35 public views::ViewTargeterDelegate {
36 public:
37 ScrollContentsView() {
38 SetEventTargeter(base::MakeUnique<views::ViewTargeter>(this));
39 SetLayoutManager(
40 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
41 }
42 ~ScrollContentsView() override {}
43
44 protected:
45 // views::View:
46 void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
47 PositionHeaderRows();
48 }
49
50 void PaintChildren(const ui::PaintContext& context) override {
51 for (int i = 0; i < child_count(); ++i) {
52 if (child_at(i)->id() != kHeaderRowId && !child_at(i)->layer())
53 child_at(i)->Paint(context);
54 }
55 // Paint header rows above other children in Z-order.
56 for (auto& header : headers_) {
57 if (!header.view()->layer())
58 header.view()->Paint(context);
59 }
60 }
61
62 void Layout() override {
63 views::View::Layout();
64 headers_.clear();
65 for (int i = 0; i < child_count(); ++i) {
66 views::View* view = child_at(i);
67 if (view->id() == kHeaderRowId)
68 headers_.emplace_back(view);
69 }
70 PositionHeaderRows();
71 }
72
73 void ViewHierarchyChanged(
74 const ViewHierarchyChangedDetails& details) override {
75 if (!details.is_add && details.parent == this) {
76 headers_.erase(std::remove_if(headers_.begin(), headers_.end(),
77 [details](const Header& header) {
78 return header.view() == details.child;
79 }),
80 headers_.end());
81 }
82 }
83
84 // views::ViewTargeterDelegate:
85 View* TargetForRect(View* root, const gfx::Rect& rect) override {
86 // Give header rows first dibs on events.
87 for (auto& header : headers_) {
88 views::View* view = header.view();
89 gfx::Rect local_to_header = rect;
90 local_to_header.Offset(-view->x(), -view->y());
91 if (ViewTargeterDelegate::DoesIntersectRect(view, local_to_header))
92 return ViewTargeterDelegate::TargetForRect(view, local_to_header);
93 }
94 return ViewTargeterDelegate::TargetForRect(root, rect);
95 }
96
97 private:
98 // A structure that keeps the original offset of each header between the
99 // calls to Layout() to allow keeping track of which view should be sticky.
100 class Header {
101 public:
102 explicit Header(views::View* header)
103 : view_(header), offset_(header->y()), sticky_(true) {
104 DecorateAsSticky(false);
105 }
106
107 // Sets decorations on a header row to indicate whether it is |sticky|.
108 void DecorateAsSticky(bool sticky) {
109 if (sticky_ == sticky)
110 return;
111 sticky_ = sticky;
112 if (sticky) {
113 view_->SetBorder(views::Border::CreateSolidSidedBorder(
114 0, 0, kHeaderRowSeparatorThickness, 0, kHeaderRowSeparatorColor));
115 } else {
116 view_->SetBorder(views::Border::CreateSolidSidedBorder(
117 kHeaderRowSeparatorThickness, 0, 0, 0, kHeaderRowSeparatorColor));
118 }
119 }
120
121 const views::View* view() const { return view_; }
122 views::View* view() { return view_; }
123 int offset() const { return offset_; }
124
125 private:
126 // A header View that can be decorated as sticky.
127 views::View* view_;
128
129 // Offset from the top of ScrollContentsView to |view|'s original vertical
130 // position.
131 int offset_;
132
133 // True if the header is decorated as sticky with a shadow below.
134 bool sticky_;
135 };
136
137 // Adjusts y-position of header rows allowing one or two rows to stick to the
138 // top of the visible viewport.
139 void PositionHeaderRows() {
140 const int scroll_offset = -y();
141 Header* previous_header = nullptr;
142 for (auto& header : base::Reversed(headers_)) {
143 if (header.offset() >= scroll_offset) {
144 header.DecorateAsSticky(false);
145 previous_header = &header;
146 continue;
147 }
148 views::View* header_view = header.view();
149 if (previous_header &&
150 previous_header->view()->y() <
151 scroll_offset + header_view->height()) {
152 // Lower header displacing the header above.
153 header_view->SetY(previous_header->view()->y() - header_view->height());
154 header.DecorateAsSticky(false);
155 previous_header->DecorateAsSticky(false);
156 } else {
157 // A header becomes sticky.
158 header_view->SetY(scroll_offset);
159 header.DecorateAsSticky(true);
160 header_view->Layout();
161 header_view->SchedulePaint();
162 }
163 break;
164 }
165 }
166
167 // Header child views that stick to the top of visible viewport when scrolled.
168 std::vector<Header> headers_;
169
170 DISALLOW_COPY_AND_ASSIGN(ScrollContentsView);
171 };
172
23 // Constants for the title row in material design. 173 // Constants for the title row in material design.
24 const int kTitleRowVerticalPadding = 4; 174 const int kTitleRowVerticalPadding = 4;
25 const int kTitleRowSeparatorBorderHeight = 1; 175 const int kTitleRowSeparatorBorderHeight = 1;
26 const int kTitleRowProgressBarHeight = 2; 176 const int kTitleRowProgressBarHeight = 2;
27 // The separator's height should be same as kTitleRowProgressBarHeight, and 177 // The separator's height should be same as kTitleRowProgressBarHeight, and
28 // should not be larger than kTitleRowSeparatorBorderHeight. 178 // should not be larger than kTitleRowSeparatorBorderHeight.
29 const int kTitleRowSeparatorHeight = kTitleRowProgressBarHeight; 179 const int kTitleRowSeparatorHeight = kTitleRowProgressBarHeight;
30 const int kTitleRowPaddingTop = kTitleRowVerticalPadding; 180 const int kTitleRowPaddingTop = kTitleRowVerticalPadding;
31 const int kTitleRowPaddingBottom = 181 const int kTitleRowPaddingBottom =
32 kTitleRowVerticalPadding - kTitleRowSeparatorHeight; 182 kTitleRowVerticalPadding - kTitleRowSeparatorHeight;
(...skipping 25 matching lines...) Expand all
58 208
59 private: 209 private:
60 int GetMaxHeight(const views::View* host) const { 210 int GetMaxHeight(const views::View* host) const {
61 int max_height = 0; 211 int max_height = 0;
62 for (int i = 0; i < host->child_count(); ++i) 212 for (int i = 0; i < host->child_count(); ++i)
63 max_height = std::max(max_height, host->child_at(i)->height()); 213 max_height = std::max(max_height, host->child_at(i)->height());
64 return max_height; 214 return max_height;
65 } 215 }
66 }; 216 };
67 217
68 } // namespace
69
70 class ScrollSeparator : public views::View { 218 class ScrollSeparator : public views::View {
71 public: 219 public:
72 ScrollSeparator() {} 220 ScrollSeparator() {}
73 221
74 ~ScrollSeparator() override {} 222 ~ScrollSeparator() override {}
75 223
76 private: 224 private:
77 // Overriden from views::View. 225 // views::View:
78 void OnPaint(gfx::Canvas* canvas) override { 226 void OnPaint(gfx::Canvas* canvas) override {
79 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor); 227 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor);
80 } 228 }
81 gfx::Size GetPreferredSize() const override { 229 gfx::Size GetPreferredSize() const override {
82 return gfx::Size(1, kTrayPopupScrollSeparatorHeight); 230 return gfx::Size(1, kTrayPopupScrollSeparatorHeight);
83 } 231 }
84 232
85 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); 233 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator);
86 }; 234 };
87 235
236 } // namespace
237
88 class ScrollBorder : public views::Border { 238 class ScrollBorder : public views::Border {
89 public: 239 public:
90 ScrollBorder() {} 240 ScrollBorder() {}
91 ~ScrollBorder() override {} 241 ~ScrollBorder() override {}
92 242
93 void set_visible(bool visible) { visible_ = visible; } 243 void set_visible(bool visible) { visible_ = visible; }
94 244
95 private: 245 private:
96 // Overridden from views::Border. 246 // views::Border:
97 void Paint(const views::View& view, gfx::Canvas* canvas) override { 247 void Paint(const views::View& view, gfx::Canvas* canvas) override {
98 if (!visible_) 248 if (!visible_)
99 return; 249 return;
100 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), 250 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1),
101 kBorderLightColor); 251 kBorderLightColor);
102 } 252 }
103 253
104 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } 254 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); }
105 255
106 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } 256 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); }
107 257
108 bool visible_; 258 bool visible_ = false;
109 259
110 DISALLOW_COPY_AND_ASSIGN(ScrollBorder); 260 DISALLOW_COPY_AND_ASSIGN(ScrollBorder);
111 }; 261 };
112 262
113 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) 263 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner)
114 : owner_(owner), 264 : owner_(owner),
115 title_row_(nullptr), 265 title_row_(nullptr),
116 scroller_(nullptr), 266 scroller_(nullptr),
117 scroll_content_(nullptr), 267 scroll_content_(nullptr),
118 progress_bar_(nullptr), 268 progress_bar_(nullptr),
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 title_row_->SetBorder(views::Border::CreateEmptyBorder( 304 title_row_->SetBorder(views::Border::CreateEmptyBorder(
155 kTitleRowPaddingTop, 0, kTitleRowPaddingBottom, 0)); 305 kTitleRowPaddingTop, 0, kTitleRowPaddingBottom, 0));
156 AddChildViewAt(title_row_, 0); 306 AddChildViewAt(title_row_, 0);
157 // In material design, we use a customized bottom border which is nomally a 307 // In material design, we use a customized bottom border which is nomally a
158 // simple separator (views::Separator) but can be combined with an 308 // simple separator (views::Separator) but can be combined with an
159 // overlapping progress bar. 309 // overlapping progress bar.
160 title_row_separator_ = new views::View; 310 title_row_separator_ = new views::View;
161 title_row_separator_->SetLayoutManager(new TitleRowSeparatorLayout); 311 title_row_separator_->SetLayoutManager(new TitleRowSeparatorLayout);
162 views::Separator* separator = 312 views::Separator* separator =
163 new views::Separator(views::Separator::HORIZONTAL); 313 new views::Separator(views::Separator::HORIZONTAL);
164 separator->SetColor(ash::kTitleRowSeparatorBorderColor); 314 separator->SetColor(kTitleRowSeparatorBorderColor);
165 separator->SetPreferredSize(kTitleRowSeparatorBorderHeight); 315 separator->SetPreferredSize(kTitleRowSeparatorBorderHeight);
166 separator->SetBorder(views::Border::CreateEmptyBorder( 316 separator->SetBorder(views::Border::CreateEmptyBorder(
167 kTitleRowSeparatorHeight - kTitleRowSeparatorBorderHeight, 0, 0, 0)); 317 kTitleRowSeparatorHeight - kTitleRowSeparatorBorderHeight, 0, 0, 0));
168 title_row_separator_->AddChildView(separator); 318 title_row_separator_->AddChildView(separator);
169 AddChildViewAt(title_row_separator_, 1); 319 AddChildViewAt(title_row_separator_, 1);
170 } else { 320 } else {
171 AddChildViewAt(title_row_, child_count()); 321 AddChildViewAt(title_row_, child_count());
172 } 322 }
173 323
174 CreateExtraTitleRowButtons(); 324 CreateExtraTitleRowButtons();
175 325
176 if (MaterialDesignController::IsSystemTrayMenuMaterial()) 326 if (MaterialDesignController::IsSystemTrayMenuMaterial())
177 back_button_ = title_row_->AddBackButton(this); 327 back_button_ = title_row_->AddBackButton(this);
178 328
179 Layout(); 329 Layout();
180 } 330 }
181 331
182 void TrayDetailsView::CreateScrollableList() { 332 void TrayDetailsView::CreateScrollableList() {
183 DCHECK(!scroller_); 333 DCHECK(!scroller_);
184 scroll_content_ = new views::View; 334 scroll_content_ = new ScrollContentsView();
185 scroll_content_->SetLayoutManager(
186 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
187 scroller_ = new FixedSizedScrollView; 335 scroller_ = new FixedSizedScrollView;
188 scroller_->SetContentsView(scroll_content_); 336 scroller_->SetContentsView(scroll_content_);
189 337
190 // Note: |scroller_| takes ownership of |scroll_border_|. 338 // Note: |scroller_| takes ownership of |scroll_border_|.
191 scroll_border_ = new ScrollBorder; 339 scroll_border_ = new ScrollBorder;
192 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); 340 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_));
193 341
194 AddChildView(scroller_); 342 AddChildView(scroller_);
195 } 343 }
196 344
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 if (index < child_count() - 1 && child_at(index + 1) != title_row_) 427 if (index < child_count() - 1 && child_at(index + 1) != title_row_)
280 scroll_border_->set_visible(true); 428 scroll_border_->set_visible(true);
281 else 429 else
282 scroll_border_->set_visible(false); 430 scroll_border_->set_visible(false);
283 } 431 }
284 432
285 views::View::OnPaintBorder(canvas); 433 views::View::OnPaintBorder(canvas);
286 } 434 }
287 435
288 } // namespace ash 436 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/system/tray/tray_constants.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698