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

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 (nits) 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 "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/progress_bar.h" 15 #include "ui/views/controls/progress_bar.h"
16 #include "ui/views/controls/scroll_view.h" 16 #include "ui/views/controls/scroll_view.h"
17 #include "ui/views/controls/separator.h" 17 #include "ui/views/controls/separator.h"
18 #include "ui/views/layout/box_layout.h" 18 #include "ui/views/layout/box_layout.h"
19 #include "ui/views/view_targeter.h"
20 #include "ui/views/view_targeter_delegate.h"
19 21
20 namespace ash { 22 namespace ash {
21 namespace { 23 namespace {
22 24
25 const int kHeaderRowSeparatorThickness = 1;
26 const SkColor kHeaderRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
27
28 // A view that is used as ScrollView contents. It supports designating some of
29 // the children as sticky header rows. The sticky header rows are not scrolled
30 // above the top of the visible viewport until the next one "pushes" it up and
31 // are painted above other children. To indicate that a child is a sticky header
32 // row use set_id(kHeaderRowId).
33 class ScrollContentsView : public views::View,
34 public views::ViewTargeterDelegate {
35 public:
36 ScrollContentsView() {
37 SetEventTargeter(base::MakeUnique<views::ViewTargeter>(this));
38 SetLayoutManager(
39 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
40 }
41 ~ScrollContentsView() override {}
42
43 protected:
44 // views::View:
45 void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
46 PositionHeaderRows();
47 }
48
49 void PaintChildren(const ui::PaintContext& context) override {
50 for (int i = 0; i < child_count(); ++i) {
51 if (child_at(i)->id() != kHeaderRowId && !child_at(i)->layer())
52 child_at(i)->Paint(context);
53 }
54 // Paint header rows above other children in Z-order.
55 for (auto& header : headers_) {
56 if (!header.view()->layer())
57 header.view()->Paint(context);
58 }
59 }
60
61 void Layout() override {
62 views::View::Layout();
63 headers_.clear();
64 for (int i = 0; i < child_count(); ++i) {
65 views::View* view = child_at(i);
66 if (view->id() == kHeaderRowId)
67 headers_.push_back(Header(view));
68 }
69 PositionHeaderRows();
70 }
71
72 void ViewHierarchyChanged(
73 const ViewHierarchyChangedDetails& details) override {
74 if (!details.is_add && details.parent == this) {
75 headers_.erase(std::remove_if(headers_.begin(), headers_.end(),
76 [details](const Header& header) {
77 return header.view() == details.child;
78 }),
79 headers_.end());
sadrul 2016/11/04 15:03:03 There should only be one header that matches the c
varkha 2016/11/04 18:18:49 Done.
varkha 2016/11/07 03:27:45 Looked into this some more. While you are right th
80 }
81 }
82
83 View* TargetForRect(View* root, const gfx::Rect& rect) override {
sadrul 2016/11/04 15:03:03 // views::ViewTargeterDelegate:
varkha 2016/11/04 18:18:49 Done.
84 // Give header rows first dibs on events.
85 for (auto& header : headers_) {
86 views::View* view = header.view();
87 gfx::Rect local_to_header = rect;
88 local_to_header.Offset(-view->x(), -view->y());
89 if (ViewTargeterDelegate::DoesIntersectRect(view, local_to_header))
90 return ViewTargeterDelegate::TargetForRect(view, local_to_header);
91 }
92 return ViewTargeterDelegate::TargetForRect(root, rect);
93 }
94
95 private:
96 // A structure that keeps the original offset of each header between the
97 // calls to Layout() to allow keeping track of which view should be sticky.
98 class Header {
99 public:
100 Header(views::View* header)
sadrul 2016/11/04 15:03:03 explicit
varkha 2016/11/04 18:18:49 Done.
101 : view_(header), offset_(header->y()), sticky_(true) {
102 DecorateAsSticky(false);
103 }
104
105 // Sets decorations on a header row to indicate whether it is |sticky|.
106 void DecorateAsSticky(bool sticky) {
107 if (sticky_ == sticky)
108 return;
109 sticky_ = sticky;
110 if (sticky) {
111 view_->SetBorder(views::Border::CreateSolidSidedBorder(
112 0, 0, kHeaderRowSeparatorThickness, 0, kHeaderRowSeparatorColor));
113 } else {
114 view_->SetBorder(views::Border::CreateSolidSidedBorder(
115 kHeaderRowSeparatorThickness, 0, 0, 0, kHeaderRowSeparatorColor));
116 }
117 }
118
119 const views::View* view() const { return view_; }
120 views::View* view() {
121 return const_cast<views::View*>(const_cast<const Header*>(this)->view());
Evan Stade 2016/11/04 15:53:46 p.s. this seems crazily verbose instead of just 'r
varkha 2016/11/04 18:18:49 Done.
122 }
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_;
sadrul 2016/11/04 15:03:03 DISALLOW_COPY_AND_ASSIGN
varkha 2016/11/04 18:18:49 This structure is used in a value array so I think
Evan Stade 2016/11/04 19:18:45 So use emplace_back instead of push_back?
varkha 2016/11/07 03:27:45 I will use emplace_back() but that still relies on
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 auto previous_header = headers_.rend();
142 for (auto header = headers_.rbegin(); header != headers_.rend(); ++header) {
sadrul 2016/11/04 15:03:03 for (auto& header : base::Reversed(headers_)) {
varkha 2016/11/04 18:18:49 Done.
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 != headers_.rend() &&
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