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

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

Issue 22929034: Relocate and refactor overview mode files. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add class comment. Created 7 years, 4 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 | Annotate | Revision Log
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/wm/overview/window_selector.h"
6
7 #include <algorithm>
8
9 #include "ash/screen_ash.h"
10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h"
12 #include "ash/wm/overview/window_selector_delegate.h"
13 #include "ash/wm/overview/window_selector_window.h"
14 #include "ash/wm/window_util.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "third_party/skia/include/core/SkColor.h"
17 #include "ui/aura/root_window.h"
18 #include "ui/aura/window.h"
19 #include "ui/base/events/event.h"
20 #include "ui/compositor/scoped_layer_animation_settings.h"
21 #include "ui/views/widget/widget.h"
22
23 namespace ash {
24
25 namespace {
26
27 const float kCardAspectRatio = 4.0f / 3.0f;
28 const int kWindowMargin = 30;
29 const int kMinCardsMajor = 3;
30 const int kOverviewSelectorTransitionMilliseconds = 100;
31 const SkColor kWindowSelectorSelectionColor = SK_ColorBLACK;
32 const float kWindowSelectorSelectionOpacity = 0.5f;
33 const int kWindowSelectorSelectionPadding = 15;
34
35 // A comparator for locating a given target window.
36 struct WindowSelectorWindowComparator
37 : public std::unary_function<WindowSelectorWindow*, bool> {
38 explicit WindowSelectorWindowComparator(const aura::Window* target_window)
39 : target(target_window) {
40 }
41
42 bool operator()(const WindowSelectorWindow* window) const {
43 return target == window->window();
44 }
45
46 const aura::Window* target;
47 };
48
49 } // namespace
50
51 WindowSelector::WindowSelector(const WindowList& windows,
52 WindowSelector::Mode mode,
53 WindowSelectorDelegate* delegate)
54 : mode_(mode),
55 delegate_(delegate),
56 selected_window_(0),
57 selection_root_(NULL) {
58 DCHECK(delegate_);
59 for (size_t i = 0; i < windows.size(); ++i) {
60 windows[i]->AddObserver(this);
61 windows_.push_back(new WindowSelectorWindow(windows[i]));
62 }
63 if (mode == WindowSelector::CYCLE)
64 selection_root_ = ash::Shell::GetActiveRootWindow();
65 PositionWindows();
66 ash::Shell::GetInstance()->AddPreTargetHandler(this);
67 }
68
69 WindowSelector::~WindowSelector() {
70 for (size_t i = 0; i < windows_.size(); i++) {
71 windows_[i]->window()->RemoveObserver(this);
72 }
73 ash::Shell::GetInstance()->RemovePreTargetHandler(this);
74 }
75
76 void WindowSelector::Step(WindowSelector::Direction direction) {
77 DCHECK(windows_.size() > 0);
78 if (!selection_widget_)
79 InitializeSelectionWidget();
80 selected_window_ = (selected_window_ + windows_.size() +
81 (direction == WindowSelector::FORWARD ? 1 : -1)) % windows_.size();
82 UpdateSelectionLocation(true);
83 }
84
85 void WindowSelector::SelectWindow() {
86 delegate_->OnWindowSelected(windows_[selected_window_]->window());
87 }
88
89 void WindowSelector::OnEvent(ui::Event* event) {
90 // If the event is targetted at any of the windows in the overview, then
91 // prevent it from propagating.
92 aura::Window* target = static_cast<aura::Window*>(event->target());
93 for (size_t i = 0; i < windows_.size(); ++i) {
94 if (windows_[i]->Contains(target)) {
95 // TODO(flackr): StopPropogation prevents generation of gesture events.
96 // We should find a better way to prevent events from being delivered to
97 // the window, perhaps a transparent window in front of the target window
98 // or using EventClientImpl::CanProcessEventsWithinSubtree.
99 event->StopPropagation();
100 break;
101 }
102 }
103
104 // This object may not be valid after this call as a selection event can
105 // trigger deletion of the window selector.
106 ui::EventHandler::OnEvent(event);
107 }
108
109 void WindowSelector::OnMouseEvent(ui::MouseEvent* event) {
110 if (event->type() != ui::ET_MOUSE_RELEASED)
111 return;
112 WindowSelectorWindow* target = GetEventTarget(event);
113 if (!target)
114 return;
115
116 HandleSelectionEvent(target);
117 }
118
119 void WindowSelector::OnTouchEvent(ui::TouchEvent* event) {
120 if (event->type() != ui::ET_TOUCH_PRESSED)
121 return;
122 WindowSelectorWindow* target = GetEventTarget(event);
123 if (!target)
124 return;
125
126 HandleSelectionEvent(target);
127 }
128
129 void WindowSelector::OnWindowDestroyed(aura::Window* window) {
130 ScopedVector<WindowSelectorWindow>::iterator iter =
131 std::find_if(windows_.begin(), windows_.end(),
132 WindowSelectorWindowComparator(window));
133 DCHECK(iter != windows_.end());
134 size_t deleted_index = iter - windows_.begin();
135 (*iter)->OnWindowDestroyed();
136 windows_.erase(iter);
137 if (windows_.empty()) {
138 delegate_->OnSelectionCanceled();
139 return;
140 }
141 if (selected_window_ >= deleted_index) {
142 if (selected_window_ > deleted_index)
143 selected_window_--;
144 selected_window_ = selected_window_ % windows_.size();
145 UpdateSelectionLocation(true);
146 }
147
148 PositionWindows();
149 }
150
151 WindowSelectorWindow* WindowSelector::GetEventTarget(ui::LocatedEvent* event) {
152 aura::Window* target = static_cast<aura::Window*>(event->target());
153 // If the target window doesn't actually contain the event location (i.e.
154 // mouse down over the window and mouse up elsewhere) then do not select the
155 // window.
156 if (!target->HitTest(event->location()))
157 return NULL;
158
159 for (size_t i = 0; i < windows_.size(); i++) {
160 if (windows_[i]->Contains(target))
161 return windows_[i];
162 }
163 return NULL;
164 }
165
166 void WindowSelector::HandleSelectionEvent(WindowSelectorWindow* target) {
167 // The selected window should not be minimized when window selection is
168 // ended.
169 target->RestoreWindowOnExit();
170 delegate_->OnWindowSelected(target->window());
171 }
172
173 void WindowSelector::PositionWindows() {
174 if (selection_root_) {
175 DCHECK_EQ(mode_, CYCLE);
176 std::vector<WindowSelectorWindow*> windows;
177 for (size_t i = 0; i < windows_.size(); ++i)
178 windows.push_back(windows_[i]);
179 PositionWindowsOnRoot(selection_root_, windows);
180 } else {
181 DCHECK_EQ(mode_, OVERVIEW);
182 Shell::RootWindowList root_window_list = Shell::GetAllRootWindows();
183 for (size_t i = 0; i < root_window_list.size(); ++i)
184 PositionWindowsFromRoot(root_window_list[i]);
185 }
186 }
187
188 void WindowSelector::PositionWindowsFromRoot(aura::RootWindow* root_window) {
189 std::vector<WindowSelectorWindow*> windows;
190 for (size_t i = 0; i < windows_.size(); ++i) {
191 if (windows_[i]->window()->GetRootWindow() == root_window)
192 windows.push_back(windows_[i]);
193 }
194 PositionWindowsOnRoot(root_window, windows);
195 }
196
197 void WindowSelector::PositionWindowsOnRoot(
198 aura::RootWindow* root_window,
199 const std::vector<WindowSelectorWindow*>& windows) {
200 if (windows.empty())
201 return;
202
203 gfx::Size window_size;
204 gfx::Rect total_bounds = ScreenAsh::ConvertRectToScreen(root_window,
205 ScreenAsh::GetDisplayWorkAreaBoundsInParent(
206 Shell::GetContainer(root_window,
207 internal::kShellWindowId_DefaultContainer)));
208
209 // Find the minimum number of windows per row that will fit all of the
210 // windows on screen.
211 size_t columns = std::max(
212 total_bounds.width() > total_bounds.height() ? kMinCardsMajor : 1,
213 static_cast<int>(ceil(sqrt(total_bounds.width() * windows.size() /
214 (kCardAspectRatio * total_bounds.height())))));
215 size_t rows = ((windows.size() + columns - 1) / columns);
216 window_size.set_width(std::min(
217 static_cast<int>(total_bounds.width() / columns),
218 static_cast<int>(total_bounds.height() * kCardAspectRatio / rows)));
219 window_size.set_height(window_size.width() / kCardAspectRatio);
220
221 // Calculate the X and Y offsets necessary to center the grid.
222 int x_offset = total_bounds.x() + ((windows.size() >= columns ? 0 :
223 (columns - windows.size()) * window_size.width()) +
224 (total_bounds.width() - columns * window_size.width())) / 2;
225 int y_offset = total_bounds.y() + (total_bounds.height() -
226 rows * window_size.height()) / 2;
227 for (size_t i = 0; i < windows.size(); ++i) {
228 gfx::Transform transform;
229 int column = i % columns;
230 int row = i / columns;
231 gfx::Rect target_bounds(window_size.width() * column + x_offset,
232 window_size.height() * row + y_offset,
233 window_size.width(),
234 window_size.height());
235 target_bounds.Inset(kWindowMargin, kWindowMargin);
236 windows[i]->TransformToFitBounds(root_window, target_bounds);
237 }
238 }
239
240 void WindowSelector::InitializeSelectionWidget() {
241 selection_widget_.reset(new views::Widget);
242 views::Widget::InitParams params;
243 params.type = views::Widget::InitParams::TYPE_POPUP;
244 params.can_activate = false;
245 params.keep_on_top = false;
246 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
247 params.opacity = views::Widget::InitParams::OPAQUE_WINDOW;
248 params.parent = Shell::GetContainer(
249 selection_root_,
250 internal::kShellWindowId_DefaultContainer);
251 params.accept_events = false;
252 selection_widget_->set_focus_on_creation(false);
253 selection_widget_->Init(params);
254 views::View* content_view = new views::View;
255 content_view->set_background(
256 views::Background::CreateSolidBackground(kWindowSelectorSelectionColor));
257 selection_widget_->SetContentsView(content_view);
258 UpdateSelectionLocation(false);
259 selection_widget_->GetNativeWindow()->parent()->StackChildAtBottom(
260 selection_widget_->GetNativeWindow());
261 selection_widget_->Show();
262 selection_widget_->GetNativeWindow()->layer()->SetOpacity(
263 kWindowSelectorSelectionOpacity);
264 }
265
266 void WindowSelector::UpdateSelectionLocation(bool animate) {
267 if (!selection_widget_)
268 return;
269 gfx::Rect target_bounds = windows_[selected_window_]->bounds();
270 target_bounds.Inset(-kWindowSelectorSelectionPadding,
271 -kWindowSelectorSelectionPadding);
272 if (animate) {
273 ui::ScopedLayerAnimationSettings animation_settings(
274 selection_widget_->GetNativeWindow()->layer()->GetAnimator());
275 animation_settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
276 kOverviewSelectorTransitionMilliseconds));
277 animation_settings.SetPreemptionStrategy(
278 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
279 selection_widget_->SetBounds(target_bounds);
280 } else {
281 selection_widget_->SetBounds(target_bounds);
282 }
283 }
284
285 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698