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/strings/utf_string_conversions.h" 14#include "ui/aura/root_window.h" 15#include "ui/base/resource/resource_bundle.h" 16#include "ui/gfx/canvas.h" 17#include "ui/gfx/image/image.h" 18#include "ui/views/accessible_pane_view.h" 19#include "ui/views/layout/grid_layout.h" 20#include "ui/views/widget/widget.h" 21 22namespace ash { 23namespace internal { 24namespace { 25 26const int kStatusTrayOffsetFromScreenEdge = 4; 27 28} 29 30StatusAreaWidgetDelegate::StatusAreaWidgetDelegate() 31 : focus_cycler_for_testing_(NULL), 32 alignment_(SHELF_ALIGNMENT_BOTTOM) { 33 // Allow the launcher to surrender the focus to another window upon 34 // navigation completion by the user. 35 set_allow_deactivate_on_esc(true); 36} 37 38StatusAreaWidgetDelegate::~StatusAreaWidgetDelegate() { 39} 40 41void StatusAreaWidgetDelegate::SetFocusCyclerForTesting( 42 const FocusCycler* focus_cycler) { 43 focus_cycler_for_testing_ = focus_cycler; 44} 45 46views::View* StatusAreaWidgetDelegate::GetDefaultFocusableChild() { 47 return child_at(0); 48} 49 50views::Widget* StatusAreaWidgetDelegate::GetWidget() { 51 return View::GetWidget(); 52} 53 54const views::Widget* StatusAreaWidgetDelegate::GetWidget() const { 55 return View::GetWidget(); 56} 57 58void StatusAreaWidgetDelegate::OnGestureEvent(ui::GestureEvent* event) { 59 if (gesture_handler_.ProcessGestureEvent(*event)) 60 event->StopPropagation(); 61 else 62 views::AccessiblePaneView::OnGestureEvent(event); 63} 64 65bool StatusAreaWidgetDelegate::CanActivate() const { 66 // We don't want mouse clicks to activate us, but we need to allow 67 // activation when the user is using the keyboard (FocusCycler). 68 const FocusCycler* focus_cycler = focus_cycler_for_testing_ ? 69 focus_cycler_for_testing_ : Shell::GetInstance()->focus_cycler(); 70 return focus_cycler->widget_activating() == GetWidget(); 71} 72 73void StatusAreaWidgetDelegate::DeleteDelegate() { 74} 75 76void StatusAreaWidgetDelegate::AddTray(views::View* tray) { 77 SetLayoutManager(NULL); // Reset layout manager before adding a child. 78 AddChildView(tray); 79 // Set the layout manager with the new list of children. 80 UpdateLayout(); 81} 82 83void StatusAreaWidgetDelegate::UpdateLayout() { 84 // Use a grid layout so that the trays can be centered in each cell, and 85 // so that the widget gets laid out correctly when tray sizes change. 86 views::GridLayout* layout = new views::GridLayout(this); 87 SetLayoutManager(layout); 88 89 views::ColumnSet* columns = layout->AddColumnSet(0); 90 if (alignment_ == SHELF_ALIGNMENT_BOTTOM || 91 alignment_ == SHELF_ALIGNMENT_TOP) { 92 // Alternate shelf layout insets are all handled by tray_background_view. 93 if (!ash::switches::UseAlternateShelfLayout()) { 94 if (alignment_ == SHELF_ALIGNMENT_TOP) 95 layout->SetInsets(kStatusTrayOffsetFromScreenEdge, 0, 0, 0); 96 else 97 layout->SetInsets(0, 0, kStatusTrayOffsetFromScreenEdge, 0); 98 } 99 bool is_first_visible_child = true; 100 for (int c = 0; c < child_count(); ++c) { 101 views::View* child = child_at(c); 102 if (!child->visible()) 103 continue; 104 if (!is_first_visible_child) 105 columns->AddPaddingColumn(0, GetTraySpacing()); 106 is_first_visible_child = false; 107 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 108 0, /* resize percent */ 109 views::GridLayout::USE_PREF, 0, 0); 110 } 111 layout->StartRow(0, 0); 112 for (int c = child_count() - 1; c >= 0; --c) { 113 views::View* child = child_at(c); 114 if (child->visible()) 115 layout->AddView(child); 116 } 117 } else { 118 if (!ash::switches::UseAlternateShelfLayout()) { 119 if (alignment_ == SHELF_ALIGNMENT_LEFT) 120 layout->SetInsets(0, kStatusTrayOffsetFromScreenEdge, 0, 0); 121 else 122 layout->SetInsets(0, 0, 0, kStatusTrayOffsetFromScreenEdge); 123 } 124 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 125 0, /* resize percent */ 126 views::GridLayout::USE_PREF, 0, 0); 127 bool is_first_visible_child = true; 128 for (int c = child_count() - 1; c >= 0; --c) { 129 views::View* child = child_at(c); 130 if (!child->visible()) 131 continue; 132 if (!is_first_visible_child) 133 layout->AddPaddingRow(0, GetTraySpacing()); 134 is_first_visible_child = false; 135 layout->StartRow(0, 0); 136 layout->AddView(child); 137 } 138 } 139 Layout(); 140 UpdateWidgetSize(); 141} 142 143void StatusAreaWidgetDelegate::ChildPreferredSizeChanged(View* child) { 144 // Need to resize the window when trays or items are added/removed. 145 UpdateWidgetSize(); 146} 147 148void StatusAreaWidgetDelegate::ChildVisibilityChanged(View* child) { 149 UpdateLayout(); 150} 151 152void StatusAreaWidgetDelegate::UpdateWidgetSize() { 153 if (GetWidget()) 154 GetWidget()->SetSize(GetPreferredSize()); 155} 156 157} // namespace internal 158} // namespace ash 159