Home | History | Annotate | Download | only in system
      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/status_area_widget_delegate.h"
      6 
      7 #include "ash/ash_export.h"
      8 #include "ash/ash_switches.h"
      9 #include "ash/focus_cycler.h"
     10 #include "ash/shell.h"
     11 #include "ash/shell_window_ids.h"
     12 #include "ash/system/tray/tray_constants.h"
     13 #include "base/memory/scoped_ptr.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "ui/aura/window_event_dispatcher.h"
     16 #include "ui/compositor/layer.h"
     17 #include "ui/compositor/scoped_layer_animation_settings.h"
     18 #include "ui/gfx/animation/tween.h"
     19 #include "ui/gfx/canvas.h"
     20 #include "ui/gfx/image/image.h"
     21 #include "ui/views/accessible_pane_view.h"
     22 #include "ui/views/layout/grid_layout.h"
     23 #include "ui/views/widget/widget.h"
     24 
     25 namespace {
     26 
     27 const int kAnimationDurationMs = 250;
     28 
     29 class StatusAreaWidgetDelegateAnimationSettings
     30     : public ui::ScopedLayerAnimationSettings {
     31  public:
     32   explicit StatusAreaWidgetDelegateAnimationSettings(ui::Layer* layer)
     33       : ui::ScopedLayerAnimationSettings(layer->GetAnimator()) {
     34     SetTransitionDuration(
     35         base::TimeDelta::FromMilliseconds(kAnimationDurationMs));
     36     SetPreemptionStrategy(
     37         ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
     38     SetTweenType(gfx::Tween::EASE_IN_OUT);
     39   }
     40 
     41   virtual ~StatusAreaWidgetDelegateAnimationSettings() {}
     42 
     43  private:
     44   DISALLOW_COPY_AND_ASSIGN(StatusAreaWidgetDelegateAnimationSettings);
     45 };
     46 
     47 }  // namespace
     48 
     49 namespace ash {
     50 
     51 StatusAreaWidgetDelegate::StatusAreaWidgetDelegate()
     52     : focus_cycler_for_testing_(NULL),
     53       alignment_(SHELF_ALIGNMENT_BOTTOM) {
     54   // Allow the launcher to surrender the focus to another window upon
     55   // navigation completion by the user.
     56   set_allow_deactivate_on_esc(true);
     57   SetPaintToLayer(true);
     58   SetFillsBoundsOpaquely(false);
     59 }
     60 
     61 StatusAreaWidgetDelegate::~StatusAreaWidgetDelegate() {
     62 }
     63 
     64 void StatusAreaWidgetDelegate::SetFocusCyclerForTesting(
     65     const FocusCycler* focus_cycler) {
     66   focus_cycler_for_testing_ = focus_cycler;
     67 }
     68 
     69 views::View* StatusAreaWidgetDelegate::GetDefaultFocusableChild() {
     70   return child_at(0);
     71 }
     72 
     73 views::Widget* StatusAreaWidgetDelegate::GetWidget() {
     74   return View::GetWidget();
     75 }
     76 
     77 const views::Widget* StatusAreaWidgetDelegate::GetWidget() const {
     78   return View::GetWidget();
     79 }
     80 
     81 void StatusAreaWidgetDelegate::OnGestureEvent(ui::GestureEvent* event) {
     82   if (gesture_handler_.ProcessGestureEvent(*event))
     83     event->StopPropagation();
     84   else
     85     views::AccessiblePaneView::OnGestureEvent(event);
     86 }
     87 
     88 bool StatusAreaWidgetDelegate::CanActivate() const {
     89   // We don't want mouse clicks to activate us, but we need to allow
     90   // activation when the user is using the keyboard (FocusCycler).
     91   const FocusCycler* focus_cycler = focus_cycler_for_testing_ ?
     92       focus_cycler_for_testing_ : Shell::GetInstance()->focus_cycler();
     93   return focus_cycler->widget_activating() == GetWidget();
     94 }
     95 
     96 void StatusAreaWidgetDelegate::DeleteDelegate() {
     97 }
     98 
     99 void StatusAreaWidgetDelegate::AddTray(views::View* tray) {
    100   SetLayoutManager(NULL);  // Reset layout manager before adding a child.
    101   AddChildView(tray);
    102   // Set the layout manager with the new list of children.
    103   UpdateLayout();
    104 }
    105 
    106 void StatusAreaWidgetDelegate::UpdateLayout() {
    107   // Use a grid layout so that the trays can be centered in each cell, and
    108   // so that the widget gets laid out correctly when tray sizes change.
    109   views::GridLayout* layout = new views::GridLayout(this);
    110   SetLayoutManager(layout);
    111 
    112   views::ColumnSet* columns = layout->AddColumnSet(0);
    113   if (alignment_ == SHELF_ALIGNMENT_BOTTOM ||
    114       alignment_ == SHELF_ALIGNMENT_TOP) {
    115     bool is_first_visible_child = true;
    116     for (int c = 0; c < child_count(); ++c) {
    117       views::View* child = child_at(c);
    118       if (!child->visible())
    119         continue;
    120       if (!is_first_visible_child)
    121         columns->AddPaddingColumn(0, kTraySpacing);
    122       is_first_visible_child = false;
    123       columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL,
    124                          0, /* resize percent */
    125                          views::GridLayout::USE_PREF, 0, 0);
    126     }
    127     layout->StartRow(0, 0);
    128     for (int c = child_count() - 1; c >= 0; --c) {
    129       views::View* child = child_at(c);
    130       if (child->visible())
    131         layout->AddView(child);
    132     }
    133   } else {
    134     columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER,
    135                        0, /* resize percent */
    136                        views::GridLayout::USE_PREF, 0, 0);
    137     bool is_first_visible_child = true;
    138     for (int c = child_count() - 1; c >= 0; --c) {
    139       views::View* child = child_at(c);
    140       if (!child->visible())
    141         continue;
    142       if (!is_first_visible_child)
    143         layout->AddPaddingRow(0, kTraySpacing);
    144       is_first_visible_child = false;
    145       layout->StartRow(0, 0);
    146       layout->AddView(child);
    147     }
    148   }
    149 
    150   layer()->GetAnimator()->StopAnimating();
    151   StatusAreaWidgetDelegateAnimationSettings settings(layer());
    152 
    153   Layout();
    154   UpdateWidgetSize();
    155 }
    156 
    157 void StatusAreaWidgetDelegate::ChildPreferredSizeChanged(View* child) {
    158   // Need to resize the window when trays or items are added/removed.
    159   StatusAreaWidgetDelegateAnimationSettings settings(layer());
    160   UpdateWidgetSize();
    161 }
    162 
    163 void StatusAreaWidgetDelegate::ChildVisibilityChanged(View* child) {
    164   UpdateLayout();
    165 }
    166 
    167 void StatusAreaWidgetDelegate::UpdateWidgetSize() {
    168   if (GetWidget())
    169     GetWidget()->SetSize(GetPreferredSize());
    170 }
    171 
    172 }  // namespace ash
    173