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/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 Loading... | |
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 if (child->layer() != topmost_layer) | |
118 parent_layer->StackAbove(child->layer(), topmost_layer); | |
119 } | |
120 } | |
sadrul
2016/12/14 00:48:29
This is really subtle. Can you look at having a te
varkha
2016/12/14 17:46:42
I will.
| |
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 Loading... | |
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, kDifference_SkClipOp); | 249 canvas->ClipRect(shadowed_area, kDifference_SkClipOp); |
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 Loading... | |
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 |
OLD | NEW |