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: 22 ScrollSeparator() {} 23 24 virtual ~ScrollSeparator() {} 25 26 private: 27 // Overriden from views::View. 28 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 29 canvas->FillRect(gfx::Rect(0, height() / 2, width(), 1), kBorderLightColor); 30 } 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: 40 ScrollBorder() {} 41 virtual ~ScrollBorder() {} 42 43 void set_visible(bool visible) { visible_ = visible; } 44 45 private: 46 // Overridden from views::Border. 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 54 virtual gfx::Insets GetInsets() const OVERRIDE { 55 return gfx::Insets(0, 0, 1, 0); 56 } 57 58 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 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 78 TrayDetailsView::~TrayDetailsView() { 79 } 80 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 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 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 112 void TrayDetailsView::Reset() { 113 RemoveAllChildViews(true); 114 footer_ = NULL; 115 scroller_ = NULL; 116 scroll_content_ = NULL; 117 } 118 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 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 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