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 // 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 143 void StatusAreaWidgetDelegate::ChildPreferredSizeChanged(View* child) { 144 // Need to resize the window when trays or items are added/removed. 145 UpdateWidgetSize(); 146 } 147 148 void StatusAreaWidgetDelegate::ChildVisibilityChanged(View* child) { 149 UpdateLayout(); 150 } 151 152 void StatusAreaWidgetDelegate::UpdateWidgetSize() { 153 if (GetWidget()) 154 GetWidget()->SetSize(GetPreferredSize()); 155 } 156 157 } // namespace internal 158 } // namespace ash 159