Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: ash/common/wm/overview/window_selector.cc

Issue 2734653002: chromeos: Move files in //ash/common to //ash (Closed)
Patch Set: fix a11y tests, fix docs Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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/wm/overview/window_selector.h"
6
7 #include <algorithm>
8 #include <functional>
9 #include <set>
10 #include <utility>
11 #include <vector>
12
13 #include "ash/common/accessibility_delegate.h"
14 #include "ash/common/accessibility_types.h"
15 #include "ash/common/metrics/user_metrics_action.h"
16 #include "ash/common/shelf/wm_shelf.h"
17 #include "ash/common/wm/mru_window_tracker.h"
18 #include "ash/common/wm/overview/window_grid.h"
19 #include "ash/common/wm/overview/window_selector_delegate.h"
20 #include "ash/common/wm/overview/window_selector_item.h"
21 #include "ash/common/wm/panels/panel_layout_manager.h"
22 #include "ash/common/wm/switchable_windows.h"
23 #include "ash/common/wm/window_state.h"
24 #include "ash/common/wm/wm_screen_util.h"
25 #include "ash/common/wm_shell.h"
26 #include "ash/common/wm_window.h"
27 #include "ash/public/cpp/shell_window_ids.h"
28 #include "ash/root_window_controller.h"
29 #include "base/auto_reset.h"
30 #include "base/command_line.h"
31 #include "base/metrics/histogram_macros.h"
32 #include "third_party/skia/include/core/SkPath.h"
33 #include "ui/base/resource/resource_bundle.h"
34 #include "ui/compositor/scoped_layer_animation_settings.h"
35 #include "ui/display/screen.h"
36 #include "ui/events/event.h"
37 #include "ui/gfx/canvas.h"
38 #include "ui/gfx/paint_vector_icon.h"
39 #include "ui/gfx/skia_util.h"
40 #include "ui/gfx/vector_icons_public.h"
41 #include "ui/views/border.h"
42 #include "ui/views/controls/image_view.h"
43 #include "ui/views/controls/textfield/textfield.h"
44 #include "ui/views/layout/box_layout.h"
45
46 namespace ash {
47
48 namespace {
49
50 // The amount of padding surrounding the text in the text filtering textbox.
51 const int kTextFilterHorizontalPadding = 10;
52
53 // The height of the text filtering textbox.
54 const int kTextFilterHeight = 40;
55
56 // The margin at the bottom to make sure the text filter layer is hidden.
57 // This is needed because positioning the text filter directly touching the top
58 // edge of the screen still allows the shadow to peek through.
59 const int kTextFieldBottomMargin = 2;
60
61 // Distance from top of overview to the top of text filtering textbox as a
62 // proportion of the total overview area.
63 const float kTextFilterTopScreenProportion = 0.02f;
64
65 // Width of the text filter area.
66 const int kTextFilterWidth = 280;
67
68 // The font style used for text filtering textbox.
69 static const ui::ResourceBundle::FontStyle kTextFilterFontStyle =
70 ui::ResourceBundle::FontStyle::BaseFont;
71
72 // The color of the text and its background in the text filtering textbox.
73 const SkColor kTextFilterTextColor = SkColorSetARGB(222, 0, 0, 0);
74 const SkColor kTextFilterBackgroundColor = SK_ColorWHITE;
75
76 // The color or search icon.
77 const SkColor kTextFilterIconColor = SkColorSetARGB(138, 0, 0, 0);
78
79 // The size of search icon.
80 const int kTextFilterIconSize = 20;
81
82 // The radius used for the rounded corners on the text filtering textbox.
83 const int kTextFilterCornerRadius = 2;
84
85 // A comparator for locating a selector item for a given root.
86 struct WindowSelectorItemForRoot {
87 explicit WindowSelectorItemForRoot(const WmWindow* root)
88 : root_window(root) {}
89
90 bool operator()(WindowSelectorItem* item) const {
91 return item->root_window() == root_window;
92 }
93
94 const WmWindow* root_window;
95 };
96
97 // A View having rounded corners and a specified background color which is
98 // only painted within the bounds defined by the rounded corners.
99 // TODO(tdanderson): This duplicates code from RoundedImageView. Refactor these
100 // classes and move into ui/views.
101 class RoundedContainerView : public views::View {
102 public:
103 RoundedContainerView(int corner_radius, SkColor background)
104 : corner_radius_(corner_radius), background_(background) {}
105
106 ~RoundedContainerView() override {}
107
108 void OnPaint(gfx::Canvas* canvas) override {
109 views::View::OnPaint(canvas);
110
111 SkScalar radius = SkIntToScalar(corner_radius_);
112 const SkScalar kRadius[8] = {radius, radius, radius, radius,
113 radius, radius, radius, radius};
114 SkPath path;
115 gfx::Rect bounds(size());
116 path.addRoundRect(gfx::RectToSkRect(bounds), kRadius);
117
118 canvas->ClipPath(path, true);
119 canvas->DrawColor(background_);
120 }
121
122 private:
123 int corner_radius_;
124 SkColor background_;
125
126 DISALLOW_COPY_AND_ASSIGN(RoundedContainerView);
127 };
128
129 // Triggers a shelf visibility update on all root window controllers.
130 void UpdateShelfVisibility() {
131 for (WmWindow* root : WmShell::Get()->GetAllRootWindows())
132 WmShelf::ForWindow(root)->UpdateVisibilityState();
133 }
134
135 gfx::Rect GetTextFilterPosition(WmWindow* root_window) {
136 gfx::Rect total_bounds = root_window->ConvertRectToScreen(
137 wm::GetDisplayWorkAreaBoundsInParent(root_window->GetChildByShellWindowId(
138 kShellWindowId_DefaultContainer)));
139 return gfx::Rect(
140 0.5 * (total_bounds.width() -
141 std::min(kTextFilterWidth, total_bounds.width())),
142 total_bounds.y() + total_bounds.height() * kTextFilterTopScreenProportion,
143 std::min(kTextFilterWidth, total_bounds.width()), kTextFilterHeight);
144 }
145
146 // Initializes the text filter on the top of the main root window and requests
147 // focus on its textfield. Uses |image| to place an icon to the left of the text
148 // field.
149 views::Widget* CreateTextFilter(views::TextfieldController* controller,
150 WmWindow* root_window,
151 const gfx::ImageSkia& image,
152 int* text_filter_bottom) {
153 views::Widget* widget = new views::Widget;
154 views::Widget::InitParams params;
155 params.type = views::Widget::InitParams::TYPE_WINDOW_FRAMELESS;
156 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
157 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
158 params.accept_events = true;
159 params.bounds = GetTextFilterPosition(root_window);
160 params.name = "OverviewModeTextFilter";
161 *text_filter_bottom = params.bounds.bottom() + kTextFieldBottomMargin;
162 root_window->GetRootWindowController()->ConfigureWidgetInitParamsForContainer(
163 widget, kShellWindowId_StatusContainer, &params);
164 widget->Init(params);
165
166 // Use |container| to specify the padding surrounding the text and to give
167 // the textfield rounded corners.
168 views::View* container = new RoundedContainerView(kTextFilterCornerRadius,
169 kTextFilterBackgroundColor);
170 ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance();
171 const int text_height =
172 std::max(kTextFilterIconSize,
173 bundle.GetFontList(kTextFilterFontStyle).GetHeight());
174 DCHECK(text_height);
175 const int vertical_padding = (params.bounds.height() - text_height) / 2;
176 views::BoxLayout* layout = new views::BoxLayout(
177 views::BoxLayout::kHorizontal, kTextFilterHorizontalPadding,
178 vertical_padding, kTextFilterHorizontalPadding);
179 container->SetLayoutManager(layout);
180
181 views::Textfield* textfield = new views::Textfield;
182 textfield->set_controller(controller);
183 textfield->SetBorder(views::NullBorder());
184 textfield->SetBackgroundColor(kTextFilterBackgroundColor);
185 textfield->SetTextColor(kTextFilterTextColor);
186 views::ImageView* image_view = new views::ImageView;
187 image_view->SetImage(image);
188 container->AddChildView(image_view);
189 textfield->SetFontList(bundle.GetFontList(kTextFilterFontStyle));
190 container->AddChildView(textfield);
191 layout->SetFlexForView(textfield, 1);
192 widget->SetContentsView(container);
193
194 // The textfield initially contains no text, so shift its position to be
195 // outside the visible bounds of the screen.
196 gfx::Transform transform;
197 transform.Translate(0, -(*text_filter_bottom));
198 WmWindow* text_filter_widget_window =
199 WmWindow::Get(widget->GetNativeWindow());
200 text_filter_widget_window->SetOpacity(0);
201 text_filter_widget_window->SetTransform(transform);
202 widget->Show();
203 textfield->RequestFocus();
204
205 return widget;
206 }
207
208 } // namespace
209
210 // static
211 bool WindowSelector::IsSelectable(WmWindow* window) {
212 wm::WindowState* state = window->GetWindowState();
213 return state->IsUserPositionable();
214 }
215
216 WindowSelector::WindowSelector(WindowSelectorDelegate* delegate)
217 : delegate_(delegate),
218 restore_focus_window_(WmShell::Get()->GetFocusedWindow()),
219 ignore_activations_(false),
220 selected_grid_index_(0),
221 overview_start_time_(base::Time::Now()),
222 num_key_presses_(0),
223 num_items_(0),
224 showing_text_filter_(false),
225 text_filter_string_length_(0),
226 num_times_textfield_cleared_(0),
227 restoring_minimized_windows_(false),
228 text_filter_bottom_(0) {
229 DCHECK(delegate_);
230 }
231
232 WindowSelector::~WindowSelector() {
233 RemoveAllObservers();
234 }
235
236 // NOTE: The work done in Init() is not done in the constructor because it may
237 // cause other, unrelated classes, (ie PanelLayoutManager) to make indirect
238 // calls to restoring_minimized_windows() on a partially constructed object.
239 void WindowSelector::Init(const WindowList& windows) {
240 if (restore_focus_window_)
241 restore_focus_window_->aura_window()->AddObserver(this);
242
243 WmShell* shell = WmShell::Get();
244
245 std::vector<WmWindow*> root_windows = shell->GetAllRootWindows();
246 std::sort(root_windows.begin(), root_windows.end(),
247 [](const WmWindow* a, const WmWindow* b) {
248 // Since we don't know if windows are vertically or horizontally
249 // oriented we use both x and y position. This may be confusing
250 // if you have 3 or more monitors which are not strictly
251 // horizontal or vertical but that case is not yet supported.
252 return (a->GetBoundsInScreen().x() + a->GetBoundsInScreen().y()) <
253 (b->GetBoundsInScreen().x() + b->GetBoundsInScreen().y());
254 });
255
256 for (WmWindow* root : root_windows) {
257 // Observed switchable containers for newly created windows on all root
258 // windows.
259 for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) {
260 WmWindow* container =
261 root->GetChildByShellWindowId(wm::kSwitchableWindowContainerIds[i]);
262 container->aura_window()->AddObserver(this);
263 observed_windows_.insert(container);
264 }
265
266 // Hide the callout widgets for panels. It is safe to call this for
267 // root windows that don't contain any panel windows.
268 PanelLayoutManager::Get(root)->SetShowCalloutWidgets(false);
269
270 std::unique_ptr<WindowGrid> grid(new WindowGrid(root, windows, this));
271 if (grid->empty())
272 continue;
273 num_items_ += grid->size();
274 grid_list_.push_back(std::move(grid));
275 }
276
277 {
278 // The calls to WindowGrid::PrepareForOverview() and CreateTextFilter(...)
279 // requires some LayoutManagers (ie PanelLayoutManager) to perform layouts
280 // so that windows are correctly visible and properly animated in overview
281 // mode. Otherwise these layouts should be suppressed during overview mode
282 // so they don't conflict with overview mode animations. The
283 // |restoring_minimized_windows_| flag enables the PanelLayoutManager to
284 // make this decision.
285 base::AutoReset<bool> auto_restoring_minimized_windows(
286 &restoring_minimized_windows_, true);
287
288 // Do not call PrepareForOverview until all items are added to window_list_
289 // as we don't want to cause any window updates until all windows in
290 // overview are observed. See http://crbug.com/384495.
291 for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) {
292 window_grid->PrepareForOverview();
293 window_grid->PositionWindows(true);
294 }
295
296 search_image_ =
297 gfx::CreateVectorIcon(gfx::VectorIconId::OMNIBOX_SEARCH,
298 kTextFilterIconSize, kTextFilterIconColor);
299 WmWindow* root_window = shell->GetPrimaryRootWindow();
300 text_filter_widget_.reset(CreateTextFilter(this, root_window, search_image_,
301 &text_filter_bottom_));
302 }
303
304 DCHECK(!grid_list_.empty());
305 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.Items", num_items_);
306
307 shell->AddActivationObserver(this);
308
309 display::Screen::GetScreen()->AddObserver(this);
310 shell->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW);
311 // Send an a11y alert.
312 WmShell::Get()->accessibility_delegate()->TriggerAccessibilityAlert(
313 A11Y_ALERT_WINDOW_OVERVIEW_MODE_ENTERED);
314
315 UpdateShelfVisibility();
316 }
317
318 // NOTE: The work done in Shutdown() is not done in the destructor because it
319 // may cause other, unrelated classes, (ie PanelLayoutManager) to make indirect
320 // calls to restoring_minimized_windows() on a partially destructed object.
321 void WindowSelector::Shutdown() {
322 is_shut_down_ = true;
323 // Stop observing screen metrics changes first to avoid auto-positioning
324 // windows in response to work area changes from window activation.
325 display::Screen::GetScreen()->RemoveObserver(this);
326
327 size_t remaining_items = 0;
328 for (std::unique_ptr<WindowGrid>& window_grid : grid_list_) {
329 for (const auto& window_selector_item : window_grid->window_list())
330 window_selector_item->RestoreWindow();
331 remaining_items += window_grid->size();
332 }
333
334 // Setting focus after restoring windows' state avoids unnecessary animations.
335 ResetFocusRestoreWindow(true);
336 RemoveAllObservers();
337
338 std::vector<WmWindow*> root_windows = WmShell::Get()->GetAllRootWindows();
339 for (WmWindow* window : root_windows) {
340 // Un-hide the callout widgets for panels. It is safe to call this for
341 // root_windows that don't contain any panel windows.
342 PanelLayoutManager::Get(window)->SetShowCalloutWidgets(true);
343 }
344
345 for (std::unique_ptr<WindowGrid>& window_grid : grid_list_)
346 window_grid->Shutdown();
347
348 DCHECK(num_items_ >= remaining_items);
349 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.OverviewClosedItems",
350 num_items_ - remaining_items);
351 UMA_HISTOGRAM_MEDIUM_TIMES("Ash.WindowSelector.TimeInOverview",
352 base::Time::Now() - overview_start_time_);
353
354 // Record metrics related to text filtering.
355 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringStringLength",
356 text_filter_string_length_);
357 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.TextFilteringTextfieldCleared",
358 num_times_textfield_cleared_);
359 if (text_filter_string_length_) {
360 UMA_HISTOGRAM_MEDIUM_TIMES(
361 "Ash.WindowSelector.TimeInOverviewWithTextFiltering",
362 base::Time::Now() - overview_start_time_);
363 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.ItemsWhenTextFilteringUsed",
364 remaining_items);
365 }
366
367 // Clearing the window list resets the ignored_by_shelf flag on the windows.
368 grid_list_.clear();
369 UpdateShelfVisibility();
370 }
371
372 void WindowSelector::RemoveAllObservers() {
373 for (WmWindow* window : observed_windows_)
374 window->aura_window()->RemoveObserver(this);
375
376 WmShell::Get()->RemoveActivationObserver(this);
377 display::Screen::GetScreen()->RemoveObserver(this);
378 if (restore_focus_window_)
379 restore_focus_window_->aura_window()->RemoveObserver(this);
380 }
381
382 void WindowSelector::CancelSelection() {
383 delegate_->OnSelectionEnded();
384 }
385
386 void WindowSelector::OnGridEmpty(WindowGrid* grid) {
387 size_t index = 0;
388 for (auto iter = grid_list_.begin(); iter != grid_list_.end(); ++iter) {
389 if (grid == (*iter).get()) {
390 index = iter - grid_list_.begin();
391 grid_list_.erase(iter);
392 break;
393 }
394 }
395 if (index > 0 && selected_grid_index_ >= index) {
396 selected_grid_index_--;
397 // If the grid which became empty was the one with the selected window, we
398 // need to select a window on the newly selected grid.
399 if (selected_grid_index_ == index - 1)
400 Move(LEFT, true);
401 }
402 if (grid_list_.empty())
403 CancelSelection();
404 }
405
406 void WindowSelector::IncrementSelection(int increment) {
407 const Direction direction =
408 increment > 0 ? WindowSelector::RIGHT : WindowSelector::LEFT;
409 for (int step = 0; step < abs(increment); ++step)
410 Move(direction, true);
411 }
412
413 bool WindowSelector::AcceptSelection() {
414 if (!grid_list_[selected_grid_index_]->is_selecting())
415 return false;
416 SelectWindow(grid_list_[selected_grid_index_]->SelectedWindow());
417 return true;
418 }
419
420 void WindowSelector::SelectWindow(WindowSelectorItem* item) {
421 WmWindow* window = item->GetWindow();
422 std::vector<WmWindow*> window_list =
423 WmShell::Get()->mru_window_tracker()->BuildMruWindowList();
424 if (!window_list.empty()) {
425 // Record UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED if the user is selecting
426 // a window other than the window that was active prior to entering overview
427 // mode (i.e., the window at the front of the MRU list).
428 if (window_list[0] != window) {
429 WmShell::Get()->RecordUserMetricsAction(
430 UMA_WINDOW_OVERVIEW_ACTIVE_WINDOW_CHANGED);
431 }
432 const auto it = std::find(window_list.begin(), window_list.end(), window);
433 if (it != window_list.end()) {
434 // Record 1-based index so that selecting a top MRU window will record 1.
435 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.SelectionDepth",
436 1 + it - window_list.begin());
437 }
438 }
439 item->EnsureVisible();
440 window->GetWindowState()->Activate();
441 }
442
443 void WindowSelector::WindowClosing(WindowSelectorItem* window) {
444 grid_list_[selected_grid_index_]->WindowClosing(window);
445 }
446
447 bool WindowSelector::HandleKeyEvent(views::Textfield* sender,
448 const ui::KeyEvent& key_event) {
449 if (key_event.type() != ui::ET_KEY_PRESSED)
450 return false;
451
452 switch (key_event.key_code()) {
453 case ui::VKEY_ESCAPE:
454 CancelSelection();
455 break;
456 case ui::VKEY_UP:
457 num_key_presses_++;
458 Move(WindowSelector::UP, true);
459 break;
460 case ui::VKEY_DOWN:
461 num_key_presses_++;
462 Move(WindowSelector::DOWN, true);
463 break;
464 case ui::VKEY_RIGHT:
465 case ui::VKEY_TAB:
466 if (key_event.key_code() == ui::VKEY_RIGHT ||
467 !(key_event.flags() & ui::EF_SHIFT_DOWN)) {
468 num_key_presses_++;
469 Move(WindowSelector::RIGHT, true);
470 break;
471 }
472 case ui::VKEY_LEFT:
473 num_key_presses_++;
474 Move(WindowSelector::LEFT, true);
475 break;
476 case ui::VKEY_W:
477 if (!(key_event.flags() & ui::EF_CONTROL_DOWN) ||
478 !grid_list_[selected_grid_index_]->is_selecting()) {
479 // Allow the textfield to handle 'W' key when not used with Ctrl.
480 return false;
481 }
482 WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_CLOSE_KEY);
483 grid_list_[selected_grid_index_]->SelectedWindow()->CloseWindow();
484 break;
485 case ui::VKEY_RETURN:
486 // Ignore if no item is selected.
487 if (!grid_list_[selected_grid_index_]->is_selecting())
488 return false;
489 UMA_HISTOGRAM_COUNTS_100("Ash.WindowSelector.ArrowKeyPresses",
490 num_key_presses_);
491 UMA_HISTOGRAM_CUSTOM_COUNTS("Ash.WindowSelector.KeyPressesOverItemsRatio",
492 (num_key_presses_ * 100) / num_items_, 1, 300,
493 30);
494 WmShell::Get()->RecordUserMetricsAction(UMA_WINDOW_OVERVIEW_ENTER_KEY);
495 SelectWindow(grid_list_[selected_grid_index_]->SelectedWindow());
496 break;
497 default:
498 // Not a key we are interested in, allow the textfield to handle it.
499 return false;
500 }
501 return true;
502 }
503
504 void WindowSelector::OnDisplayAdded(const display::Display& display) {}
505
506 void WindowSelector::OnDisplayRemoved(const display::Display& display) {
507 // TODO(flackr): Keep window selection active on remaining displays.
508 CancelSelection();
509 }
510
511 void WindowSelector::OnDisplayMetricsChanged(const display::Display& display,
512 uint32_t metrics) {
513 PositionWindows(/* animate */ false);
514 RepositionTextFilterOnDisplayMetricsChange();
515 }
516
517 void WindowSelector::OnWindowHierarchyChanged(
518 const HierarchyChangeParams& params) {
519 // Only care about newly added children of |observed_windows_|.
520 if (!observed_windows_.count(WmWindow::Get(params.receiver)) ||
521 !observed_windows_.count(WmWindow::Get(params.new_parent))) {
522 return;
523 }
524
525 WmWindow* new_window = WmWindow::Get(params.target);
526 if (!IsSelectable(new_window))
527 return;
528
529 for (size_t i = 0; i < wm::kSwitchableWindowContainerIdsLength; ++i) {
530 if (new_window->GetParent()->GetShellWindowId() ==
531 wm::kSwitchableWindowContainerIds[i] &&
532 !new_window->GetTransientParent()) {
533 // The new window is in one of the switchable containers, abort overview.
534 CancelSelection();
535 return;
536 }
537 }
538 }
539
540 void WindowSelector::OnWindowDestroying(aura::Window* window) {
541 window->RemoveObserver(this);
542 observed_windows_.erase(WmWindow::Get(window));
543 if (WmWindow::Get(window) == restore_focus_window_)
544 restore_focus_window_ = nullptr;
545 }
546
547 void WindowSelector::OnWindowActivated(WmWindow* gained_active,
548 WmWindow* lost_active) {
549 if (ignore_activations_ || !gained_active ||
550 gained_active == GetTextFilterWidgetWindow()) {
551 return;
552 }
553
554 WmWindow* root_window = gained_active->GetRootWindow();
555 auto grid =
556 std::find_if(grid_list_.begin(), grid_list_.end(),
557 [root_window](const std::unique_ptr<WindowGrid>& grid) {
558 return grid->root_window() == root_window;
559 });
560 if (grid == grid_list_.end())
561 return;
562 const auto& windows = (*grid)->window_list();
563
564 auto iter = std::find_if(
565 windows.begin(), windows.end(),
566 [gained_active](const std::unique_ptr<WindowSelectorItem>& window) {
567 return window->Contains(gained_active);
568 });
569
570 if (iter == windows.end() && showing_text_filter_ &&
571 lost_active == GetTextFilterWidgetWindow()) {
572 return;
573 }
574
575 // Don't restore focus on exit if a window was just activated.
576 ResetFocusRestoreWindow(false);
577 CancelSelection();
578 }
579
580 void WindowSelector::OnAttemptToReactivateWindow(WmWindow* request_active,
581 WmWindow* actual_active) {
582 OnWindowActivated(request_active, actual_active);
583 }
584
585 void WindowSelector::ContentsChanged(views::Textfield* sender,
586 const base::string16& new_contents) {
587 text_filter_string_length_ = new_contents.length();
588 if (!text_filter_string_length_)
589 num_times_textfield_cleared_++;
590
591 bool should_show_text_filter = !new_contents.empty();
592 if (showing_text_filter_ != should_show_text_filter) {
593 WmWindow* text_filter_widget_window = GetTextFilterWidgetWindow();
594 ui::ScopedLayerAnimationSettings animation_settings(
595 text_filter_widget_window->GetLayer()->GetAnimator());
596 animation_settings.SetPreemptionStrategy(
597 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
598 animation_settings.SetTweenType(showing_text_filter_
599 ? gfx::Tween::FAST_OUT_LINEAR_IN
600 : gfx::Tween::LINEAR_OUT_SLOW_IN);
601
602 gfx::Transform transform;
603 if (should_show_text_filter) {
604 transform.Translate(0, 0);
605 text_filter_widget_window->SetOpacity(1);
606 } else {
607 transform.Translate(0, -text_filter_bottom_);
608 text_filter_widget_window->SetOpacity(0);
609 }
610
611 text_filter_widget_window->SetTransform(transform);
612 showing_text_filter_ = should_show_text_filter;
613 }
614 for (auto iter = grid_list_.begin(); iter != grid_list_.end(); iter++)
615 (*iter)->FilterItems(new_contents);
616
617 // If the selection widget is not active, execute a Move() command so that it
618 // shows up on the first undimmed item.
619 if (grid_list_[selected_grid_index_]->is_selecting())
620 return;
621 Move(WindowSelector::RIGHT, false);
622 }
623
624 WmWindow* WindowSelector::GetTextFilterWidgetWindow() {
625 return WmWindow::Get(text_filter_widget_->GetNativeWindow());
626 }
627
628 void WindowSelector::PositionWindows(bool animate) {
629 for (std::unique_ptr<WindowGrid>& grid : grid_list_)
630 grid->PositionWindows(animate);
631 }
632
633 void WindowSelector::RepositionTextFilterOnDisplayMetricsChange() {
634 WmWindow* root_window = WmShell::Get()->GetPrimaryRootWindow();
635 const gfx::Rect rect = GetTextFilterPosition(root_window);
636 text_filter_bottom_ = rect.bottom() + kTextFieldBottomMargin;
637 text_filter_widget_->SetBounds(rect);
638
639 gfx::Transform transform;
640 transform.Translate(
641 0, text_filter_string_length_ == 0 ? -text_filter_bottom_ : 0);
642 WmWindow* text_filter_window = GetTextFilterWidgetWindow();
643 text_filter_window->SetOpacity(text_filter_string_length_ == 0 ? 0 : 1);
644 text_filter_window->SetTransform(transform);
645 }
646
647 void WindowSelector::ResetFocusRestoreWindow(bool focus) {
648 if (!restore_focus_window_)
649 return;
650 if (focus) {
651 base::AutoReset<bool> restoring_focus(&ignore_activations_, true);
652 restore_focus_window_->Activate();
653 }
654 // If the window is in the observed_windows_ list it needs to continue to be
655 // observed.
656 if (observed_windows_.find(restore_focus_window_) ==
657 observed_windows_.end()) {
658 restore_focus_window_->aura_window()->RemoveObserver(this);
659 }
660 restore_focus_window_ = nullptr;
661 }
662
663 void WindowSelector::Move(Direction direction, bool animate) {
664 // Direction to move if moving past the end of a display.
665 int display_direction = (direction == RIGHT || direction == DOWN) ? 1 : -1;
666
667 // If this is the first move and it's going backwards, start on the last
668 // display.
669 if (display_direction == -1 && !grid_list_.empty() &&
670 !grid_list_[selected_grid_index_]->is_selecting()) {
671 selected_grid_index_ = grid_list_.size() - 1;
672 }
673
674 // Keep calling Move() on the grids until one of them reports no overflow or
675 // we made a full cycle on all the grids.
676 for (size_t i = 0; i <= grid_list_.size() &&
677 grid_list_[selected_grid_index_]->Move(direction, animate);
678 i++) {
679 selected_grid_index_ =
680 (selected_grid_index_ + display_direction + grid_list_.size()) %
681 grid_list_.size();
682 }
683 }
684
685 } // namespace ash
OLDNEW
« no previous file with comments | « ash/common/wm/overview/window_selector.h ('k') | ash/common/wm/overview/window_selector_controller.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698