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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ash/common/system/tray/tray_details_view.cc
diff --git a/ash/common/system/tray/tray_details_view.cc b/ash/common/system/tray/tray_details_view.cc
index 70ff14fd6b4feb2838251819af30b34515ef2cf2..2e10a6167c09c371ecf615a9977e864a74af317c 100644
--- a/ash/common/system/tray/tray_details_view.cc
+++ b/ash/common/system/tray/tray_details_view.cc
@@ -16,10 +16,161 @@
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/separator.h"
#include "ui/views/layout/box_layout.h"
+#include "ui/views/view_targeter.h"
+#include "ui/views/view_targeter_delegate.h"
namespace ash {
namespace {
+const int kHeaderRowSeparatorThickness = 1;
+const SkColor kHeaderRowSeparatorColor = SkColorSetA(SK_ColorBLACK, 0x1F);
+
+// A view that is used as ScrollView contents. It supports designating some of
+// the children as sticky header rows. The sticky header rows are not scrolled
+// above the top of the visible viewport until the next one "pushes" it up and
+// are painted above other children. To indicate that a child is a sticky header
+// row use set_id(kHeaderRowId).
+class ScrollContentsView : public views::View,
+ public views::ViewTargeterDelegate {
+ public:
+ ScrollContentsView() {
+ SetEventTargeter(base::MakeUnique<views::ViewTargeter>(this));
+ SetLayoutManager(
+ new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
+ }
+ ~ScrollContentsView() override {}
+
+ protected:
+ // views::View:
+ void OnBoundsChanged(const gfx::Rect& previous_bounds) override {
+ PositionHeaderRows();
+ }
+
+ void PaintChildren(const ui::PaintContext& context) override {
+ for (int i = 0; i < child_count(); ++i) {
+ if (child_at(i)->id() != kHeaderRowId && !child_at(i)->layer())
+ child_at(i)->Paint(context);
+ }
+ // Paint header rows above other children in Z-order.
+ for (auto& header : headers_) {
+ if (!header.view()->layer())
+ header.view()->Paint(context);
+ }
+ }
+
+ void Layout() override {
+ views::View::Layout();
+ headers_.clear();
+ for (int i = 0; i < child_count(); ++i) {
+ views::View* view = child_at(i);
+ if (view->id() == kHeaderRowId)
+ headers_.push_back(Header(view));
+ }
+ PositionHeaderRows();
+ }
+
+ void ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) override {
+ if (!details.is_add && details.parent == this) {
+ headers_.erase(std::remove_if(headers_.begin(), headers_.end(),
+ [details](const Header& header) {
+ return header.view() == details.child;
+ }),
+ headers_.end());
+ }
+ }
+
+ View* TargetForRect(View* root, const gfx::Rect& rect) override {
+ // Give header rows first dibs on events.
+ for (auto& header : headers_) {
+ views::View* view = header.view();
+ gfx::Rect local_to_header = rect;
+ local_to_header.Offset(-view->x(), -view->y());
+ if (ViewTargeterDelegate::DoesIntersectRect(view, local_to_header))
+ return ViewTargeterDelegate::TargetForRect(view, local_to_header);
+ }
+ return ViewTargeterDelegate::TargetForRect(root, rect);
+ }
+
+ private:
+ // A structure that keeps the original offset of each header between the
+ // 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.
+ class Header {
+ public:
+ Header(views::View* header)
+ : view_(header), offset_(header->y()), sticky_(true) {
+ DecorateAsSticky(false);
+ }
+
+ // Sets decorations on a header row to indicate whether it is |sticky|.
+ void DecorateAsSticky(bool sticky) {
+ if (sticky_ == sticky)
+ return;
+ sticky_ = sticky;
+ if (sticky) {
+ view_->SetBorder(views::Border::CreateSolidSidedBorder(
+ 0, 0, kHeaderRowSeparatorThickness, 0, kHeaderRowSeparatorColor));
+ } else {
+ view_->SetBorder(views::Border::CreateSolidSidedBorder(
+ kHeaderRowSeparatorThickness, 0, 0, 0, kHeaderRowSeparatorColor));
+ }
+ }
+
+ 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
+ views::View* view() {
+ return const_cast<views::View*>(const_cast<const Header*>(this)->view());
+ }
+ int offset() const { return offset_; }
+
+ private:
+ // A header View that can be decorated as sticky.
+ views::View* view_;
+
+ // Offset from the top of ScrollContentsView to |view|'s original vertical
+ // position.
+ int offset_;
+
+ // True if the header is decorated as sticky with a shadow below.
+ bool sticky_;
+ };
+
+ // Adjusts y-position of header rows allowing one or two rows to stick to the
+ // top of the visible viewport.
+ void PositionHeaderRows() {
+ const int scroll_offset = -y();
+ auto previous_header = headers_.rend();
+ for (auto header = headers_.rbegin(); header != headers_.rend(); ++header) {
+ 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.
+ if (header->offset() < scroll_offset) {
+ if (previous_header != headers_.rend() &&
+ previous_header->view()->y() <
+ scroll_offset + header_view->height()) {
+ // Lower header displacing the header above.
+ header_view->SetY(previous_header->view()->y() -
+ header_view->height());
+ header->DecorateAsSticky(false);
+ previous_header->DecorateAsSticky(false);
+ } else {
+ // A header becomes sticky.
+ header_view->SetY(scroll_offset);
+ header->DecorateAsSticky(true);
+ header_view->Layout();
+ header_view->SchedulePaint();
+ }
+ break;
+ } 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.
+ header->DecorateAsSticky(false);
+ previous_header = header;
+ }
+ }
+ }
+
+ // Header child views that stick to the top of visible viewport when scrolled.
+ std::vector<Header> headers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScrollContentsView);
+};
+
// Constants for the title row in material design.
const int kTitleRowVerticalPadding = 4;
const int kTitleRowSeparatorBorderHeight = 1;
@@ -65,8 +216,6 @@ class TitleRowSeparatorLayout : public views::LayoutManager {
}
};
-} // namespace
-
class ScrollSeparator : public views::View {
public:
ScrollSeparator() {}
@@ -74,7 +223,7 @@ class ScrollSeparator : public views::View {
~ScrollSeparator() override {}
private:
- // Overriden from views::View.
+ // views::View:
void OnPaint(gfx::Canvas* canvas) override {
canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor);
}
@@ -85,6 +234,8 @@ class ScrollSeparator : public views::View {
DISALLOW_COPY_AND_ASSIGN(ScrollSeparator);
};
+} // namespace
+
class ScrollBorder : public views::Border {
public:
ScrollBorder() {}
@@ -93,7 +244,7 @@ class ScrollBorder : public views::Border {
void set_visible(bool visible) { visible_ = visible; }
private:
- // Overridden from views::Border.
+ // views::Border:
void Paint(const views::View& view, gfx::Canvas* canvas) override {
if (!visible_)
return;
@@ -105,7 +256,7 @@ class ScrollBorder : public views::Border {
gfx::Size GetMinimumSize() const override { return gfx::Size(0, 1); }
- bool visible_;
+ bool visible_ = false;
DISALLOW_COPY_AND_ASSIGN(ScrollBorder);
};
@@ -161,7 +312,7 @@ void TrayDetailsView::CreateTitleRow(int string_id) {
title_row_separator_->SetLayoutManager(new TitleRowSeparatorLayout);
views::Separator* separator =
new views::Separator(views::Separator::HORIZONTAL);
- separator->SetColor(ash::kTitleRowSeparatorBorderColor);
+ separator->SetColor(kTitleRowSeparatorBorderColor);
separator->SetPreferredSize(kTitleRowSeparatorBorderHeight);
separator->SetBorder(views::Border::CreateEmptyBorder(
kTitleRowSeparatorHeight - kTitleRowSeparatorBorderHeight, 0, 0, 0));
@@ -181,9 +332,7 @@ void TrayDetailsView::CreateTitleRow(int string_id) {
void TrayDetailsView::CreateScrollableList() {
DCHECK(!scroller_);
- scroll_content_ = new views::View;
- scroll_content_->SetLayoutManager(
- new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 1));
+ scroll_content_ = new ScrollContentsView();
scroller_ = new FixedSizedScrollView;
scroller_->SetContentsView(scroll_content_);
« 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