OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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 "ui/touch_selection/touch_selection_controller_aura.h" | |
6 | |
7 #include "ui/aura/client/cursor_client.h" | |
8 #include "ui/aura/client/screen_position_client.h" | |
9 #include "ui/aura/env.h" | |
10 #include "ui/aura/window.h" | |
11 #include "ui/events/event.h" | |
12 #include "ui/events/gesture_detection/gesture_configuration.h" | |
13 #include "ui/events/gestures/motion_event_aura.h" | |
14 #include "ui/touch_selection/touch_handle_drawable_aura.h" | |
15 #include "ui/touch_selection/touch_selection_controller_aura_test_api.h" | |
16 | |
17 namespace ui { | |
18 namespace { | |
19 | |
20 gfx::Rect ConvertRectToScreen(aura::Window* window, const gfx::Rect& rect) { | |
21 gfx::Point origin = rect.origin(); | |
22 gfx::Point end = gfx::Point(rect.right(), rect.bottom()); | |
23 | |
24 aura::Window* root_window = window->GetRootWindow(); | |
25 if (!root_window) | |
26 return rect; | |
27 aura::client::ScreenPositionClient* screen_position_client = | |
28 aura::client::GetScreenPositionClient(root_window); | |
29 if (!screen_position_client) | |
30 return rect; | |
31 screen_position_client->ConvertPointToScreen(window, &origin); | |
32 screen_position_client->ConvertPointToScreen(window, &end); | |
33 return gfx::Rect(origin.x(), origin.y(), end.x() - origin.x(), | |
34 end.y() - origin.y()); | |
35 } | |
36 | |
37 void ClipPoint(gfx::PointF* point, const gfx::Rect& clip_rect) { | |
38 point->SetToMax(clip_rect.origin()); | |
39 point->SetToMin(clip_rect.bottom_right()); | |
40 } | |
41 | |
42 void ClipSelectionBound(SelectionBound* bound, const gfx::Rect& clip_rect) { | |
43 gfx::PointF edge_top = bound->edge_top(); | |
44 gfx::PointF edge_bottom = bound->edge_bottom(); | |
45 ClipPoint(&edge_top, clip_rect); | |
46 ClipPoint(&edge_bottom, clip_rect); | |
47 bound->SetEdge(edge_top, edge_bottom); | |
48 } | |
49 | |
50 } // namespace | |
51 | |
52 class TouchSelectionControllerAura::EnvPreTargetHandler : public EventHandler { | |
53 public: | |
54 EnvPreTargetHandler(TouchSelectionControllerAura* selection_controller); | |
55 ~EnvPreTargetHandler() override; | |
56 | |
57 private: | |
58 // EventHandler: | |
59 void OnKeyEvent(KeyEvent* event) override; | |
60 void OnMouseEvent(MouseEvent* event) override; | |
61 void OnScrollEvent(ScrollEvent* event) override; | |
62 | |
63 TouchSelectionControllerAura* selection_controller_; | |
64 }; | |
65 | |
66 TouchSelectionControllerAura::EnvPreTargetHandler::EnvPreTargetHandler( | |
67 TouchSelectionControllerAura* selection_controller) | |
68 : selection_controller_(selection_controller) { | |
69 aura::Env::GetInstance()->AddPreTargetHandler(this); | |
70 } | |
71 | |
72 TouchSelectionControllerAura::EnvPreTargetHandler::~EnvPreTargetHandler() { | |
73 aura::Env::GetInstance()->RemovePreTargetHandler(this); | |
74 } | |
75 | |
76 void TouchSelectionControllerAura::EnvPreTargetHandler::OnKeyEvent( | |
77 KeyEvent* event) { | |
78 DCHECK(selection_controller_->controller_->is_insertion_active() || | |
79 selection_controller_->controller_->is_selection_active()); | |
80 | |
81 selection_controller_->HideAndDisallowShowingAutomatically(); | |
82 } | |
83 | |
84 void TouchSelectionControllerAura::EnvPreTargetHandler::OnMouseEvent( | |
85 MouseEvent* event) { | |
86 DCHECK(selection_controller_->controller_->is_insertion_active() || | |
87 selection_controller_->controller_->is_selection_active()); | |
88 | |
89 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient( | |
90 selection_controller_->client_->GetParentWindow()->GetRootWindow()); | |
91 if (!cursor_client || cursor_client->IsMouseEventsEnabled()) | |
92 selection_controller_->HideAndDisallowShowingAutomatically(); | |
93 } | |
94 | |
95 void TouchSelectionControllerAura::EnvPreTargetHandler::OnScrollEvent( | |
96 ScrollEvent* event) { | |
97 DCHECK(selection_controller_->controller_->is_insertion_active() || | |
98 selection_controller_->controller_->is_selection_active()); | |
99 | |
100 selection_controller_->HideAndDisallowShowingAutomatically(); | |
101 } | |
102 | |
103 TouchSelectionControllerAura::TouchSelectionControllerAura( | |
104 TouchSelectionControllerAuraClient* client) | |
105 : client_(client), | |
106 motion_event_(new MotionEventAura), | |
107 scroll_in_progress_(false), | |
108 overscroll_in_progress_(false), | |
109 handle_drag_in_progress_(false), | |
110 selection_editable_(false), | |
111 test_api_(nullptr) { | |
112 DCHECK(client); | |
113 int tap_timeout_ms = | |
114 GestureConfiguration::GetInstance()->show_press_delay_in_ms(); | |
115 int touch_slop = | |
116 GestureConfiguration::GetInstance()->max_touch_move_in_pixels_for_click(); | |
117 bool show_on_tap_for_empty_editable = true; | |
118 controller_.reset(new TouchSelectionController( | |
119 this, | |
120 base::TimeDelta::FromMilliseconds(tap_timeout_ms), | |
121 touch_slop, | |
122 show_on_tap_for_empty_editable)); | |
123 client_->GetEventTarget()->AddPreTargetHandler(this); | |
124 } | |
125 | |
126 TouchSelectionControllerAura::~TouchSelectionControllerAura() { | |
127 client_->GetEventTarget()->RemovePreTargetHandler(this); | |
128 } | |
129 | |
130 void TouchSelectionControllerAura::OnSelectionEditable(bool editable) { | |
131 selection_editable_ = editable; | |
132 controller_->OnSelectionEditable(editable); | |
133 UpdateQuickMenu(); | |
134 } | |
135 | |
136 void TouchSelectionControllerAura::OnSelectionEmpty(bool empty) { | |
137 controller_->OnSelectionEmpty(empty); | |
138 UpdateQuickMenu(); | |
139 } | |
140 | |
141 | |
142 void TouchSelectionControllerAura::OnSelectionBoundsUpdated( | |
143 const SelectionBound& start, | |
144 const SelectionBound& end) { | |
145 if (controller_->OnSelectionBoundsUpdated(start, end)) | |
146 UpdateQuickMenu(); | |
147 } | |
148 | |
149 void TouchSelectionControllerAura::HideAndDisallowShowingAutomatically() { | |
150 controller_->HideAndDisallowShowingAutomatically(); | |
151 UpdateQuickMenu(); | |
152 } | |
153 | |
154 void TouchSelectionControllerAura::OnWindowMoved() { | |
155 UpdateQuickMenu(); | |
156 } | |
157 | |
158 void TouchSelectionControllerAura::OnOverscrollStarted() { | |
159 overscroll_in_progress_ = true; | |
160 UpdateQuickMenu(); | |
161 } | |
162 | |
163 void TouchSelectionControllerAura::OnOverscrollCompleted() { | |
164 overscroll_in_progress_ = false; | |
165 UpdateQuickMenu(); | |
166 } | |
167 | |
168 void TouchSelectionControllerAura::OnFlingCompleted() { | |
169 scroll_in_progress_ = false; | |
170 UpdateQuickMenu(); | |
171 } | |
172 | |
173 bool TouchSelectionControllerAura::SupportsAnimation() const { | |
174 return false; | |
175 } | |
176 | |
177 void TouchSelectionControllerAura::SetNeedsAnimate() { | |
178 NOTREACHED(); | |
179 } | |
180 | |
181 void TouchSelectionControllerAura::MoveCaret(const gfx::PointF& position) { | |
182 client_->MoveCaret(position); | |
183 } | |
184 | |
185 void TouchSelectionControllerAura::MoveRangeSelectionExtent( | |
186 const gfx::PointF& extent) { | |
187 client_->MoveRangeSelectionExtent(extent); | |
188 } | |
189 | |
190 void TouchSelectionControllerAura::SelectBetweenCoordinates( | |
191 const gfx::PointF& base, | |
192 const gfx::PointF& extent) { | |
193 client_->SelectBetweenCoordinates(base, extent); | |
194 } | |
195 | |
196 void TouchSelectionControllerAura::OnSelectionEvent( | |
197 SelectionEventType event, | |
198 const gfx::PointF& position) { | |
199 switch (event) { | |
200 case SELECTION_SHOWN: | |
201 UpdateQuickMenu(); | |
202 env_pre_target_handler_.reset(new EnvPreTargetHandler(this)); | |
203 break; | |
204 case SELECTION_CLEARED: | |
205 env_pre_target_handler_.reset(); | |
206 UpdateQuickMenu(); | |
207 break; | |
208 case SELECTION_DRAG_STARTED: | |
209 handle_drag_in_progress_ = true; | |
210 UpdateQuickMenu(); | |
211 break; | |
212 case SELECTION_DRAG_STOPPED: | |
213 handle_drag_in_progress_ = false; | |
214 UpdateQuickMenu(); | |
215 break; | |
216 case INSERTION_SHOWN: | |
217 UpdateQuickMenu(); | |
218 env_pre_target_handler_.reset(new EnvPreTargetHandler(this)); | |
219 break; | |
220 case INSERTION_MOVED: | |
221 break; | |
222 case INSERTION_TAPPED: | |
223 break; | |
224 case INSERTION_CLEARED: | |
225 env_pre_target_handler_.reset(); | |
226 UpdateQuickMenu(); | |
227 break; | |
228 case INSERTION_DRAG_STARTED: | |
229 handle_drag_in_progress_ = true; | |
230 UpdateQuickMenu(); | |
231 break; | |
232 case INSERTION_DRAG_STOPPED: | |
233 handle_drag_in_progress_ = false; | |
234 UpdateQuickMenu(); | |
235 break; | |
236 }; | |
237 } | |
238 | |
239 scoped_ptr<TouchHandleDrawable> TouchSelectionControllerAura::CreateDrawable() { | |
240 return scoped_ptr<TouchHandleDrawable>( | |
241 new TouchHandleDrawableAura(client_->GetParentWindow())); | |
242 } | |
243 | |
244 gfx::Rect TouchSelectionControllerAura::GetMenuAnchorRect() const { | |
245 SelectionBound start = controller_->start(); | |
246 SelectionBound end = controller_->end(); | |
247 const gfx::Rect& client_bounds = client_->GetClientBounds(); | |
248 if (start.visible()) | |
249 ClipSelectionBound(&start, client_bounds); | |
250 if (end.visible()) | |
251 ClipSelectionBound(&end, client_bounds); | |
252 | |
253 if (start.visible() && end.visible()) | |
254 return RectBetweenSelectionBounds(start, end); | |
255 if (end.visible()) | |
256 return gfx::BoundingRect(end.edge_top_rounded(), end.edge_bottom_rounded()); | |
257 return gfx::BoundingRect(start.edge_top_rounded(), | |
258 start.edge_bottom_rounded()); | |
259 } | |
260 | |
261 void TouchSelectionControllerAura::ShowQuickMenu() { | |
262 DCHECK(controller_->is_insertion_active() || | |
263 controller_->is_selection_active()); | |
264 | |
265 if (!controller_->start().visible() && !controller_->end().visible()) | |
266 return; | |
267 | |
268 if (TouchSelectionMenuRunner::GetInstance()) { | |
269 aura::Window* parent = client_->GetParentWindow(); | |
270 TouchSelectionMenuRunner::GetInstance()->RunMenu( | |
271 this, | |
272 ConvertRectToScreen(parent, GetMenuAnchorRect()), | |
273 TouchHandleDrawableAura::GetMaxHandleImageSize(), | |
274 parent->GetToplevelWindow()); | |
275 } | |
276 } | |
277 | |
278 void TouchSelectionControllerAura::UpdateQuickMenu() { | |
279 // Hide quick menu if there is any. | |
280 if (TouchSelectionMenuRunner::GetInstance() && | |
281 TouchSelectionMenuRunner::GetInstance()->IsRunning()) { | |
282 TouchSelectionMenuRunner::GetInstance()->CloseMenu(); | |
283 } else { | |
284 quick_menu_timer_.Stop(); | |
285 } | |
286 | |
287 // Start timer to show quick menu if necessary. | |
288 if (!controller_->is_insertion_active() && | |
289 !controller_->is_selection_active()) | |
290 return; | |
291 | |
292 if (!IsQuickMenuAllowed()) | |
293 return; | |
294 | |
295 if (test_api_ && test_api_->immediate_quick_menu()) { | |
296 ShowQuickMenu(); | |
297 } else { | |
298 quick_menu_timer_.Start( | |
299 FROM_HERE, | |
300 base::TimeDelta::FromMilliseconds(100), | |
301 this, | |
302 &TouchSelectionControllerAura::ShowQuickMenu); | |
jdduke (slow)
2015/03/13 15:41:27
Why the delay here? What about fading it in or som
mohsen
2015/03/13 17:35:33
I don't know exactly what was the original intenti
| |
303 } | |
304 } | |
305 | |
306 bool TouchSelectionControllerAura::IsQuickMenuAllowed() const { | |
307 return !scroll_in_progress_ && !overscroll_in_progress_ && | |
308 !handle_drag_in_progress_; | |
309 } | |
310 | |
311 bool TouchSelectionControllerAura::IsCommandIdEnabled(int command_id) const { | |
312 return client_->IsCommandIdEnabled(command_id); | |
313 } | |
314 | |
315 void TouchSelectionControllerAura::ExecuteCommand(int command_id, | |
316 int event_flags) { | |
317 HideAndDisallowShowingAutomatically(); | |
318 client_->ExecuteCommand(command_id, event_flags); | |
319 } | |
320 | |
321 void TouchSelectionControllerAura::OpenContextMenu() { | |
322 HideAndDisallowShowingAutomatically(); | |
323 gfx::Rect anchor_rect = GetMenuAnchorRect(); | |
324 client_->OpenContextMenu(gfx::Point(anchor_rect.CenterPoint().x(), | |
325 anchor_rect.y())); | |
326 } | |
327 | |
328 void TouchSelectionControllerAura::OnTouchEvent(TouchEvent* event) { | |
329 const int index = motion_event_->FindPointerIndexOfId(event->touch_id()); | |
330 const bool pointer_id_is_active = index != -1; | |
331 | |
332 if (event->type() != ET_TOUCH_PRESSED && !pointer_id_is_active) | |
333 return; | |
334 | |
335 if (event->type() == ET_TOUCH_PRESSED && pointer_id_is_active) | |
336 motion_event_.reset(new MotionEventAura); | |
337 | |
338 motion_event_->OnTouch(*event); | |
339 if (controller_->WillHandleTouchEvent(*motion_event_)) | |
340 event->SetHandled(); | |
341 motion_event_->CleanupRemovedTouchPoints(*event); | |
342 } | |
343 | |
344 void TouchSelectionControllerAura::OnGestureEvent(GestureEvent* event) { | |
345 switch (event->type()) { | |
346 case ET_GESTURE_LONG_PRESS: | |
347 controller_->OnLongPressEvent(); | |
348 break; | |
349 case ET_GESTURE_TAP: | |
350 if (RectBetweenSelectionBounds( | |
351 controller_->start(), | |
352 controller_->end()).Contains(event->x(), event->y())) { | |
353 if (!controller_->is_insertion_active() && | |
354 !controller_->is_selection_active()) { | |
355 controller_->AllowShowingFromCurrentSelection(); | |
356 event->SetHandled(); | |
357 } else if (!selection_editable_) { | |
358 event->SetHandled(); | |
359 } | |
360 } | |
361 if (!event->handled()) | |
362 controller_->OnTapEvent(); | |
363 break; | |
364 case ET_GESTURE_SCROLL_BEGIN: | |
365 scroll_in_progress_ = true; | |
366 UpdateQuickMenu(); | |
367 break; | |
368 case ET_GESTURE_SCROLL_END: | |
369 scroll_in_progress_ = false; | |
370 UpdateQuickMenu(); | |
371 break; | |
372 default: | |
373 break; | |
374 } | |
375 } | |
376 | |
377 } // namespace ui | |
OLD | NEW |