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