OLD | NEW |
| (Empty) |
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/common/system/status_area_widget_delegate.h" | |
6 | |
7 #include "ash/common/focus_cycler.h" | |
8 #include "ash/common/shelf/shelf_constants.h" | |
9 #include "ash/common/shelf/wm_shelf.h" | |
10 #include "ash/common/shelf/wm_shelf_util.h" | |
11 #include "ash/common/system/tray/tray_constants.h" | |
12 #include "ash/common/wm_shell.h" | |
13 #include "ash/common/wm_window.h" | |
14 #include "ash/root_window_controller.h" | |
15 #include "ui/compositor/layer.h" | |
16 #include "ui/compositor/scoped_layer_animation_settings.h" | |
17 #include "ui/gfx/animation/tween.h" | |
18 #include "ui/views/accessible_pane_view.h" | |
19 #include "ui/views/border.h" | |
20 #include "ui/views/layout/grid_layout.h" | |
21 | |
22 namespace { | |
23 | |
24 constexpr int kAnimationDurationMs = 250; | |
25 | |
26 constexpr int kPaddingFromEdgeOfShelf = 3; | |
27 | |
28 class StatusAreaWidgetDelegateAnimationSettings | |
29 : public ui::ScopedLayerAnimationSettings { | |
30 public: | |
31 explicit StatusAreaWidgetDelegateAnimationSettings(ui::Layer* layer) | |
32 : ui::ScopedLayerAnimationSettings(layer->GetAnimator()) { | |
33 SetTransitionDuration( | |
34 base::TimeDelta::FromMilliseconds(kAnimationDurationMs)); | |
35 SetPreemptionStrategy(ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
36 SetTweenType(gfx::Tween::EASE_IN_OUT); | |
37 } | |
38 | |
39 ~StatusAreaWidgetDelegateAnimationSettings() override {} | |
40 | |
41 private: | |
42 DISALLOW_COPY_AND_ASSIGN(StatusAreaWidgetDelegateAnimationSettings); | |
43 }; | |
44 | |
45 } // namespace | |
46 | |
47 namespace ash { | |
48 | |
49 StatusAreaWidgetDelegate::StatusAreaWidgetDelegate() | |
50 : focus_cycler_for_testing_(nullptr), alignment_(SHELF_ALIGNMENT_BOTTOM) { | |
51 // Allow the launcher to surrender the focus to another window upon | |
52 // navigation completion by the user. | |
53 set_allow_deactivate_on_esc(true); | |
54 SetPaintToLayer(); | |
55 layer()->SetFillsBoundsOpaquely(false); | |
56 } | |
57 | |
58 StatusAreaWidgetDelegate::~StatusAreaWidgetDelegate() {} | |
59 | |
60 void StatusAreaWidgetDelegate::SetFocusCyclerForTesting( | |
61 const FocusCycler* focus_cycler) { | |
62 focus_cycler_for_testing_ = focus_cycler; | |
63 } | |
64 | |
65 views::View* StatusAreaWidgetDelegate::GetDefaultFocusableChild() { | |
66 return child_at(0); | |
67 } | |
68 | |
69 views::Widget* StatusAreaWidgetDelegate::GetWidget() { | |
70 return View::GetWidget(); | |
71 } | |
72 | |
73 const views::Widget* StatusAreaWidgetDelegate::GetWidget() const { | |
74 return View::GetWidget(); | |
75 } | |
76 | |
77 void StatusAreaWidgetDelegate::OnGestureEvent(ui::GestureEvent* event) { | |
78 views::Widget* target_widget = | |
79 static_cast<views::View*>(event->target())->GetWidget(); | |
80 WmWindow* target_window = WmWindow::Get(target_widget->GetNativeWindow()); | |
81 WmShelf* shelf = target_window->GetRootWindowController()->GetShelf(); | |
82 if (shelf->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_ | |
93 : WmShell::Get()->focus_cycler(); | |
94 return focus_cycler->widget_activating() == GetWidget(); | |
95 } | |
96 | |
97 void StatusAreaWidgetDelegate::DeleteDelegate() {} | |
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 // Update tray border based on layout. | |
113 bool is_child_on_edge = true; | |
114 for (int c = 0; c < child_count(); ++c) { | |
115 views::View* child = child_at(c); | |
116 if (!child->visible()) | |
117 continue; | |
118 SetBorderOnChild(child, is_child_on_edge); | |
119 is_child_on_edge = false; | |
120 } | |
121 | |
122 views::ColumnSet* columns = layout->AddColumnSet(0); | |
123 | |
124 if (IsHorizontalAlignment(alignment_)) { | |
125 for (int c = child_count() - 1; c >= 0; --c) { | |
126 views::View* child = child_at(c); | |
127 if (!child->visible()) | |
128 continue; | |
129 columns->AddColumn(views::GridLayout::CENTER, views::GridLayout::FILL, | |
130 0, /* resize percent */ | |
131 views::GridLayout::USE_PREF, 0, 0); | |
132 } | |
133 layout->StartRow(0, 0); | |
134 for (int c = child_count() - 1; c >= 0; --c) { | |
135 views::View* child = child_at(c); | |
136 if (child->visible()) | |
137 layout->AddView(child); | |
138 } | |
139 } else { | |
140 columns->AddColumn(views::GridLayout::FILL, views::GridLayout::CENTER, | |
141 0, /* resize percent */ | |
142 views::GridLayout::USE_PREF, 0, 0); | |
143 for (int c = child_count() - 1; c >= 0; --c) { | |
144 views::View* child = child_at(c); | |
145 if (!child->visible()) | |
146 continue; | |
147 layout->StartRow(0, 0); | |
148 layout->AddView(child); | |
149 } | |
150 } | |
151 | |
152 layer()->GetAnimator()->StopAnimating(); | |
153 StatusAreaWidgetDelegateAnimationSettings settings(layer()); | |
154 | |
155 Layout(); | |
156 UpdateWidgetSize(); | |
157 } | |
158 | |
159 void StatusAreaWidgetDelegate::ChildPreferredSizeChanged(View* child) { | |
160 // Need to resize the window when trays or items are added/removed. | |
161 StatusAreaWidgetDelegateAnimationSettings settings(layer()); | |
162 UpdateWidgetSize(); | |
163 } | |
164 | |
165 void StatusAreaWidgetDelegate::ChildVisibilityChanged(View* child) { | |
166 UpdateLayout(); | |
167 } | |
168 | |
169 void StatusAreaWidgetDelegate::UpdateWidgetSize() { | |
170 if (GetWidget()) | |
171 GetWidget()->SetSize(GetPreferredSize()); | |
172 } | |
173 | |
174 void StatusAreaWidgetDelegate::SetBorderOnChild(views::View* child, | |
175 bool extend_border_to_edge) { | |
176 // Tray views are laid out right-to-left or bottom-to-top. | |
177 const bool horizontal_alignment = IsHorizontalAlignment(alignment_); | |
178 const int padding = (GetShelfConstant(SHELF_SIZE) - kTrayItemSize) / 2; | |
179 | |
180 const int top_edge = horizontal_alignment ? padding : 0; | |
181 const int left_edge = horizontal_alignment ? 0 : padding; | |
182 const int bottom_edge = | |
183 horizontal_alignment | |
184 ? padding | |
185 : (extend_border_to_edge ? kPaddingFromEdgeOfShelf : 0); | |
186 const int right_edge = | |
187 horizontal_alignment | |
188 ? (extend_border_to_edge ? kPaddingFromEdgeOfShelf : 0) | |
189 : padding; | |
190 child->SetBorder( | |
191 views::CreateEmptyBorder(top_edge, left_edge, bottom_edge, right_edge)); | |
192 | |
193 // Layout on |child| needs to be updated based on new border value before | |
194 // displaying; otherwise |child| will be showing with old border size. | |
195 // Fix for crbug.com/623438. | |
196 child->Layout(); | |
197 } | |
198 | |
199 } // namespace ash | |
OLD | NEW |