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

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: Addressing feedback 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 | « no previous file | 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;
mohsen 2014/12/04 00:34:56 At least, line 144 has the same indentation issue.
mfomitchev 2014/12/09 22:32:26 Done.
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:
161 widget_left = bound.edge_top.x() - kSelectionHandleHorizPadding;
162 break;
163 case ALIGN_RIGHT:
164 widget_left = bound.edge_top.x() - image_size.width() - 143 widget_left = bound.edge_top.x() - image_size.width() -
165 kSelectionHandleHorizPadding; 144 kSelectionHandleHorizPadding;
166 break; 145 break;
167 case ALIGN_CENTER: 146 case ui::SelectionBound::RIGHT:
147 widget_left = bound.edge_top.x() - kSelectionHandleHorizPadding;
148 break;
149 case ui::SelectionBound::CENTER:
168 widget_left = bound.edge_top.x() - widget_width / 2; 150 widget_left = bound.edge_top.x() - widget_width / 2;
169 break; 151 break;
152 default:
153 NOTREACHED() << "Undefined bound type.";
154 break;
170 }; 155 };
171 return gfx::Rect( 156 return gfx::Rect(
172 widget_left, bound.edge_top.y(), widget_width, widget_height); 157 widget_left, bound.edge_top.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());
179 gfx::Rect union_rect = center_rect; 164 gfx::Rect union_rect = center_rect;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 246
262 ~EditingHandleView() override { SetWidgetVisible(false, false); } 247 ~EditingHandleView() override { SetWidgetVisible(false, false); }
263 248
264 // Overridden from views::WidgetDelegateView: 249 // Overridden from views::WidgetDelegateView:
265 bool WidgetHasHitTestMask() const override { return true; } 250 bool WidgetHasHitTestMask() const override { return true; }
266 251
267 void GetWidgetHitTestMask(gfx::Path* mask) const override { 252 void GetWidgetHitTestMask(gfx::Path* mask) const override {
268 gfx::Size image_size = image_->Size(); 253 gfx::Size image_size = image_->Size();
269 mask->addRect( 254 mask->addRect(
270 SkIntToScalar(0), 255 SkIntToScalar(0),
271 SkIntToScalar(selection_bound_.GetHeight()), 256 SkIntToScalar(selection_bound_.GetHeight() +
257 kSelectionHandleVerticalVisualOffset),
272 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding, 258 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding,
273 SkIntToScalar(selection_bound_.GetHeight() + image_size.height() + 259 SkIntToScalar(selection_bound_.GetHeight() +
274 kSelectionHandleVertPadding)); 260 kSelectionHandleVerticalVisualOffset +
261 image_size.height() + kSelectionHandleVertPadding));
275 } 262 }
276 263
277 void DeleteDelegate() override { 264 void DeleteDelegate() override {
278 // We are owned and deleted by TouchSelectionController. 265 // We are owned and deleted by TouchSelectionController.
279 } 266 }
280 267
281 // Overridden from views::View: 268 // Overridden from views::View:
282 void OnPaint(gfx::Canvas* canvas) override { 269 void OnPaint(gfx::Canvas* canvas) override {
283 if (draw_invisible_) 270 if (draw_invisible_)
284 return; 271 return;
285 272
286 Alignment cursor_alignment = GetCursorAlignment(selection_bound_.type);
287 int cursor_x = 0;
288 switch (cursor_alignment) {
289 case ALIGN_RIGHT:
290 cursor_x =
291 selection_bound_.edge_top.x() - kSelectionHandleLineWidth + 1;
292 break;
293 case ALIGN_LEFT:
294 cursor_x = selection_bound_.edge_top.x() - 1;
295 break;
296 case ALIGN_CENTER:
297 cursor_x =
298 selection_bound_.edge_top.x() - kSelectionHandleLineWidth / 2;
299 break;
300 };
301 // Draw the cursor line.
302 canvas->FillRect(gfx::Rect(cursor_x,
303 0,
304 kSelectionHandleLineWidth,
305 selection_bound_.GetHeight()),
306 kSelectionHandleLineColor);
307 // Draw the handle image. 273 // Draw the handle image.
308 canvas->DrawImageInt(*image_->ToImageSkia(), 274 canvas->DrawImageInt(
309 kSelectionHandleHorizPadding, selection_bound_.GetHeight()); 275 *image_->ToImageSkia(),
276 kSelectionHandleHorizPadding,
277 selection_bound_.GetHeight() + kSelectionHandleVerticalVisualOffset);
310 } 278 }
311 279
312 void OnGestureEvent(ui::GestureEvent* event) override { 280 void OnGestureEvent(ui::GestureEvent* event) override {
313 event->SetHandled(); 281 event->SetHandled();
314 switch (event->type()) { 282 switch (event->type()) {
315 case ui::ET_GESTURE_SCROLL_BEGIN: { 283 case ui::ET_GESTURE_SCROLL_BEGIN: {
316 widget_->SetCapture(this); 284 widget_->SetCapture(this);
317 controller_->SetDraggingHandle(this); 285 controller_->SetDraggingHandle(this);
318 // Distance from the point which is |kSelectionHandleVerticalDragOffset| 286 // Distance from the point which is |kSelectionHandleVerticalDragOffset|
319 // pixels above the bottom of the handle's cursor line to the event 287 // pixels above the bottom of the selection bound edge to the event
320 // location (aka the touch-drag point). 288 // location (aka the touch-drag point).
321 drag_offset_ = selection_bound_.edge_bottom - 289 drag_offset_ = selection_bound_.edge_bottom -
322 gfx::Vector2d(0, kSelectionHandleVerticalDragOffset) - 290 gfx::Vector2d(0, kSelectionHandleVerticalDragOffset) -
323 event->location(); 291 event->location();
324 break; 292 break;
325 } 293 }
326 case ui::ET_GESTURE_SCROLL_UPDATE: { 294 case ui::ET_GESTURE_SCROLL_UPDATE: {
327 controller_->SelectionHandleDragged(event->location() + drag_offset_); 295 controller_->SelectionHandleDragged(event->location() + drag_offset_);
328 break; 296 break;
329 } 297 }
330 case ui::ET_GESTURE_SCROLL_END: 298 case ui::ET_GESTURE_SCROLL_END:
331 case ui::ET_SCROLL_FLING_START: 299 case ui::ET_SCROLL_FLING_START:
332 widget_->ReleaseCapture(); 300 widget_->ReleaseCapture();
333 controller_->SetDraggingHandle(nullptr); 301 controller_->SetDraggingHandle(nullptr);
334 break; 302 break;
335 default: 303 default:
336 break; 304 break;
337 } 305 }
338 } 306 }
339 307
340 gfx::Size GetPreferredSize() const override { 308 gfx::Size GetPreferredSize() const override {
341 gfx::Size image_size = image_->Size(); 309 return GetSelectionWidgetBounds(selection_bound_).size();
342 return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding,
343 image_size.height() + selection_bound_.GetHeight() +
344 kSelectionHandleVertPadding);
345 } 310 }
346 311
347 bool IsWidgetVisible() const { 312 bool IsWidgetVisible() const {
348 return widget_->IsVisible(); 313 return widget_->IsVisible();
349 } 314 }
350 315
351 void SetWidgetVisible(bool visible, bool quick) { 316 void SetWidgetVisible(bool visible, bool quick) {
352 if (widget_->IsVisible() == visible) 317 if (widget_->IsVisible() == visible)
353 return; 318 return;
354 widget_->SetVisibilityAnimationDuration( 319 widget_->SetVisibilityAnimationDuration(
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 gfx::Rect menu_anchor; 654 gfx::Rect menu_anchor;
690 if (ShouldShowHandleFor(b1) && ShouldShowHandleFor(b2)) 655 if (ShouldShowHandleFor(b1) && ShouldShowHandleFor(b2))
691 menu_anchor = ui::RectBetweenSelectionBounds(b1_in_screen, b2_in_screen); 656 menu_anchor = ui::RectBetweenSelectionBounds(b1_in_screen, b2_in_screen);
692 else if (ShouldShowHandleFor(b1)) 657 else if (ShouldShowHandleFor(b1))
693 menu_anchor = BoundToRect(b1_in_screen); 658 menu_anchor = BoundToRect(b1_in_screen);
694 else if (ShouldShowHandleFor(b2)) 659 else if (ShouldShowHandleFor(b2))
695 menu_anchor = BoundToRect(b2_in_screen); 660 menu_anchor = BoundToRect(b2_in_screen);
696 else 661 else
697 return; 662 return;
698 663
664 // Enlarge the anchor rect so that the menu is offset from the text at least
665 // by the same distance the handles are offset from the text.
666 menu_anchor.Inset(0, -kSelectionHandleVerticalVisualOffset,
667 0, -kSelectionHandleVerticalVisualOffset);
mohsen 2014/12/04 00:34:56 I think you can use Rect::Inset(int horizontal, in
mfomitchev 2014/12/09 22:32:26 Done.
699 DCHECK(!context_menu_); 668 DCHECK(!context_menu_);
700 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor, 669 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor,
701 GetMaxHandleImageSize(), 670 GetMaxHandleImageSize(),
702 client_view_->GetNativeView()); 671 client_view_->GetNativeView());
703 } 672 }
704 673
705 void TouchSelectionControllerImpl::StartContextMenuTimer() { 674 void TouchSelectionControllerImpl::StartContextMenuTimer() {
706 if (context_menu_timer_.IsRunning()) 675 if (context_menu_timer_.IsRunning())
707 return; 676 return;
708 context_menu_timer_.Start( 677 context_menu_timer_.Start(
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
760 729
761 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() { 730 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() {
762 return selection_handle_1_.get(); 731 return selection_handle_1_.get();
763 } 732 }
764 733
765 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() { 734 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() {
766 return selection_handle_2_.get(); 735 return selection_handle_2_.get();
767 } 736 }
768 737
769 } // namespace views 738 } // namespace views
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698