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

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

Issue 2557333003: [ash-md] Stacks child layers properly for sticky header rows (Closed)
Patch Set: [ash-md] Stacks child layers properly for sticky header rows (no shill changes) Created 4 years 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
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/ash_view_ids.h" 7 #include "ash/common/ash_view_ids.h"
8 #include "ash/common/material_design/material_design_controller.h" 8 #include "ash/common/material_design/material_design_controller.h"
9 #include "ash/common/system/tray/fixed_sized_scroll_view.h" 9 #include "ash/common/system/tray/fixed_sized_scroll_view.h"
10 #include "ash/common/system/tray/system_menu_button.h" 10 #include "ash/common/system/tray/system_menu_button.h"
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 views::View::Layout(); 93 views::View::Layout();
94 headers_.clear(); 94 headers_.clear();
95 for (int i = 0; i < child_count(); ++i) { 95 for (int i = 0; i < child_count(); ++i) {
96 views::View* view = child_at(i); 96 views::View* view = child_at(i);
97 if (view->id() == VIEW_ID_STICKY_HEADER) 97 if (view->id() == VIEW_ID_STICKY_HEADER)
98 headers_.emplace_back(view); 98 headers_.emplace_back(view);
99 } 99 }
100 PositionHeaderRows(); 100 PositionHeaderRows();
101 } 101 }
102 102
103 void ReorderChildLayers(ui::Layer* parent_layer) override {
104 views::View::ReorderChildLayers(parent_layer);
105 ui::Layer* topmost_layer = TopmostLayer(this, parent_layer);
106 if (!topmost_layer)
107 return;
108
109 // Keep the sticky headers with layers above the rest of the children's
110 // layers. Make sure to avoid changing the stacking order of the layers that
111 // are children of |parent_layer| but do not belong to the same parent view.
112 // Note: this assumes that all views that have id=VIEW_ID_STICKY_HEADER have
113 // a layer.
114 for (int i = child_count() - 1; i >= 0; --i) {
115 View* child = child_at(i);
116 if (child->id() == VIEW_ID_STICKY_HEADER &&
117 child->layer() != topmost_layer) {
118 parent_layer->StackAbove(child->layer(), topmost_layer);
119 }
120 }
121 }
122
103 void ViewHierarchyChanged( 123 void ViewHierarchyChanged(
104 const ViewHierarchyChangedDetails& details) override { 124 const ViewHierarchyChangedDetails& details) override {
105 if (!details.is_add && details.parent == this) { 125 if (!details.is_add && details.parent == this) {
106 headers_.erase(std::remove_if(headers_.begin(), headers_.end(), 126 headers_.erase(std::remove_if(headers_.begin(), headers_.end(),
107 [details](const Header& header) { 127 [details](const Header& header) {
108 return header.view == details.child; 128 return header.view == details.child;
109 }), 129 }),
110 headers_.end()); 130 headers_.end());
111 } else if (details.is_add && details.parent == this && 131 } else if (details.is_add && details.parent == this &&
112 details.child == child_at(0)) { 132 details.child == child_at(0)) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 bool draw_separator_below; 182 bool draw_separator_below;
163 }; 183 };
164 184
165 // Adjusts y-position of header rows allowing one or two rows to stick to the 185 // Adjusts y-position of header rows allowing one or two rows to stick to the
166 // top of the visible viewport. 186 // top of the visible viewport.
167 void PositionHeaderRows() { 187 void PositionHeaderRows() {
168 const int scroll_offset = -y(); 188 const int scroll_offset = -y();
169 Header* previous_header = nullptr; 189 Header* previous_header = nullptr;
170 for (auto& header : base::Reversed(headers_)) { 190 for (auto& header : base::Reversed(headers_)) {
171 views::View* header_view = header.view; 191 views::View* header_view = header.view;
172 header.draw_separator_below = false; 192 bool draw_separator_below = false;
173 if (header.natural_offset >= scroll_offset) { 193 if (header.natural_offset >= scroll_offset) {
174 previous_header = &header; 194 previous_header = &header;
175 header_view->SetY(header.natural_offset); 195 header_view->SetY(header.natural_offset);
176 continue; 196 } else {
197 if (previous_header &&
198 previous_header->view->y() <=
199 scroll_offset + header_view->height()) {
200 // Lower header displacing the header above.
201 draw_separator_below = true;
202 header_view->SetY(previous_header->view->y() - header_view->height());
203 } else {
204 // A header becomes sticky.
205 header_view->SetY(scroll_offset);
206 header_view->Layout();
207 header_view->SchedulePaint();
208 }
177 } 209 }
178 if (previous_header && 210 if (header.draw_separator_below != draw_separator_below) {
179 previous_header->view->y() <= scroll_offset + header_view->height()) { 211 header.draw_separator_below = draw_separator_below;
180 // Lower header displacing the header above. 212 TrayPopupUtils::ShowStickyHeaderSeparator(header_view,
181 header.draw_separator_below = true; 213 draw_separator_below);
182 header_view->SetY(previous_header->view->y() - header_view->height());
183 } else {
184 // A header becomes sticky.
185 header_view->SetY(scroll_offset);
186 header_view->Layout();
187 header_view->SchedulePaint();
188 } 214 }
189 break; 215 if (header.natural_offset < scroll_offset)
216 break;
190 } 217 }
191 } 218 }
192 219
193 // Paints a separator for a header view. The separator can be a horizontal 220 // Paints a separator for a header view. The separator can be a horizontal
194 // rule or a horizontal shadow, depending on whether the header is sticking to 221 // rule or a horizontal shadow, depending on whether the header is sticking to
195 // the top of the scroll viewport. The return value indicates whether a shadow 222 // the top of the scroll viewport. The return value indicates whether a shadow
196 // was drawn. 223 // was drawn.
197 bool PaintDelineation(const Header& header, const ui::PaintContext& context) { 224 bool PaintDelineation(const Header& header, const ui::PaintContext& context) {
198 const View* view = header.view; 225 const View* view = header.view;
199 226
200 // If the header is where it normally belongs, draw nothing. 227 // If the header is where it normally belongs or If the header is pushed by
201 if (view->y() == header.natural_offset) 228 // a header directly below it, draw nothing.
229 if (view->y() == header.natural_offset || header.draw_separator_below)
202 return false; 230 return false;
203 231
204 // If the header is pushed by a header directly below it, draw a separator.
205 if (header.draw_separator_below) {
206 // TODO(estade): look better at 1.5x scale.
207 ui::PaintRecorder recorder(context, size());
208 gfx::Canvas* canvas = recorder.canvas();
209 gfx::Rect separator = view->bounds();
210 separator.set_y(separator.bottom() - kSeparatorWidth);
211 separator.set_height(kSeparatorWidth);
212 canvas->FillRect(separator, kSeparatorColor);
213 return false;
214 }
215
216 // Otherwise, draw a shadow below. 232 // Otherwise, draw a shadow below.
217 DrawShadow(context, 233 DrawShadow(context,
218 gfx::Rect(0, 0, view->width(), view->bounds().bottom())); 234 gfx::Rect(0, 0, view->width(), view->bounds().bottom()));
219 return true; 235 return true;
220 } 236 }
221 237
222 // Draws a drop shadow below |shadowed_area|. 238 // Draws a drop shadow below |shadowed_area|.
223 void DrawShadow(const ui::PaintContext& context, 239 void DrawShadow(const ui::PaintContext& context,
224 const gfx::Rect& shadowed_area) { 240 const gfx::Rect& shadowed_area) {
225 ui::PaintRecorder recorder(context, size()); 241 ui::PaintRecorder recorder(context, size());
226 gfx::Canvas* canvas = recorder.canvas(); 242 gfx::Canvas* canvas = recorder.canvas();
227 SkPaint paint; 243 SkPaint paint;
228 gfx::ShadowValues shadow; 244 gfx::ShadowValues shadow;
229 shadow.emplace_back(gfx::Vector2d(0, kShadowOffsetY), kShadowBlur, 245 shadow.emplace_back(gfx::Vector2d(0, kShadowOffsetY), kShadowBlur,
230 kSeparatorColor); 246 kSeparatorColor);
231 paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow)); 247 paint.setLooper(gfx::CreateShadowDrawLooperCorrectBlur(shadow));
232 paint.setAntiAlias(true); 248 paint.setAntiAlias(true);
233 canvas->ClipRect(shadowed_area, SkClipOp::kDifference); 249 canvas->ClipRect(shadowed_area, SkClipOp::kDifference);
234 canvas->DrawRect(shadowed_area, paint); 250 canvas->DrawRect(shadowed_area, paint);
235 } 251 }
236 252
253 // Recursively iterates through children to return the child layer that is
254 // stacked at the top. Only considers layers that are direct |parent_layer|'s
255 // children.
256 ui::Layer* TopmostLayer(views::View* view, ui::Layer* parent_layer) {
257 DCHECK(parent_layer);
258 // Iterate backwards through the children to find the topmost layer.
259 for (int i = view->child_count() - 1; i >= 0; --i) {
260 views::View* child = view->child_at(i);
261 ui::Layer* layer = TopmostLayer(child, parent_layer);
262 if (layer)
263 return layer;
264 }
265 if (view->layer() && view->layer() != parent_layer &&
266 view->layer()->parent() == parent_layer) {
267 return view->layer();
268 }
269 return nullptr;
270 }
271
237 views::BoxLayout* box_layout_; 272 views::BoxLayout* box_layout_;
238 273
239 // Header child views that stick to the top of visible viewport when scrolled. 274 // Header child views that stick to the top of visible viewport when scrolled.
240 std::vector<Header> headers_; 275 std::vector<Header> headers_;
241 276
242 DISALLOW_COPY_AND_ASSIGN(ScrollContentsView); 277 DISALLOW_COPY_AND_ASSIGN(ScrollContentsView);
243 }; 278 };
244 279
245 // Constants for the title row in material design. 280 // Constants for the title row in material design.
246 const int kTitleRowVerticalPadding = 4; 281 const int kTitleRowVerticalPadding = 4;
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 if (index < child_count() - 1 && child_at(index + 1) != title_row_) 601 if (index < child_count() - 1 && child_at(index + 1) != title_row_)
567 scroll_border_->set_visible(true); 602 scroll_border_->set_visible(true);
568 else 603 else
569 scroll_border_->set_visible(false); 604 scroll_border_->set_visible(false);
570 } 605 }
571 606
572 views::View::OnPaintBorder(canvas); 607 views::View::OnPaintBorder(canvas);
573 } 608 }
574 609
575 } // namespace ash 610 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/system/chromeos/network/vpn_list_view.cc ('k') | ash/common/system/tray/tray_details_view_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698