Home | History | Annotate | Download | only in tray
      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