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
3 // found in the LICENSE file.
4
5 #include "ash/system/tray/tray_details_view.h"
6
7 #include "ash/system/tray/fixed_sized_scroll_view.h"
8 #include "ash/system/tray/system_tray.h"
9 #include "ash/system/tray/system_tray_item.h"
10 #include "ash/system/tray/tray_constants.h"
11 #include "ui/gfx/canvas.h"
12 #include "ui/views/background.h"
13 #include "ui/views/border.h"
14 #include "ui/views/controls/scroll_view.h"
15 #include "ui/views/layout/box_layout.h"
16
17 namespace ash {
18 namespace internal {
19
20 class ScrollSeparator : public views::View {
21 public:
ScrollSeparator()22 ScrollSeparator() {}
23
~ScrollSeparator()24 virtual ~ScrollSeparator() {}
25
26 private:
27 // Overriden from views::View.
OnPaint(gfx::Canvas * canvas)28 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
29 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor);
30 }
GetPreferredSize()31 virtual gfx::Size GetPreferredSize() OVERRIDE {
32 return gfx::Size(1, kTrayPopupScrollSeparatorHeight);
33 }
34
35 DISALLOW_COPY_AND_ASSIGN(ScrollSeparator);
36 };
37
38 class ScrollBorder : public views::Border {
39 public:
ScrollBorder()40 ScrollBorder() {}
~ScrollBorder()41 virtual ~ScrollBorder() {}
42
set_visible(bool visible)43 void set_visible(bool visible) { visible_ = visible; }
44
45 private:
46 // Overridden from views::Border.
Paint(const views::View & view,gfx::Canvas * canvas)47 virtual void Paint(const views::View& view, gfx::Canvas* canvas) OVERRIDE {
48 if (!visible_)
49 return;
50 canvas->FillRect(gfx::Rect(0, view.height() - 1, view.width(), 1),
51 kBorderLightColor);
52 }
53
GetInsets() const54 virtual gfx::Insets GetInsets() const OVERRIDE {
55 return gfx::Insets(0, 0, 1, 0);
56 }
57
GetMinimumSize() const58 virtual gfx::Size GetMinimumSize() const OVERRIDE {
59 return gfx::Size(0, 1);
60 }
61
62 bool visible_;
63
64 DISALLOW_COPY_AND_ASSIGN(ScrollBorder);
65 };
66
TrayDetailsView(SystemTrayItem * owner)67 TrayDetailsView::TrayDetailsView(SystemTrayItem* owner)
68 : owner_(owner),
69 footer_(NULL),
70 scroller_(NULL),
71 scroll_content_(NULL),
72 scroll_border_(NULL) {
73 SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical,
74 0, 0, 0));
75 set_background(views::Background::CreateSolidBackground(kBackgroundColor));
76 }
77
~TrayDetailsView()78 TrayDetailsView::~TrayDetailsView() {
79 }
80
CreateSpecialRow(int string_id,ViewClickListener * listener)81 void TrayDetailsView::CreateSpecialRow(int string_id,
82 ViewClickListener* listener) {
83 DCHECK(!footer_);
84 footer_ = new SpecialPopupRow();
85 footer_->SetTextLabel(string_id, listener);
86 AddChildViewAt(footer_, child_count());
87 }
88
CreateScrollableList()89 void TrayDetailsView::CreateScrollableList() {
90 DCHECK(!scroller_);
91 scroll_content_ = new views::View;
92 scroll_content_->SetLayoutManager(new views::BoxLayout(
93 views::BoxLayout::kVertical, 0, 0, 1));
94 scroller_ = new FixedSizedScrollView;
95 scroller_->SetContentsView(scroll_content_);
96
97 // Note: |scroller_| takes ownership of |scroll_border_|.
98 scroll_border_ = new ScrollBorder;
99 scroller_->set_border(scroll_border_);
100
101 AddChildView(scroller_);
102 }
103
AddScrollSeparator()104 void TrayDetailsView::AddScrollSeparator() {
105 DCHECK(scroll_content_);
106 // Do not draw the separator if it is the very first item
107 // in the scrollable list.
108 if (scroll_content_->has_children())
109 scroll_content_->AddChildView(new ScrollSeparator);
110 }
111
Reset()112 void TrayDetailsView::Reset() {
113 RemoveAllChildViews(true);
114 footer_ = NULL;
115 scroller_ = NULL;
116 scroll_content_ = NULL;
117 }
118
TransitionToDefaultView()119 void TrayDetailsView::TransitionToDefaultView() {
120 // Cache pointer to owner in this function scope. TrayDetailsView will be
121 // deleted after called ShowDefaultView.
122 SystemTrayItem* owner = owner_;
123 if (footer_ && footer_->content() && footer_->content()->HasFocus())
124 owner->set_restore_focus(true);
125 owner->system_tray()->ShowDefaultView(BUBBLE_USE_EXISTING);
126 owner->set_restore_focus(false);
127 }
128
Layout()129 void TrayDetailsView::Layout() {
130 if (!scroller_ || !footer_ || bounds().IsEmpty()) {
131 views::View::Layout();
132 return;
133 }
134
135 scroller_->set_fixed_size(gfx::Size());
136 gfx::Size size = GetPreferredSize();
137
138 // Set the scroller to fill the space above the bottom row, so that the
139 // bottom row of the detailed view will always stay just above the footer.
140 gfx::Size scroller_size = scroll_content_->GetPreferredSize();
141 scroller_->set_fixed_size(gfx::Size(
142 width() + scroller_->GetScrollBarWidth(),
143 scroller_size.height() - (size.height() - height())));
144
145 views::View::Layout();
146 // Always make sure the footer element is bottom aligned.
147 gfx::Rect fbounds = footer_->bounds();
148 fbounds.set_y(height() - footer_->height());
149 footer_->SetBoundsRect(fbounds);
150 }
151
OnPaintBorder(gfx::Canvas * canvas)152 void TrayDetailsView::OnPaintBorder(gfx::Canvas* canvas) {
153 if (scroll_border_) {
154 int index = GetIndexOf(scroller_);
155 if (index < child_count() - 1 && child_at(index + 1) != footer_)
156 scroll_border_->set_visible(true);
157 else
158 scroll_border_->set_visible(false);
159 }
160
161 views::View::OnPaintBorder(canvas);
162 }
163
164 } // namespace internal
165 } // namespace ash
166