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

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

Issue 2561253002: [ash-md] Adds support for Z-order iteration in views::View (Closed)
Patch Set: [ash-md] Adds support for Z-order iteration in views::View (using GetChildrenOrderedByVisualOrder) 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
62 } 62 }
63 ~ScrollContentsView() override {} 63 ~ScrollContentsView() override {}
64 64
65 protected: 65 protected:
66 // views::View: 66 // views::View:
67 void OnBoundsChanged(const gfx::Rect& previous_bounds) override { 67 void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
68 PositionHeaderRows(); 68 PositionHeaderRows();
69 } 69 }
70 70
71 void PaintChildren(const ui::PaintContext& context) override { 71 void PaintChildren(const ui::PaintContext& context) override {
72 for (int i = 0; i < child_count(); ++i) { 72 views::View::PaintChildren(context);
73 if (child_at(i)->id() != VIEW_ID_STICKY_HEADER && !child_at(i)->layer())
74 child_at(i)->Paint(context);
75 }
76 bool did_draw_shadow = false; 73 bool did_draw_shadow = false;
77 // Paint header rows above other children in Z-order. 74 // Paint header row separators.
78 for (auto& header : headers_) { 75 for (auto& header : headers_)
79 if (!header.view->layer())
80 header.view->Paint(context);
81 did_draw_shadow = PaintDelineation(header, context) || did_draw_shadow; 76 did_draw_shadow = PaintDelineation(header, context) || did_draw_shadow;
82 }
83 77
84 // Draw a shadow at the top of the viewport when scrolled, but only if a 78 // Draw a shadow at the top of the viewport when scrolled, but only if a
85 // header didn't already draw one. Overlap the shadow with the separator 79 // header didn't already draw one. Overlap the shadow with the separator
86 // that's below the header view so we don't get both a separator and a full 80 // that's below the header view so we don't get both a separator and a full
87 // shadow. 81 // shadow.
88 if (y() != 0 && !did_draw_shadow) 82 if (y() != 0 && !did_draw_shadow)
89 DrawShadow(context, gfx::Rect(0, 0, width(), -y() - kSeparatorWidth)); 83 DrawShadow(context, gfx::Rect(0, 0, width(), -y() - kSeparatorWidth));
90 } 84 }
91 85
92 void Layout() override { 86 void Layout() override {
93 views::View::Layout(); 87 views::View::Layout();
94 headers_.clear(); 88 headers_.clear();
95 for (int i = 0; i < child_count(); ++i) { 89 for (int i = 0; i < child_count(); ++i) {
96 views::View* view = child_at(i); 90 views::View* view = child_at(i);
97 if (view->id() == VIEW_ID_STICKY_HEADER) 91 if (view->id() == VIEW_ID_STICKY_HEADER)
98 headers_.emplace_back(view); 92 headers_.emplace_back(view);
99 } 93 }
100 PositionHeaderRows(); 94 PositionHeaderRows();
101 } 95 }
102 96
97 View::Views GetChildrenOrderedByVisualOrder() override {
98 // TODO(varkha): Not sure if this is worth it but the array could be a class
99 // member |children_in_visual_order_| and only updated in an override of
100 // ReorderChildLayers() before calling base View::ReorderChildLayers(). Then
101 // this method could simply return |children_in_visual_order_|.
102 View::Views children;
103 // Iterate over regular children and later over the sticky headers to keep
104 // the sticky headers above in Z-order.
105 for (int i = 0; i < child_count(); ++i) {
106 if (child_at(i)->id() != VIEW_ID_STICKY_HEADER)
107 children.push_back(child_at(i));
108 }
109 for (int i = 0; i < child_count(); ++i) {
110 if (child_at(i)->id() == VIEW_ID_STICKY_HEADER)
111 children.push_back(child_at(i));
112 }
113 DCHECK_EQ(child_count(), static_cast<int>(children.size()));
114 return children;
115 }
116
103 void ViewHierarchyChanged( 117 void ViewHierarchyChanged(
104 const ViewHierarchyChangedDetails& details) override { 118 const ViewHierarchyChangedDetails& details) override {
105 if (!details.is_add && details.parent == this) { 119 if (!details.is_add && details.parent == this) {
106 headers_.erase(std::remove_if(headers_.begin(), headers_.end(), 120 headers_.erase(std::remove_if(headers_.begin(), headers_.end(),
107 [details](const Header& header) { 121 [details](const Header& header) {
108 return header.view == details.child; 122 return header.view == details.child;
109 }), 123 }),
110 headers_.end()); 124 headers_.end());
111 } else if (details.is_add && details.parent == this && 125 } else if (details.is_add && details.parent == this &&
112 details.child == child_at(0)) { 126 details.child == child_at(0)) {
113 // We always want padding on the bottom of the scroll contents. 127 // We always want padding on the bottom of the scroll contents.
114 // We only want padding on the top of the scroll contents if the first 128 // We only want padding on the top of the scroll contents if the first
115 // child is not a header (in that case, the padding is built into the 129 // child is not a header (in that case, the padding is built into the
116 // header). 130 // header).
117 DCHECK_EQ(box_layout_, GetLayoutManager()); 131 DCHECK_EQ(box_layout_, GetLayoutManager());
118 box_layout_->set_inside_border_insets( 132 box_layout_->set_inside_border_insets(
119 gfx::Insets(details.child->id() == VIEW_ID_STICKY_HEADER 133 gfx::Insets(details.child->id() == VIEW_ID_STICKY_HEADER
120 ? 0 134 ? 0
121 : kMenuSeparatorVerticalPadding, 135 : kMenuSeparatorVerticalPadding,
122 0, kMenuSeparatorVerticalPadding, 0)); 136 0, kMenuSeparatorVerticalPadding, 0));
123 } 137 }
124 } 138 }
125 139
126 // views::ViewTargeterDelegate:
127 View* TargetForRect(View* root, const gfx::Rect& rect) override {
128 // Give header rows first dibs on events.
129 for (auto& header : headers_) {
130 views::View* view = header.view;
131 gfx::Rect local_to_header = rect;
132 local_to_header.Offset(-view->x(), -view->y());
133 if (ViewTargeterDelegate::DoesIntersectRect(view, local_to_header))
134 return ViewTargeterDelegate::TargetForRect(view, local_to_header);
135 }
136 return ViewTargeterDelegate::TargetForRect(root, rect);
137 }
138
139 private: 140 private:
140 const SkColor kSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F); 141 const SkColor kSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
141 const int kShadowOffsetY = 2; 142 const int kShadowOffsetY = 2;
142 const int kShadowBlur = 2; 143 const int kShadowBlur = 2;
143 // TODO(fukino): Remove this constant once we stop maintaining pre-MD design. 144 // TODO(fukino): Remove this constant once we stop maintaining pre-MD design.
144 // crbug.com/614453. 145 // crbug.com/614453.
145 const int kContentsBetweenChildSpacingNonMd = 1; 146 const int kContentsBetweenChildSpacingNonMd = 1;
146 147
147 // A structure that keeps the original offset of each header between the 148 // A structure that keeps the original offset of each header between the
148 // calls to Layout() to allow keeping track of which view should be sticky. 149 // calls to Layout() to allow keeping track of which view should be sticky.
(...skipping 13 matching lines...) Expand all
162 bool draw_separator_below; 163 bool draw_separator_below;
163 }; 164 };
164 165
165 // Adjusts y-position of header rows allowing one or two rows to stick to the 166 // Adjusts y-position of header rows allowing one or two rows to stick to the
166 // top of the visible viewport. 167 // top of the visible viewport.
167 void PositionHeaderRows() { 168 void PositionHeaderRows() {
168 const int scroll_offset = -y(); 169 const int scroll_offset = -y();
169 Header* previous_header = nullptr; 170 Header* previous_header = nullptr;
170 for (auto& header : base::Reversed(headers_)) { 171 for (auto& header : base::Reversed(headers_)) {
171 views::View* header_view = header.view; 172 views::View* header_view = header.view;
172 header.draw_separator_below = false; 173 bool draw_separator_below = false;
173 if (header.natural_offset >= scroll_offset) { 174 if (header.natural_offset >= scroll_offset) {
174 previous_header = &header; 175 previous_header = &header;
175 header_view->SetY(header.natural_offset); 176 header_view->SetY(header.natural_offset);
176 continue; 177 } else {
178 if (previous_header &&
179 previous_header->view->y() <=
180 scroll_offset + header_view->height()) {
181 // Lower header displacing the header above.
182 draw_separator_below = true;
183 header_view->SetY(previous_header->view->y() - header_view->height());
184 } else {
185 // A header becomes sticky.
186 header_view->SetY(scroll_offset);
187 header_view->Layout();
188 header_view->SchedulePaint();
189 }
177 } 190 }
178 if (previous_header && 191 if (header.draw_separator_below != draw_separator_below) {
179 previous_header->view->y() <= scroll_offset + header_view->height()) { 192 header.draw_separator_below = draw_separator_below;
180 // Lower header displacing the header above. 193 TrayPopupUtils::ShowStickyHeaderSeparator(header_view,
181 header.draw_separator_below = true; 194 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 } 195 }
189 break; 196 if (header.natural_offset < scroll_offset)
197 break;
190 } 198 }
191 } 199 }
192 200
193 // Paints a separator for a header view. The separator can be a horizontal 201 // 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 202 // 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 203 // the top of the scroll viewport. The return value indicates whether a shadow
196 // was drawn. 204 // was drawn.
197 bool PaintDelineation(const Header& header, const ui::PaintContext& context) { 205 bool PaintDelineation(const Header& header, const ui::PaintContext& context) {
198 const View* view = header.view; 206 const View* view = header.view;
199 207
200 // If the header is where it normally belongs, draw nothing. 208 // If the header is where it normally belongs or If the header is pushed by
201 if (view->y() == header.natural_offset) 209 // a header directly below it, draw nothing.
210 if (view->y() == header.natural_offset || header.draw_separator_below)
202 return false; 211 return false;
203 212
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. 213 // Otherwise, draw a shadow below.
217 DrawShadow(context, 214 DrawShadow(context,
218 gfx::Rect(0, 0, view->width(), view->bounds().bottom())); 215 gfx::Rect(0, 0, view->width(), view->bounds().bottom()));
219 return true; 216 return true;
220 } 217 }
221 218
222 // Draws a drop shadow below |shadowed_area|. 219 // Draws a drop shadow below |shadowed_area|.
223 void DrawShadow(const ui::PaintContext& context, 220 void DrawShadow(const ui::PaintContext& context,
224 const gfx::Rect& shadowed_area) { 221 const gfx::Rect& shadowed_area) {
225 ui::PaintRecorder recorder(context, size()); 222 ui::PaintRecorder recorder(context, size());
(...skipping 340 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 if (index < child_count() - 1 && child_at(index + 1) != title_row_) 563 if (index < child_count() - 1 && child_at(index + 1) != title_row_)
567 scroll_border_->set_visible(true); 564 scroll_border_->set_visible(true);
568 else 565 else
569 scroll_border_->set_visible(false); 566 scroll_border_->set_visible(false);
570 } 567 }
571 568
572 views::View::OnPaintBorder(canvas); 569 views::View::OnPaintBorder(canvas);
573 } 570 }
574 571
575 } // namespace ash 572 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698