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