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 22 namespace ash { 23 namespace internal { 24 namespace { 25 26 const int kStatusTrayOffsetFromScreenEdge = 4; 27 28 } 29 30 StatusAreaWidgetDelegate::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 38 StatusAreaWidgetDelegate::~StatusAreaWidgetDelegate() { 39 } 40 41 void StatusAreaWidgetDelegate::SetFocusCyclerForTesting( 42 const FocusCycler* focus_cycler) { 43 focus_cycler_for_testing_ = focus_cycler; 44 } 45 46 views::View* StatusAreaWidgetDelegate::GetDefaultFocusableChild() { 47 return child_at(0); 48 } 49 50 views::Widget* StatusAreaWidgetDelegate::GetWidget() { 51 return View::GetWidget(); 52 } 53 54 const views::Widget* StatusAreaWidgetDelegate::GetWidget() const { 55 return View::GetWidget(); 56 } 57 58 void StatusAreaWidgetDelegate::OnGestureEvent(ui::GestureEvent* event) { 59 if (gesture_handler_.ProcessGestureEvent(*event)) 60 event->StopPropagation(); 61 else 62 views::AccessiblePaneView::OnGestureEvent(event); 63 } 64 65 bool 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 73 void StatusAreaWidgetDelegate::DeleteDelegate() { 74 } 75 76 void 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 83 void 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 if (alignment_ == SHELF_ALIGNMENT_TOP) 93 layout->SetInsets(kStatusTrayOffsetFromScreenEdge, 0, 0, 0); 94 else 95 layout->SetInsets(0, 0, kStatusTrayOffsetFromScreenEdge, 0); 96 bool is_first_visible_child = true; 97 for (int c = 0; c < child_count(); ++c) { 98 views::View* child = child_at(c); 99 if (!child->visible()) 100 continue; 101 if (!is_first_visible_child) 102 columns->AddPaddingColumn(0, GetTraySpacing()); 103 is_first_visible_child = false; 104 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, 105 0, /* resize percent */ 106 views::GridLayout::USE_PREF, 0, 0); 107 } 108 layout->StartRow(0, 0); 109 for (int c = child_count() - 1; c >= 0; --c) { 110 views::View* child = child_at(c); 111 if (child->visible()) 112 layout->AddView(child); 113 } 114 } else { 115 if (alignment_ == SHELF_ALIGNMENT_LEFT) 116 layout->SetInsets(0, kStatusTrayOffsetFromScreenEdge, 0, 0); 117 else 118 layout->SetInsets(0, 0, 0, kStatusTrayOffsetFromScreenEdge); 119 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, 120 0, /* resize percent */ 121 views::GridLayout::USE_PREF, 0, 0); 122 bool is_first_visible_child = true; 123 for (int c = child_count() - 1; c >= 0; --c) { 124 views::View* child = child_at(c); 125 if (!child->visible()) 126 continue; 127 if (!is_first_visible_child) 128 layout->AddPaddingRow(0, GetTraySpacing()); 129 is_first_visible_child = false; 130 layout->StartRow(0, 0); 131 layout->AddView(child); 132 } 133 } 134 Layout(); 135 UpdateWidgetSize(); 136 } 137 138 void StatusAreaWidgetDelegate::ChildPreferredSizeChanged(View* child) { 139 // Need to resize the window when trays or items are added/removed. 140 UpdateWidgetSize(); 141 } 142 143 void StatusAreaWidgetDelegate::ChildVisibilityChanged(View* child) { 144 UpdateLayout(); 145 } 146 147 void StatusAreaWidgetDelegate::UpdateWidgetSize() { 148 if (GetWidget()) 149 GetWidget()->SetSize(GetPreferredSize()); 150 } 151 152 } // namespace internal 153 } // namespace ash 154