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

Side by Side Diff: ui/views/touchui/touch_selection_controller_impl.cc

Issue 16580009: Change touch selection handles to images given by UX. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 6 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
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/views/touchui/touch_selection_controller_impl.h" 5 #include "ui/views/touchui/touch_selection_controller_impl.h"
6 6
7 #include "base/time.h" 7 #include "base/time.h"
8 #include "grit/ui_resources.h"
8 #include "grit/ui_strings.h" 9 #include "grit/ui_strings.h"
10 #include "ui/base/resource/resource_bundle.h"
9 #include "ui/base/ui_base_switches_util.h" 11 #include "ui/base/ui_base_switches_util.h"
10 #include "ui/gfx/canvas.h" 12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/image/image.h"
11 #include "ui/gfx/path.h" 14 #include "ui/gfx/path.h"
12 #include "ui/gfx/rect.h" 15 #include "ui/gfx/rect.h"
13 #include "ui/gfx/screen.h" 16 #include "ui/gfx/screen.h"
14 #include "ui/gfx/size.h" 17 #include "ui/gfx/size.h"
15 #include "ui/views/corewm/shadow_types.h" 18 #include "ui/views/corewm/shadow_types.h"
16 #include "ui/views/widget/widget.h" 19 #include "ui/views/widget/widget.h"
17 20
18 namespace { 21 namespace {
19 22
20 // Constants defining the visual attributes of selection handles 23 // Constants defining the visual attributes of selection handles
21 const int kSelectionHandleRadius = 10; 24 const int kSelectionHandleLineWidth = 2;
22 const int kSelectionHandleAlpha = 0x7F; 25 const SkColor kSelectionHandleLineColor =
23 const SkColor kSelectionHandleColor = 26 SkColorSetRGB(0x42, 0x81, 0xf4);
24 SkColorSetA(SK_ColorBLACK, kSelectionHandleAlpha);
25 27
26 // The minimum selection size to trigger selection controller. 28 // The minimum selection size to trigger selection controller.
27 const int kMinSelectionSize = 4; 29 const int kMinSelectionSize = 4;
28 30
29 const int kContextMenuTimoutMs = 200; 31 const int kContextMenuTimoutMs = 200;
30 32
31 // Convenience struct to represent a circle shape.
32 struct Circle {
33 int radius;
34 gfx::Point center;
35 SkColor color;
36 };
37
38 // Creates a widget to host SelectionHandleView. 33 // Creates a widget to host SelectionHandleView.
39 views::Widget* CreateTouchSelectionPopupWidget( 34 views::Widget* CreateTouchSelectionPopupWidget(
40 gfx::NativeView context, 35 gfx::NativeView context,
41 views::WidgetDelegate* widget_delegate) { 36 views::WidgetDelegate* widget_delegate) {
42 views::Widget* widget = new views::Widget; 37 views::Widget* widget = new views::Widget;
43 views::Widget::InitParams params(views::Widget::InitParams::TYPE_TOOLTIP); 38 views::Widget::InitParams params(views::Widget::InitParams::TYPE_TOOLTIP);
44 params.can_activate = false; 39 params.can_activate = false;
45 params.transparent = true; 40 params.transparent = true;
46 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; 41 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
47 params.context = context; 42 params.context = context;
48 params.delegate = widget_delegate; 43 params.delegate = widget_delegate;
49 widget->Init(params); 44 widget->Init(params);
50 #if defined(USE_AURA) 45 #if defined(USE_AURA)
51 SetShadowType(widget->GetNativeView(), views::corewm::SHADOW_TYPE_NONE); 46 SetShadowType(widget->GetNativeView(), views::corewm::SHADOW_TYPE_NONE);
52 #endif 47 #endif
53 return widget; 48 return widget;
54 } 49 }
55 50
56 void PaintCircle(const Circle& circle, gfx::Canvas* canvas) { 51 gfx::Image* GetHandleImage() {
57 SkPaint paint; 52 static gfx::Image* handle_image = NULL;
58 paint.setAntiAlias(true); 53 if (!handle_image) {
59 paint.setStyle(SkPaint::kFill_Style); 54 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed(
sadrul 2013/06/07 02:19:10 indentation is off here.
varunjain 2013/06/07 06:09:04 Done.
60 paint.setColor(circle.color); 55 IDR_TEXT_SELECTION_HANDLE);
61 canvas->DrawCircle(circle.center, circle.radius, paint); 56 }
57 return handle_image;
58 }
59
60 gfx::Size GetHandleImageSize() {
61 return GetHandleImage()->Size();
62 } 62 }
63 63
64 // The points may not match exactly, since the selection range computation may 64 // The points may not match exactly, since the selection range computation may
65 // introduce some floating point errors. So check for a minimum size to decide 65 // introduce some floating point errors. So check for a minimum size to decide
66 // whether or not there is any selection. 66 // whether or not there is any selection.
67 bool IsEmptySelection(const gfx::Point& p1, const gfx::Point& p2) { 67 bool IsEmptySelection(const gfx::Point& p1, const gfx::Point& p2) {
68 int delta_x = p2.x() - p1.x(); 68 int delta_x = p2.x() - p1.x();
69 int delta_y = p2.y() - p1.y(); 69 int delta_y = p2.y() - p1.y();
70 return (abs(delta_x) < kMinSelectionSize && abs(delta_y) < kMinSelectionSize); 70 return (abs(delta_x) < kMinSelectionSize && abs(delta_y) < kMinSelectionSize);
71 } 71 }
72 72
73 gfx::Rect GetHandleBoundsFromCursor(const gfx::Rect& cursor) {
74 return gfx::Rect(cursor.x() - kSelectionHandleRadius, cursor.y(),
75 2 * kSelectionHandleRadius,
76 2 * kSelectionHandleRadius + cursor.height());
77 }
78
79 } // namespace 73 } // namespace
80 74
81 namespace views { 75 namespace views {
82 76
83 // A View that displays the text selection handle. 77 // A View that displays the text selection handle.
84 class TouchSelectionControllerImpl::EditingHandleView 78 class TouchSelectionControllerImpl::EditingHandleView
85 : public views::WidgetDelegateView { 79 : public views::WidgetDelegateView {
86 public: 80 public:
87 explicit EditingHandleView(TouchSelectionControllerImpl* controller, 81 explicit EditingHandleView(TouchSelectionControllerImpl* controller,
88 gfx::NativeView context) 82 gfx::NativeView context)
(...skipping 11 matching lines...) Expand all
100 } 94 }
101 95
102 int cursor_height() const { return cursor_height_; } 96 int cursor_height() const { return cursor_height_; }
103 97
104 // Overridden from views::WidgetDelegateView: 98 // Overridden from views::WidgetDelegateView:
105 virtual bool WidgetHasHitTestMask() const OVERRIDE { 99 virtual bool WidgetHasHitTestMask() const OVERRIDE {
106 return true; 100 return true;
107 } 101 }
108 102
109 virtual void GetWidgetHitTestMask(gfx::Path* mask) const OVERRIDE { 103 virtual void GetWidgetHitTestMask(gfx::Path* mask) const OVERRIDE {
110 mask->addCircle(SkIntToScalar(kSelectionHandleRadius), 104 gfx::Size image_size = GetHandleImageSize();
111 SkIntToScalar(kSelectionHandleRadius + cursor_height_), 105 mask->addRect(SkIntToScalar(0), SkIntToScalar(cursor_height_),
112 SkIntToScalar(kSelectionHandleRadius)); 106 SkIntToScalar(image_size.width()),
107 SkIntToScalar(cursor_height_ + image_size.height()));
113 } 108 }
114 109
115 virtual void DeleteDelegate() OVERRIDE { 110 virtual void DeleteDelegate() OVERRIDE {
116 // We are owned and deleted by TouchSelectionController. 111 // We are owned and deleted by TouchSelectionController.
117 } 112 }
118 113
119 // Overridden from views::View: 114 // Overridden from views::View:
120 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 115 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
121 Circle circle = {kSelectionHandleRadius, gfx::Point(kSelectionHandleRadius, 116 gfx::Size image_size = GetHandleImageSize();
122 kSelectionHandleRadius + cursor_height_), 117 canvas->FillRect(
123 kSelectionHandleColor}; 118 gfx::Rect(image_size.width() / 2 - kSelectionHandleLineWidth, 0,
124 PaintCircle(circle, canvas); 119 2 * kSelectionHandleLineWidth, cursor_height_),
125 canvas->DrawLine(gfx::Point(kSelectionHandleRadius, 0), 120 kSelectionHandleLineColor);
126 gfx::Point(kSelectionHandleRadius, cursor_height_), 121 canvas->DrawImageInt(*GetHandleImage()->ToImageSkia(), 0, cursor_height_);
127 kSelectionHandleColor);
128 } 122 }
129 123
130 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE { 124 virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE {
131 event->SetHandled(); 125 event->SetHandled();
132 switch (event->type()) { 126 switch (event->type()) {
133 case ui::ET_GESTURE_SCROLL_BEGIN: 127 case ui::ET_GESTURE_SCROLL_BEGIN:
134 controller_->SetDraggingHandle(this); 128 controller_->SetDraggingHandle(this);
135 break; 129 break;
136 case ui::ET_GESTURE_SCROLL_UPDATE: 130 case ui::ET_GESTURE_SCROLL_UPDATE:
137 controller_->SelectionHandleDragged(event->location()); 131 controller_->SelectionHandleDragged(event->location());
(...skipping 11 matching lines...) Expand all
149 if (visible != widget_->IsVisible()) { 143 if (visible != widget_->IsVisible()) {
150 if (visible) 144 if (visible)
151 widget_->Show(); 145 widget_->Show();
152 else 146 else
153 widget_->Hide(); 147 widget_->Hide();
154 } 148 }
155 View::SetVisible(visible); 149 View::SetVisible(visible);
156 } 150 }
157 151
158 virtual gfx::Size GetPreferredSize() OVERRIDE { 152 virtual gfx::Size GetPreferredSize() OVERRIDE {
159 return gfx::Size(2 * kSelectionHandleRadius, 153 gfx::Size image_size = GetHandleImageSize();
160 2 * kSelectionHandleRadius + cursor_height_); 154 return gfx::Size(image_size.width(),
155 image_size.height() + cursor_height_);
161 } 156 }
162 157
163 bool IsWidgetVisible() const { 158 bool IsWidgetVisible() const {
164 return widget_->IsVisible(); 159 return widget_->IsVisible();
165 } 160 }
166 161
167 void SetSelectionRectInScreen(const gfx::Rect& rect) { 162 void SetSelectionRectInScreen(const gfx::Rect& rect) {
163 gfx::Size image_size = GetHandleImageSize();
168 cursor_height_ = rect.height(); 164 cursor_height_ = rect.height();
169 gfx::Rect widget_bounds = GetHandleBoundsFromCursor(rect); 165 gfx::Rect widget_bounds(rect.x() - image_size.width() / 2, rect.y(),
166 image_size.width(), rect.height() + image_size.height());
170 widget_->SetBounds(widget_bounds); 167 widget_->SetBounds(widget_bounds);
171 } 168 }
172 169
173 gfx::Point GetScreenPosition() { 170 gfx::Point GetScreenPosition() {
174 return widget_->GetClientAreaBoundsInScreen().origin(); 171 return widget_->GetClientAreaBoundsInScreen().origin();
175 } 172 }
176 173
177 private: 174 private:
178 scoped_ptr<Widget> widget_; 175 scoped_ptr<Widget> widget_;
179 TouchSelectionControllerImpl* controller_; 176 TouchSelectionControllerImpl* controller_;
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 StartContextMenuTimer(); 278 StartContextMenuTimer();
282 } 279 }
283 280
284 void TouchSelectionControllerImpl::SelectionHandleDragged( 281 void TouchSelectionControllerImpl::SelectionHandleDragged(
285 const gfx::Point& drag_pos) { 282 const gfx::Point& drag_pos) {
286 // We do not want to show the context menu while dragging. 283 // We do not want to show the context menu while dragging.
287 HideContextMenu(); 284 HideContextMenu();
288 285
289 DCHECK(dragging_handle_); 286 DCHECK(dragging_handle_);
290 287
288 gfx::Size image_size = GetHandleImageSize();
291 gfx::Point offset_drag_pos(drag_pos.x(), 289 gfx::Point offset_drag_pos(drag_pos.x(),
292 drag_pos.y() - dragging_handle_->cursor_height() / 2 - 290 drag_pos.y() - dragging_handle_->cursor_height() / 2 -
293 2 * kSelectionHandleRadius); 291 image_size.height() / 2);
294 ConvertPointToClientView(dragging_handle_, &offset_drag_pos); 292 ConvertPointToClientView(dragging_handle_, &offset_drag_pos);
295 if (dragging_handle_ == cursor_handle_.get()) { 293 if (dragging_handle_ == cursor_handle_.get()) {
296 client_view_->MoveCaretTo(offset_drag_pos); 294 client_view_->MoveCaretTo(offset_drag_pos);
297 return; 295 return;
298 } 296 }
299 297
300 // Find the stationary selection handle. 298 // Find the stationary selection handle.
301 EditingHandleView* fixed_handle = selection_handle_1_.get(); 299 EditingHandleView* fixed_handle = selection_handle_1_.get();
302 if (fixed_handle == dragging_handle_) 300 if (fixed_handle == dragging_handle_)
303 fixed_handle = selection_handle_2_.get(); 301 fixed_handle = selection_handle_2_.get();
304 302
305 // Find selection end points in client_view's coordinate system. 303 // Find selection end points in client_view's coordinate system.
306 gfx::Point p2(kSelectionHandleRadius, fixed_handle->cursor_height() / 2); 304 gfx::Point p2(image_size.width() / 2, fixed_handle->cursor_height() / 2);
307 ConvertPointToClientView(fixed_handle, &p2); 305 ConvertPointToClientView(fixed_handle, &p2);
308 306
309 // Instruct client_view to select the region between p1 and p2. The position 307 // Instruct client_view to select the region between p1 and p2. The position
310 // of |fixed_handle| is the start and that of |dragging_handle| is the end 308 // of |fixed_handle| is the start and that of |dragging_handle| is the end
311 // of selection. 309 // of selection.
312 client_view_->SelectRect(p2, offset_drag_pos); 310 client_view_->SelectRect(p2, offset_drag_pos);
313 } 311 }
314 312
315 void TouchSelectionControllerImpl::ConvertPointToClientView( 313 void TouchSelectionControllerImpl::ConvertPointToClientView(
316 EditingHandleView* source, gfx::Point* point) { 314 EditingHandleView* source, gfx::Point* point) {
317 View::ConvertPointToScreen(source, point); 315 View::ConvertPointToScreen(source, point);
318 client_view_->ConvertPointFromScreen(point); 316 client_view_->ConvertPointFromScreen(point);
319 } 317 }
320 318
321 bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const { 319 bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const {
322 return client_view_->IsCommandIdEnabled(command_id); 320 return client_view_->IsCommandIdEnabled(command_id);
323 } 321 }
324 322
325 void TouchSelectionControllerImpl::ExecuteCommand(int command_id, 323 void TouchSelectionControllerImpl::ExecuteCommand(int command_id,
326 int event_flags) { 324 int event_flags) {
327 HideContextMenu(); 325 HideContextMenu();
328 client_view_->ExecuteCommand(command_id, event_flags); 326 client_view_->ExecuteCommand(command_id, event_flags);
329 } 327 }
330 328
331 void TouchSelectionControllerImpl::OpenContextMenu() { 329 void TouchSelectionControllerImpl::OpenContextMenu() {
332 gfx::Point anchor = context_menu_->anchor_rect().origin(); 330 gfx::Point anchor = context_menu_->anchor_rect().origin();
333 anchor.Offset(0, -kSelectionHandleRadius); 331 // anchor.Offset(0, -kSelectionHandleRadius);
sadrul 2013/06/07 02:19:10 remove
varunjain 2013/06/07 06:09:04 Done.
334 HideContextMenu(); 332 HideContextMenu();
335 client_view_->OpenContextMenu(anchor); 333 client_view_->OpenContextMenu(anchor);
336 } 334 }
337 335
338 void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) { 336 void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) {
339 if (menu == context_menu_) 337 if (menu == context_menu_)
340 context_menu_ = NULL; 338 context_menu_ = NULL;
341 } 339 }
342 340
343 void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) { 341 void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) {
344 DCHECK_EQ(client_widget_, widget); 342 DCHECK_EQ(client_widget_, widget);
345 client_widget_ = NULL; 343 client_widget_ = NULL;
346 } 344 }
347 345
348 void TouchSelectionControllerImpl::OnWidgetBoundsChanged( 346 void TouchSelectionControllerImpl::OnWidgetBoundsChanged(
349 Widget* widget, 347 Widget* widget,
350 const gfx::Rect& new_bounds) { 348 const gfx::Rect& new_bounds) {
351 DCHECK_EQ(client_widget_, widget); 349 DCHECK_EQ(client_widget_, widget);
352 HideContextMenu(); 350 HideContextMenu();
353 SelectionChanged(); 351 SelectionChanged();
354 } 352 }
355 353
356 void TouchSelectionControllerImpl::ContextMenuTimerFired() { 354 void TouchSelectionControllerImpl::ContextMenuTimerFired() {
357 // Get selection end points in client_view's space. 355 // Get selection end points in client_view's space.
358 gfx::Rect r1, r2; 356 gfx::Rect r1, r2;
359 client_view_->GetSelectionEndPoints(&r1, &r2); 357 client_view_->GetSelectionEndPoints(&r1, &r2);
360 358
361 gfx::Rect handle_1_bounds = GetHandleBoundsFromCursor(r1); 359 gfx::Rect handle_1_bounds;
362 gfx::Rect handle_2_bounds = GetHandleBoundsFromCursor(r2); 360 gfx::Rect handle_2_bounds;
361 if (cursor_handle_->IsWidgetVisible()) {
362 handle_1_bounds = cursor_handle_->GetBoundsInScreen();
363 handle_2_bounds = handle_1_bounds;
364 } else {
365 handle_1_bounds = selection_handle_1_->GetBoundsInScreen();
366 handle_2_bounds = selection_handle_2_->GetBoundsInScreen();
367 }
363 368
364 // if selection is completely inside the view, we display the context menu 369 // if selection is completely inside the view, we display the context menu
365 // in the middle of the end points on the top. Else, we show it above the 370 // in the middle of the end points on the top. Else, we show it above the
366 // visible handle. If no handle is visible, we do not show the menu. 371 // visible handle. If no handle is visible, we do not show the menu.
367 gfx::Rect menu_anchor; 372 gfx::Rect menu_anchor;
368 gfx::Rect client_bounds = client_view_->GetBounds(); 373 gfx::Rect client_bounds = client_view_->GetBounds();
369 if (client_bounds.Contains(r1.origin()) && 374 if (client_bounds.Contains(r1.origin()) &&
370 client_bounds.Contains(r2.origin())) { 375 client_bounds.Contains(r2.origin())) {
371 menu_anchor = gfx::UnionRects(handle_1_bounds, handle_2_bounds); 376 menu_anchor = gfx::UnionRects(handle_1_bounds, handle_2_bounds);
372 } else if (client_bounds.Contains(r1.origin())) { 377 } else if (client_bounds.Contains(r1.origin())) {
373 menu_anchor = handle_1_bounds; 378 menu_anchor = handle_1_bounds;
374 } else if (client_bounds.Contains(r2.origin())) { 379 } else if (client_bounds.Contains(r2.origin())) {
375 menu_anchor = handle_2_bounds; 380 menu_anchor = handle_2_bounds;
376 } else { 381 } else {
377 return; 382 return;
378 } 383 }
379 384
380 gfx::Point menu_origin = menu_anchor.origin();
381 client_view_->ConvertPointToScreen(&menu_origin);
382 menu_anchor.set_origin(menu_origin);
383
384 DCHECK(!context_menu_); 385 DCHECK(!context_menu_);
385 context_menu_ = new TouchEditingMenuView(this, menu_anchor, 386 context_menu_ = new TouchEditingMenuView(this, menu_anchor,
386 client_view_->GetNativeView()); 387 client_view_->GetNativeView());
387 } 388 }
388 389
389 void TouchSelectionControllerImpl::StartContextMenuTimer() { 390 void TouchSelectionControllerImpl::StartContextMenuTimer() {
390 if (context_menu_timer_.IsRunning()) 391 if (context_menu_timer_.IsRunning())
391 return; 392 return;
392 context_menu_timer_.Start( 393 context_menu_timer_.Start(
393 FROM_HERE, 394 FROM_HERE,
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 } 439 }
439 440
440 ui::TouchSelectionController* ViewsTouchSelectionControllerFactory::create( 441 ui::TouchSelectionController* ViewsTouchSelectionControllerFactory::create(
441 ui::TouchEditable* client_view) { 442 ui::TouchEditable* client_view) {
442 if (switches::IsTouchEditingEnabled()) 443 if (switches::IsTouchEditingEnabled())
443 return new views::TouchSelectionControllerImpl(client_view); 444 return new views::TouchSelectionControllerImpl(client_view);
444 return NULL; 445 return NULL;
445 } 446 }
446 447
447 } // namespace views 448 } // namespace views
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698