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

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 (comments) 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') | chromeos/dbus/fake_shill_manager_client.cc » ('j') | 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());
80 }
81 }
82
83 View* TargetForRect(View* root, const gfx::Rect& rect) override {
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 ofwhich view should be sticky.
Evan Stade 2016/11/03 19:24:31 nit: of which
varkha 2016/11/03 21:29:30 Done.
98 class Header {
99 public:
100 Header(views::View* header)
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_; }
Evan Stade 2016/11/03 19:24:31 what do you need this version for?
varkha 2016/11/03 21:29:30 Line 77 uses it (to keep the iterator const). Line
120 views::View* view() {
121 return const_cast<views::View*>(const_cast<const Header*>(this)->view());
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_;
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) {
143 views::View* header_view = header->view();
Evan Stade 2016/11/03 19:24:31 nit: declare in the tightest scope it's needed
varkha 2016/11/03 21:29:30 Done.
144 if (header->offset() < scroll_offset) {
145 if (previous_header != headers_.rend() &&
146 previous_header->view()->y() <
147 scroll_offset + header_view->height()) {
148 // Lower header displacing the header above.
149 header_view->SetY(previous_header->view()->y() -
150 header_view->height());
151 header->DecorateAsSticky(false);
152 previous_header->DecorateAsSticky(false);
153 } else {
154 // A header becomes sticky.
155 header_view->SetY(scroll_offset);
156 header->DecorateAsSticky(true);
157 header_view->Layout();
158 header_view->SchedulePaint();
159 }
160 break;
161 } else {
Evan Stade 2016/11/03 19:24:32 no else after break (I would actually invert the c
varkha 2016/11/03 21:29:30 Done.
162 header->DecorateAsSticky(false);
163 previous_header = header;
164 }
165 }
166 }
167
168 // Header child views that stick to the top of visible viewport when scrolled.
169 std::vector<Header> headers_;
170
171 DISALLOW_COPY_AND_ASSIGN(ScrollContentsView);
172 };
173
23 // Constants for the title row in material design. 174 // Constants for the title row in material design.
24 const int kTitleRowVerticalPadding = 4; 175 const int kTitleRowVerticalPadding = 4;
25 const int kTitleRowSeparatorBorderHeight = 1; 176 const int kTitleRowSeparatorBorderHeight = 1;
26 const int kTitleRowProgressBarHeight = 2; 177 const int kTitleRowProgressBarHeight = 2;
27 // The separator's height should be same as kTitleRowProgressBarHeight, and 178 // The separator's height should be same as kTitleRowProgressBarHeight, and
28 // should not be larger than kTitleRowSeparatorBorderHeight. 179 // should not be larger than kTitleRowSeparatorBorderHeight.
29 const int kTitleRowSeparatorHeight = kTitleRowProgressBarHeight; 180 const int kTitleRowSeparatorHeight = kTitleRowProgressBarHeight;
30 const int kTitleRowPaddingTop = kTitleRowVerticalPadding; 181 const int kTitleRowPaddingTop = kTitleRowVerticalPadding;
31 const int kTitleRowPaddingBottom = 182 const int kTitleRowPaddingBottom =
32 kTitleRowVerticalPadding - kTitleRowSeparatorHeight; 183 kTitleRowVerticalPadding - kTitleRowSeparatorHeight;
(...skipping 25 matching lines...) Expand all
58 209
59 private: 210 private:
60 int GetMaxHeight(const views::View* host) const { 211 int GetMaxHeight(const views::View* host) const {
61 int max_height = 0; 212 int max_height = 0;
62 for (int i = 0; i < host->child_count(); ++i) 213 for (int i = 0; i < host->child_count(); ++i)
63 max_height = std::max(max_height, host->child_at(i)->height()); 214 max_height = std::max(max_height, host->child_at(i)->height());
64 return max_height; 215 return max_height;
65 } 216 }
66 }; 217 };
67 218
68 } // namespace
69
70 class ScrollSeparator : public views::View { 219 class ScrollSeparator : public views::View {
71 public: 220 public:
72 ScrollSeparator() {} 221 ScrollSeparator() {}
73 222
74 ~ScrollSeparator() override {} 223 ~ScrollSeparator() override {}
75 224
76 private: 225 private:
77 // Overriden from views::View. 226 // views::View:
78 void OnPaint(gfx::Canvas* canvas) override { 227 void OnPaint(gfx::Canvas* canvas) override {
79 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor); 228 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor);
80 } 229 }
81 gfx::Size GetPreferredSize() const override { 230 gfx::Size GetPreferredSize() const override {
82 return gfx::Size(1, kTrayPopupScrollSeparatorHeight); 231 return gfx::Size(1, kTrayPopupScrollSeparatorHeight);
83 } 232 }
84 233
85 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator); 234 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator);
86 }; 235 };
87 236
237 } // namespace
238
88 class ScrollBorder : public views::Border { 239 class ScrollBorder : public views::Border {
89 public: 240 public:
90 ScrollBorder() {} 241 ScrollBorder() {}
91 ~ScrollBorder() override {} 242 ~ScrollBorder() override {}
92 243
93 void set_visible(bool visible) { visible_ = visible; } 244 void set_visible(bool visible) { visible_ = visible; }
94 245
95 private: 246 private:
96 // Overridden from views::Border. 247 // views::Border:
97 void Paint(const views::View& view, gfx::Canvas* canvas) override { 248 void Paint(const views::View& view, gfx::Canvas* canvas) override {
98 if (!visible_) 249 if (!visible_)
99 return; 250 return;
100 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1), 251 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1),
101 kBorderLightColor); 252 kBorderLightColor);
102 } 253 }
103 254
104 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); } 255 gfx::Insets GetInsets() const override { return gfx::Insets(0, 0, 1, 0); }
105 256
106 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); } 257 gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); }
107 258
108 bool visible_; 259 bool visible_ = false;
109 260
110 DISALLOW_COPY_AND_ASSIGN(ScrollBorder); 261 DISALLOW_COPY_AND_ASSIGN(ScrollBorder);
111 }; 262 };
112 263
113 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner) 264 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner)
114 : owner_(owner), 265 : owner_(owner),
115 title_row_(nullptr), 266 title_row_(nullptr),
116 scroller_(nullptr), 267 scroller_(nullptr),
117 scroll_content_(nullptr), 268 scroll_content_(nullptr),
118 progress_bar_(nullptr), 269 progress_bar_(nullptr),
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 title_row_->SetBorder(views::Border::CreateEmptyBorder( 305 title_row_->SetBorder(views::Border::CreateEmptyBorder(
155 kTitleRowPaddingTop, 0, kTitleRowPaddingBottom, 0)); 306 kTitleRowPaddingTop, 0, kTitleRowPaddingBottom, 0));
156 AddChildViewAt(title_row_, 0); 307 AddChildViewAt(title_row_, 0);
157 // In material design, we use a customized bottom border which is nomally a 308 // In material design, we use a customized bottom border which is nomally a
158 // simple separator (views::Separator) but can be combined with an 309 // simple separator (views::Separator) but can be combined with an
159 // overlapping progress bar. 310 // overlapping progress bar.
160 title_row_separator_ = new views::View; 311 title_row_separator_ = new views::View;
161 title_row_separator_->SetLayoutManager(new TitleRowSeparatorLayout); 312 title_row_separator_->SetLayoutManager(new TitleRowSeparatorLayout);
162 views::Separator* separator = 313 views::Separator* separator =
163 new views::Separator(views::Separator::HORIZONTAL); 314 new views::Separator(views::Separator::HORIZONTAL);
164 separator->SetColor(ash::kTitleRowSeparatorBorderColor); 315 separator->SetColor(kTitleRowSeparatorBorderColor);
165 separator->SetPreferredSize(kTitleRowSeparatorBorderHeight); 316 separator->SetPreferredSize(kTitleRowSeparatorBorderHeight);
166 separator->SetBorder(views::Border::CreateEmptyBorder( 317 separator->SetBorder(views::Border::CreateEmptyBorder(
167 kTitleRowSeparatorHeight - kTitleRowSeparatorBorderHeight, 0, 0, 0)); 318 kTitleRowSeparatorHeight - kTitleRowSeparatorBorderHeight, 0, 0, 0));
168 title_row_separator_->AddChildView(separator); 319 title_row_separator_->AddChildView(separator);
169 AddChildViewAt(title_row_separator_, 1); 320 AddChildViewAt(title_row_separator_, 1);
170 } else { 321 } else {
171 AddChildViewAt(title_row_, child_count()); 322 AddChildViewAt(title_row_, child_count());
172 } 323 }
173 324
174 CreateExtraTitleRowButtons(); 325 CreateExtraTitleRowButtons();
175 326
176 if (MaterialDesignController::IsSystemTrayMenuMaterial()) 327 if (MaterialDesignController::IsSystemTrayMenuMaterial())
177 back_button_ = title_row_->AddBackButton(this); 328 back_button_ = title_row_->AddBackButton(this);
178 329
179 Layout(); 330 Layout();
180 } 331 }
181 332
182 void TrayDetailsView::CreateScrollableList() { 333 void TrayDetailsView::CreateScrollableList() {
183 DCHECK(!scroller_); 334 DCHECK(!scroller_);
184 scroll_content_ = new views::View; 335 scroll_content_ = new ScrollContentsView();
185 scroll_content_->SetLayoutManager(
186 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
187 scroller_ = new FixedSizedScrollView; 336 scroller_ = new FixedSizedScrollView;
188 scroller_->SetContentsView(scroll_content_); 337 scroller_->SetContentsView(scroll_content_);
189 338
190 // Note: |scroller_| takes ownership of |scroll_border_|. 339 // Note: |scroller_| takes ownership of |scroll_border_|.
191 scroll_border_ = new ScrollBorder; 340 scroll_border_ = new ScrollBorder;
192 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_)); 341 scroller_->SetBorder(std::unique_ptr<views::Border>(scroll_border_));
193 342
194 AddChildView(scroller_); 343 AddChildView(scroller_);
195 } 344 }
196 345
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
279 if (index < child_count() - 1 && child_at(index + 1) != title_row_) 428 if (index < child_count() - 1 && child_at(index + 1) != title_row_)
280 scroll_border_->set_visible(true); 429 scroll_border_->set_visible(true);
281 else 430 else
282 scroll_border_->set_visible(false); 431 scroll_border_->set_visible(false);
283 } 432 }
284 433
285 views::View::OnPaintBorder(canvas); 434 views::View::OnPaintBorder(canvas);
286 } 435 }
287 436
288 } // namespace ash 437 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/system/tray/tray_constants.cc ('k') | chromeos/dbus/fake_shill_manager_client.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698