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

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

Issue 769393002: Minor visual improvements to text selection UI (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixing the failing test Created 6 years 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
« no previous file with comments | « content/browser/web_contents/touch_editable_impl_aura_browsertest.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/time.h" 7 #include "base/time/time.h"
8 #include "ui/aura/client/cursor_client.h" 8 #include "ui/aura/client/cursor_client.h"
9 #include "ui/aura/env.h" 9 #include "ui/aura/env.h"
10 #include "ui/aura/window.h" 10 #include "ui/aura/window.h"
11 #include "ui/base/resource/resource_bundle.h" 11 #include "ui/base/resource/resource_bundle.h"
12 #include "ui/gfx/canvas.h" 12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/image/image.h" 13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/path.h" 14 #include "ui/gfx/path.h"
15 #include "ui/gfx/rect.h" 15 #include "ui/gfx/rect.h"
16 #include "ui/gfx/screen.h" 16 #include "ui/gfx/screen.h"
17 #include "ui/gfx/size.h" 17 #include "ui/gfx/size.h"
18 #include "ui/resources/grit/ui_resources.h" 18 #include "ui/resources/grit/ui_resources.h"
19 #include "ui/strings/grit/ui_strings.h" 19 #include "ui/strings/grit/ui_strings.h"
20 #include "ui/views/widget/widget.h" 20 #include "ui/views/widget/widget.h"
21 #include "ui/wm/core/coordinate_conversion.h" 21 #include "ui/wm/core/coordinate_conversion.h"
22 #include "ui/wm/core/masked_window_targeter.h" 22 #include "ui/wm/core/masked_window_targeter.h"
23 23
24 namespace { 24 namespace {
25 25
26 // Constants defining the visual attributes of selection handles 26 // Constants defining the visual attributes of selection handles
27 27
28 // Controls the width of the cursor line associated with the selection handle. 28 // The distance by which a handle image is offset from the bottom of the
29 const int kSelectionHandleLineWidth = 2; 29 // selection/text baseline.
30 30 const int kSelectionHandleVerticalVisualOffset = 2;
31 const SkColor kSelectionHandleLineColor =
32 SkColorSetRGB(0x42, 0x81, 0xf4);
33 31
34 // When a handle is dragged, the drag position reported to the client view is 32 // When a handle is dragged, the drag position reported to the client view is
35 // offset vertically to represent the cursor position. This constant specifies 33 // offset vertically to represent the cursor position. This constant specifies
36 // the offset in pixels above the "O" (see pic below). This is required because 34 // the offset in pixels above the bottom of the selection (see pic below). This
37 // say if this is zero, that means the drag position we report is the point 35 // is required because say if this is zero, that means the drag position we
38 // right above the "O" or the bottom most point of the cursor "|". In that case, 36 // report is right on the text baseline. In that case, a vertical movement of
39 // a vertical movement of even one pixel will make the handle jump to the line 37 // even one pixel will make the handle jump to the line below it. So when the
40 // below it. So when the user just starts dragging, the handle will jump to the 38 // user just starts dragging, the handle will jump to the next line if the user
41 // next line if the user makes any vertical movement. It is correct but 39 // makes any vertical movement. So we have this non-zero offset to prevent this
42 // looks/feels weird. So we have this non-zero offset to prevent this jumping. 40 // jumping.
43 // 41 //
44 // Editing handle widget showing the padding and difference between the position 42 // Editing handle widget showing the padding and difference between the position
45 // of the ET_GESTURE_SCROLL_UPDATE event and the drag position reported to the 43 // of the ET_GESTURE_SCROLL_UPDATE event and the drag position reported to the
46 // client: 44 // client:
47 // _____ 45 // ___________
48 // | |<-|---- Drag position reported to client 46 // Selection Highlight --->_____|__|<-|---- Drag position reported to client
49 // _ | O | 47 // _ | O |
50 // Vertical Padding __| | <-|---- ET_GESTURE_SCROLL_UPDATE position 48 // Vertical Padding __| | <-|---- ET_GESTURE_SCROLL_UPDATE position
51 // |_ |_____|<--- Editing handle widget 49 // |_ |_____|<--- Editing handle widget
52 // 50 //
53 // | | 51 // | |
54 // T 52 // T
55 // Horizontal Padding 53 // Horizontal Padding
56 // 54 //
57 const int kSelectionHandleVerticalDragOffset = 5; 55 const int kSelectionHandleVerticalDragOffset = 5;
58 56
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
122 case ui::SelectionBound::CENTER: 120 case ui::SelectionBound::CENTER:
123 return GetCenterHandleImage(); 121 return GetCenterHandleImage();
124 case ui::SelectionBound::RIGHT: 122 case ui::SelectionBound::RIGHT:
125 return GetRightHandleImage(); 123 return GetRightHandleImage();
126 default: 124 default:
127 NOTREACHED() << "Invalid touch handle bound type."; 125 NOTREACHED() << "Invalid touch handle bound type.";
128 return nullptr; 126 return nullptr;
129 }; 127 };
130 } 128 }
131 129
132 enum Alignment {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT};
133
134 // Determine the cursor line alignment to the handle image based on the bound
135 // type. Depends on the visual shapes of the handle image assets.
136 Alignment GetCursorAlignment(ui::SelectionBound::Type bound_type) {
137 switch (bound_type) {
138 case ui::SelectionBound::LEFT:
139 return ALIGN_RIGHT;
140 case ui::SelectionBound::RIGHT:
141 return ALIGN_LEFT;
142 case ui::SelectionBound::CENTER:
143 return ALIGN_CENTER;
144 default:
145 NOTREACHED() << "Undefined bound type for cursor alignment.";
146 return ALIGN_LEFT;
147 };
148 }
149
150 // Calculates the bounds of the widget containing the selection handle based 130 // Calculates the bounds of the widget containing the selection handle based
151 // on the SelectionBound's type and location 131 // on the SelectionBound's type and location
152 gfx::Rect GetSelectionWidgetBounds(const ui::SelectionBound& bound) { 132 gfx::Rect GetSelectionWidgetBounds(const ui::SelectionBound& bound) {
153 Alignment cursor_alignment = GetCursorAlignment(bound.type());
154 gfx::Size image_size = GetHandleImage(bound.type())->Size(); 133 gfx::Size image_size = GetHandleImage(bound.type())->Size();
155 int widget_width = image_size.width() + 2 * kSelectionHandleHorizPadding; 134 int widget_width = image_size.width() + 2 * kSelectionHandleHorizPadding;
156 int widget_height = bound.GetHeight() + image_size.height() + 135 int widget_height = bound.GetHeight() + image_size.height() +
157 kSelectionHandleVertPadding; 136 kSelectionHandleVerticalVisualOffset +
137 kSelectionHandleVertPadding;
138 // Due to the shape of the handle images, the widget is aligned differently to
139 // the selection bound depending on the type of the bound.
158 int widget_left = 0; 140 int widget_left = 0;
159 switch (cursor_alignment) { 141 switch (bound.type()) {
160 case ALIGN_LEFT: 142 case ui::SelectionBound::LEFT:
143 widget_left = bound.edge_top_rounded().x() - image_size.width() -
144 kSelectionHandleHorizPadding;
145 break;
146 case ui::SelectionBound::RIGHT:
161 widget_left = bound.edge_top_rounded().x() - kSelectionHandleHorizPadding; 147 widget_left = bound.edge_top_rounded().x() - kSelectionHandleHorizPadding;
162 break; 148 break;
163 case ALIGN_RIGHT: 149 case ui::SelectionBound::CENTER:
164 widget_left = bound.edge_top_rounded().x() - image_size.width() - 150 widget_left = bound.edge_top_rounded().x() - widget_width / 2;
165 kSelectionHandleHorizPadding;
166 break; 151 break;
167 case ALIGN_CENTER: 152 default:
168 widget_left = bound.edge_top_rounded().x() - widget_width / 2; 153 NOTREACHED() << "Undefined bound type.";
169 break; 154 break;
170 }; 155 };
171 return gfx::Rect( 156 return gfx::Rect(
172 widget_left, bound.edge_top_rounded().y(), widget_width, widget_height); 157 widget_left, bound.edge_top_rounded().y(), widget_width, widget_height);
173 } 158 }
174 159
175 gfx::Size GetMaxHandleImageSize() { 160 gfx::Size GetMaxHandleImageSize() {
176 gfx::Rect center_rect = gfx::Rect(GetCenterHandleImage()->Size()); 161 gfx::Rect center_rect = gfx::Rect(GetCenterHandleImage()->Size());
177 gfx::Rect left_rect = gfx::Rect(GetLeftHandleImage()->Size()); 162 gfx::Rect left_rect = gfx::Rect(GetLeftHandleImage()->Size());
178 gfx::Rect right_rect = gfx::Rect(GetRightHandleImage()->Size()); 163 gfx::Rect right_rect = gfx::Rect(GetRightHandleImage()->Size());
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 245
261 ~EditingHandleView() override { SetWidgetVisible(false, false); } 246 ~EditingHandleView() override { SetWidgetVisible(false, false); }
262 247
263 // Overridden from views::WidgetDelegateView: 248 // Overridden from views::WidgetDelegateView:
264 bool WidgetHasHitTestMask() const override { return true; } 249 bool WidgetHasHitTestMask() const override { return true; }
265 250
266 void GetWidgetHitTestMask(gfx::Path* mask) const override { 251 void GetWidgetHitTestMask(gfx::Path* mask) const override {
267 gfx::Size image_size = image_->Size(); 252 gfx::Size image_size = image_->Size();
268 mask->addRect( 253 mask->addRect(
269 SkIntToScalar(0), 254 SkIntToScalar(0),
270 SkIntToScalar(selection_bound_.GetHeight()), 255 SkIntToScalar(selection_bound_.GetHeight() +
256 kSelectionHandleVerticalVisualOffset),
271 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding, 257 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
272 SkIntToScalar(selection_bound_.GetHeight() + image_size.height() + 258 SkIntToScalar(selection_bound_.GetHeight() +
273 kSelectionHandleVertPadding)); 259 kSelectionHandleVerticalVisualOffset +
260 image_size.height() + kSelectionHandleVertPadding));
274 } 261 }
275 262
276 void DeleteDelegate() override { 263 void DeleteDelegate() override {
277 // We are owned and deleted by TouchSelectionController. 264 // We are owned and deleted by TouchSelectionController.
278 } 265 }
279 266
280 // Overridden from views::View: 267 // Overridden from views::View:
281 void OnPaint(gfx::Canvas* canvas) override { 268 void OnPaint(gfx::Canvas* canvas) override {
282 if (draw_invisible_) 269 if (draw_invisible_)
283 return; 270 return;
284 271
285 Alignment cursor_alignment = GetCursorAlignment(selection_bound_.type());
286 int cursor_x = 0;
287 switch (cursor_alignment) {
288 case ALIGN_RIGHT:
289 cursor_x = selection_bound_.edge_top_rounded().x() -
290 kSelectionHandleLineWidth + 1;
291 break;
292 case ALIGN_LEFT:
293 cursor_x = selection_bound_.edge_top_rounded().x() - 1;
294 break;
295 case ALIGN_CENTER:
296 cursor_x = selection_bound_.edge_top_rounded().x() -
297 kSelectionHandleLineWidth / 2;
298 break;
299 };
300 // Draw the cursor line.
301 canvas->FillRect(gfx::Rect(cursor_x,
302 0,
303 kSelectionHandleLineWidth,
304 selection_bound_.GetHeight()),
305 kSelectionHandleLineColor);
306 // Draw the handle image. 272 // Draw the handle image.
307 canvas->DrawImageInt(*image_->ToImageSkia(), 273 canvas->DrawImageInt(
308 kSelectionHandleHorizPadding, selection_bound_.GetHeight()); 274 *image_->ToImageSkia(),
275 kSelectionHandleHorizPadding,
276 selection_bound_.GetHeight() + kSelectionHandleVerticalVisualOffset);
309 } 277 }
310 278
311 void OnGestureEvent(ui::GestureEvent* event) override { 279 void OnGestureEvent(ui::GestureEvent* event) override {
312 event->SetHandled(); 280 event->SetHandled();
313 switch (event->type()) { 281 switch (event->type()) {
314 case ui::ET_GESTURE_SCROLL_BEGIN: { 282 case ui::ET_GESTURE_SCROLL_BEGIN: {
315 widget_->SetCapture(this); 283 widget_->SetCapture(this);
316 controller_->SetDraggingHandle(this); 284 controller_->SetDraggingHandle(this);
317 // Distance from the point which is |kSelectionHandleVerticalDragOffset| 285 // Distance from the point which is |kSelectionHandleVerticalDragOffset|
318 // pixels above the bottom of the handle's cursor line to the event 286 // pixels above the bottom of the selection bound edge to the event
319 // location (aka the touch-drag point). 287 // location (aka the touch-drag point).
320 drag_offset_ = selection_bound_.edge_bottom_rounded() - 288 drag_offset_ = selection_bound_.edge_bottom_rounded() -
321 gfx::Vector2d(0, kSelectionHandleVerticalDragOffset) - 289 gfx::Vector2d(0, kSelectionHandleVerticalDragOffset) -
322 event->location(); 290 event->location();
323 break; 291 break;
324 } 292 }
325 case ui::ET_GESTURE_SCROLL_UPDATE: { 293 case ui::ET_GESTURE_SCROLL_UPDATE: {
326 controller_->SelectionHandleDragged(event->location() + drag_offset_); 294 controller_->SelectionHandleDragged(event->location() + drag_offset_);
327 break; 295 break;
328 } 296 }
329 case ui::ET_GESTURE_SCROLL_END: 297 case ui::ET_GESTURE_SCROLL_END:
330 case ui::ET_SCROLL_FLING_START: 298 case ui::ET_SCROLL_FLING_START:
331 widget_->ReleaseCapture(); 299 widget_->ReleaseCapture();
332 controller_->SetDraggingHandle(nullptr); 300 controller_->SetDraggingHandle(nullptr);
333 break; 301 break;
334 default: 302 default:
335 break; 303 break;
336 } 304 }
337 } 305 }
338 306
339 gfx::Size GetPreferredSize() const override { 307 gfx::Size GetPreferredSize() const override {
340 gfx::Size image_size = image_->Size(); 308 return GetSelectionWidgetBounds(selection_bound_).size();
341 return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding,
342 image_size.height() + selection_bound_.GetHeight() +
343 kSelectionHandleVertPadding);
344 } 309 }
345 310
346 bool IsWidgetVisible() const { 311 bool IsWidgetVisible() const {
347 return widget_->IsVisible(); 312 return widget_->IsVisible();
348 } 313 }
349 314
350 void SetWidgetVisible(bool visible, bool quick) { 315 void SetWidgetVisible(bool visible, bool quick) {
351 if (widget_->IsVisible() == visible) 316 if (widget_->IsVisible() == visible)
352 return; 317 return;
353 widget_->SetVisibilityAnimationDuration( 318 widget_->SetVisibilityAnimationDuration(
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
695 gfx::Rect menu_anchor; 660 gfx::Rect menu_anchor;
696 if (ShouldShowHandleFor(b1) && ShouldShowHandleFor(b2)) 661 if (ShouldShowHandleFor(b1) && ShouldShowHandleFor(b2))
697 menu_anchor = ui::RectBetweenSelectionBounds(b1_in_screen, b2_in_screen); 662 menu_anchor = ui::RectBetweenSelectionBounds(b1_in_screen, b2_in_screen);
698 else if (ShouldShowHandleFor(b1)) 663 else if (ShouldShowHandleFor(b1))
699 menu_anchor = BoundToRect(b1_in_screen); 664 menu_anchor = BoundToRect(b1_in_screen);
700 else if (ShouldShowHandleFor(b2)) 665 else if (ShouldShowHandleFor(b2))
701 menu_anchor = BoundToRect(b2_in_screen); 666 menu_anchor = BoundToRect(b2_in_screen);
702 else 667 else
703 return; 668 return;
704 669
670 // Enlarge the anchor rect so that the menu is offset from the text at least
671 // by the same distance the handles are offset from the text.
672 menu_anchor.Inset(0, -kSelectionHandleVerticalVisualOffset);
673
705 DCHECK(!context_menu_); 674 DCHECK(!context_menu_);
706 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor, 675 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor,
707 GetMaxHandleImageSize(), 676 GetMaxHandleImageSize(),
708 client_view_->GetNativeView()); 677 client_view_->GetNativeView());
709 } 678 }
710 679
711 void TouchSelectionControllerImpl::StartContextMenuTimer() { 680 void TouchSelectionControllerImpl::StartContextMenuTimer() {
712 if (context_menu_timer_.IsRunning()) 681 if (context_menu_timer_.IsRunning())
713 return; 682 return;
714 context_menu_timer_.Start( 683 context_menu_timer_.Start(
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
766 735
767 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() { 736 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() {
768 return selection_handle_1_.get(); 737 return selection_handle_1_.get();
769 } 738 }
770 739
771 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() { 740 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() {
772 return selection_handle_2_.get(); 741 return selection_handle_2_.get();
773 } 742 }
774 743
775 } // namespace views 744 } // namespace views
OLDNEW
« no previous file with comments | « content/browser/web_contents/touch_editable_impl_aura_browsertest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698