OLD | NEW |
---|---|
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/masked_window_targeter.h" | 22 #include "ui/wm/core/masked_window_targeter.h" |
22 | 23 |
23 namespace { | 24 namespace { |
24 | 25 |
25 // Constants defining the visual attributes of selection handles | 26 // Constants defining the visual attributes of selection handles |
26 const int kSelectionHandleLineWidth = 1; | 27 |
28 // Controls the width of the cursor line associated with the selection handle. | |
29 const int kSelectionHandleLineWidth = 2; | |
30 | |
27 const SkColor kSelectionHandleLineColor = | 31 const SkColor kSelectionHandleLineColor = |
28 SkColorSetRGB(0x42, 0x81, 0xf4); | 32 SkColorSetRGB(0x42, 0x81, 0xf4); |
29 | 33 |
30 // When a handle is dragged, the drag position reported to the client view is | 34 // Padding around the selection handle defining the area that will be included |
31 // offset vertically to represent the cursor position. This constant specifies | 35 // in the touch target to make dragging the handle easier (see pic below). |
32 // the offset in pixels above the "O" (see pic below). This is required because | |
33 // say if this is zero, that means the drag position we report is the point | |
34 // right above the "O" or the bottom most point of the cursor "|". In that case, | |
35 // a vertical movement of even one pixel will make the handle jump to the line | |
36 // below it. So when the user just starts dragging, the handle will jump to the | |
37 // next line if the user makes any vertical movement. It is correct but | |
38 // looks/feels weird. So we have this non-zero offset to prevent this jumping. | |
39 // | |
40 // Editing handle widget showing the difference between the position of the | |
41 // ET_GESTURE_SCROLL_UPDATE event and the drag position reported to the client: | |
42 // _____ | 36 // _____ |
43 // | |<-|---- Drag position reported to client | 37 // | | | |
44 // _ | O | | 38 // _ | O | |
45 // Vertical Padding __| | <-|---- ET_GESTURE_SCROLL_UPDATE position | 39 // Vertical Padding __| | |<--- Editing handle widget |
46 // |_ |_____|<--- Editing handle widget | 40 // |_ |_____| |
47 // | 41 // |
48 // | | | 42 // | | |
49 // T | 43 // T |
50 // Horizontal Padding | 44 // Horizontal Padding |
51 // | 45 // |
52 const int kSelectionHandleVerticalDragOffset = 5; | |
53 | |
54 // Padding around the selection handle defining the area that will be included | |
55 // in the touch target to make dragging the handle easier (see pic above). | |
56 const int kSelectionHandleHorizPadding = 10; | 46 const int kSelectionHandleHorizPadding = 10; |
57 const int kSelectionHandleVertPadding = 20; | 47 const int kSelectionHandleVertPadding = 20; |
58 | 48 |
59 const int kContextMenuTimoutMs = 200; | 49 const int kContextMenuTimoutMs = 200; |
60 | 50 |
61 const int kSelectionHandleQuickFadeDurationMs = 50; | 51 const int kSelectionHandleQuickFadeDurationMs = 50; |
62 | 52 |
63 // Minimum height for selection handle bar. If the bar height is going to be | 53 // Minimum height for selection handle bar. If the bar height is going to be |
64 // less than this value, handle will not be shown. | 54 // less than this value, handle will not be shown. |
65 const int kSelectionHandleBarMinHeight = 5; | 55 const int kSelectionHandleBarMinHeight = 5; |
66 // Maximum amount that selection handle bar can stick out of client view's | 56 // Maximum amount that selection handle bar can stick out of client view's |
67 // boundaries. | 57 // boundaries. |
68 const int kSelectionHandleBarBottomAllowance = 3; | 58 const int kSelectionHandleBarBottomAllowance = 3; |
69 | 59 |
70 // Creates a widget to host SelectionHandleView. | 60 // Creates a widget to host SelectionHandleView. |
71 views::Widget* CreateTouchSelectionPopupWidget( | 61 views::Widget* CreateTouchSelectionPopupWidget( |
72 gfx::NativeView context, | 62 gfx::NativeView context, |
73 views::WidgetDelegate* widget_delegate) { | 63 views::WidgetDelegate* widget_delegate) { |
74 views::Widget* widget = new views::Widget; | 64 views::Widget* widget = new views::Widget; |
75 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); | 65 views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); |
76 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; | 66 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; |
77 params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; | 67 params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE; |
78 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; | 68 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; |
79 params.parent = context; | 69 params.parent = context; |
80 params.delegate = widget_delegate; | 70 params.delegate = widget_delegate; |
81 widget->Init(params); | 71 widget->Init(params); |
82 return widget; | 72 return widget; |
83 } | 73 } |
84 | 74 |
mohsen
2014/11/07 16:52:27
The only difference between following 3 functions
mfomitchev
2014/11/10 04:04:12
I kind of like not having to pass id. And not havi
| |
85 gfx::Image* GetHandleImage() { | 75 gfx::Image* GetCenterHandleImage() { |
86 static gfx::Image* handle_image = NULL; | 76 static gfx::Image* handle_image = nullptr; |
87 if (!handle_image) { | 77 if (!handle_image) { |
88 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( | 78 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
89 IDR_TEXT_SELECTION_HANDLE); | 79 IDR_TEXT_SELECTION_HANDLE_CENTER); |
90 } | 80 } |
91 return handle_image; | 81 return handle_image; |
92 } | 82 } |
93 | 83 |
94 gfx::Size GetHandleImageSize() { | 84 gfx::Image* GetLeftHandleImage() { |
95 return GetHandleImage()->Size(); | 85 static gfx::Image* handle_image = nullptr; |
86 if (!handle_image) { | |
87 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( | |
88 IDR_TEXT_SELECTION_HANDLE_LEFT); | |
89 } | |
90 return handle_image; | |
96 } | 91 } |
97 | 92 |
98 // Cannot use gfx::UnionRect since it does not work for empty rects. | 93 gfx::Image* GetRightHandleImage() { |
99 gfx::Rect Union(const gfx::Rect& r1, const gfx::Rect& r2) { | 94 static gfx::Image* handle_image = nullptr; |
100 int rx = std::min(r1.x(), r2.x()); | 95 if (!handle_image) { |
101 int ry = std::min(r1.y(), r2.y()); | 96 handle_image = &ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
102 int rr = std::max(r1.right(), r2.right()); | 97 IDR_TEXT_SELECTION_HANDLE_RIGHT); |
103 int rb = std::max(r1.bottom(), r2.bottom()); | 98 } |
104 | 99 return handle_image; |
105 return gfx::Rect(rx, ry, rr - rx, rb - ry); | |
106 } | 100 } |
107 | 101 |
108 // Convenience methods to convert a |rect| from screen to the |client|'s | 102 // Return the appropriate handle image based on the bound's type |
103 gfx::Image* GetHandleImage(const ui::SelectionBound& bound) { | |
mohsen
2014/11/07 16:52:27
GetHandleImage(ui::SelectionBound::Type bound_type
mfomitchev
2014/11/10 04:04:12
Done.
| |
104 switch(bound.type) { | |
105 case ui::SelectionBound::LEFT: | |
106 return GetLeftHandleImage(); | |
107 case ui::SelectionBound::CENTER: | |
108 return GetCenterHandleImage(); | |
109 case ui::SelectionBound::RIGHT: | |
110 return GetRightHandleImage(); | |
111 default: | |
112 NOTREACHED() << "Invalid touch handle bound type."; | |
113 return nullptr; | |
114 }; | |
115 } | |
116 | |
117 enum Alignment {ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT}; | |
mohsen
2014/11/07 16:52:27
Can't we just use SelectionBound::Type enum?
mfomitchev
2014/11/10 04:04:12
Not sure what are you suggesting - have GetCursorA
mohsen
2014/11/10 22:25:59
You have codes like this:
Alignment alignment =
mfomitchev
2014/11/10 23:07:29
GetCursorAlignment is used twice, so doing this wo
mohsen
2014/11/13 22:59:56
What I was suggesting was to remove Alignment enum
mfomitchev
2014/11/13 23:49:51
Yup, that's how I understood it. Whether the align
| |
118 | |
119 // Determine the cursor line alignment to the handle image based on the bound | |
120 // type. Depends on the visual shapes of the handle image assets. | |
121 Alignment GetCursorAlignment(ui::SelectionBound::Type bound_type) { | |
122 switch (bound_type) { | |
123 case ui::SelectionBound::LEFT: | |
124 return ALIGN_RIGHT; | |
125 case ui::SelectionBound::RIGHT: | |
126 return ALIGN_LEFT; | |
127 case ui::SelectionBound::CENTER: | |
128 return ALIGN_CENTER; | |
129 default: | |
130 NOTREACHED() << "Undefined bound type for cursor alignment."; | |
131 return ALIGN_LEFT; | |
132 }; | |
133 } | |
134 | |
135 // Calculates the bounds of the widget containing the selection handle based | |
136 // on the SelectionBound's type and location | |
137 gfx::Rect GetSelectionWidgetBounds(const ui::SelectionBound& bound) { | |
138 Alignment cursor_alignment = GetCursorAlignment(bound.type); | |
139 gfx::Size image_size = GetHandleImage(bound)->Size(); | |
140 int widget_width = image_size.width() + 2 * kSelectionHandleHorizPadding; | |
141 int widget_height = bound.GetHeight() + image_size.height() + | |
142 kSelectionHandleVertPadding; | |
143 int widget_left = 0; | |
144 switch (cursor_alignment) { | |
145 case ALIGN_LEFT: | |
146 widget_left = bound.edge_top.x() - kSelectionHandleHorizPadding; | |
147 break; | |
148 case ALIGN_RIGHT: | |
149 widget_left = bound.edge_top.x() - image_size.width() - | |
150 kSelectionHandleHorizPadding; | |
151 break; | |
152 case ALIGN_CENTER: | |
153 widget_left = bound.edge_top.x() - widget_width / 2; | |
154 break; | |
155 }; | |
156 return gfx::Rect( | |
157 widget_left, bound.edge_top.y(), widget_width, widget_height); | |
158 } | |
159 | |
160 gfx::Size GetMaxHandleImageSize() { | |
161 static gfx::Size* max_size = nullptr; | |
mohsen
2014/11/07 16:52:27
Is this caching to prevent image load every time o
mfomitchev
2014/11/10 04:04:12
Done.
| |
162 if (!max_size) { | |
163 gfx::Rect center_rect = gfx::Rect(GetCenterHandleImage()->Size()); | |
164 gfx::Rect left_rect = gfx::Rect(GetLeftHandleImage()->Size()); | |
165 gfx::Rect right_rect = gfx::Rect(GetRightHandleImage()->Size()); | |
166 gfx::Rect union_rect = center_rect; | |
167 union_rect.Union(left_rect); | |
168 union_rect.Union(right_rect); | |
169 max_size = new gfx::Size(union_rect.size()); | |
170 } | |
171 return *max_size; | |
172 } | |
173 | |
174 // Convenience methods to convert a |bound| from screen to the |client|'s | |
109 // coordinate system and vice versa. | 175 // coordinate system and vice versa. |
110 // Note that this is not quite correct because it does not take into account | 176 // Note that this is not quite correct because it does not take into account |
111 // transforms such as rotation and scaling. This should be in TouchEditable. | 177 // transforms such as rotation and scaling. This should be in TouchEditable. |
112 // TODO(varunjain): Fix this. | 178 // TODO(varunjain): Fix this. |
113 gfx::Rect ConvertFromScreen(ui::TouchEditable* client, const gfx::Rect& rect) { | 179 ui::SelectionBound ConvertFromScreen(ui::TouchEditable* client, |
114 gfx::Point origin = rect.origin(); | 180 const ui::SelectionBound& bound) { |
115 client->ConvertPointFromScreen(&origin); | 181 ui::SelectionBound result = bound; |
116 return gfx::Rect(origin, rect.size()); | 182 gfx::Point edge_bottom = bound.edge_bottom; |
183 gfx::Point edge_top = bound.edge_top; | |
184 client->ConvertPointFromScreen(&edge_bottom); | |
185 client->ConvertPointFromScreen(&edge_top); | |
186 result.edge_bottom = edge_bottom; | |
187 result.edge_top = edge_top; | |
188 return result; | |
117 } | 189 } |
118 gfx::Rect ConvertToScreen(ui::TouchEditable* client, const gfx::Rect& rect) { | 190 |
119 gfx::Point origin = rect.origin(); | 191 ui::SelectionBound ConvertToScreen(ui::TouchEditable* client, |
120 client->ConvertPointToScreen(&origin); | 192 const ui::SelectionBound& bound) { |
121 return gfx::Rect(origin, rect.size()); | 193 ui::SelectionBound result = bound; |
194 gfx::Point edge_bottom = bound.edge_bottom; | |
195 gfx::Point edge_top = bound.edge_top; | |
196 client->ConvertPointToScreen(&edge_bottom); | |
197 client->ConvertPointToScreen(&edge_top); | |
198 result.edge_bottom = edge_bottom; | |
199 result.edge_top = edge_top; | |
200 return result; | |
201 } | |
202 | |
203 gfx::Rect BoundToRect(const ui::SelectionBound& bound) { | |
204 return gfx::Rect(bound.edge_top, | |
205 gfx::Size(0, bound.edge_bottom.y() - bound.edge_top.y())); | |
mohsen
2014/11/07 16:52:27
gfx::BoundingRect()
mfomitchev
2014/11/10 04:04:12
Done
| |
122 } | 206 } |
123 | 207 |
124 } // namespace | 208 } // namespace |
125 | 209 |
126 namespace views { | 210 namespace views { |
127 | 211 |
128 typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView; | 212 typedef TouchSelectionControllerImpl::EditingHandleView EditingHandleView; |
129 | 213 |
130 class TouchHandleWindowTargeter : public wm::MaskedWindowTargeter { | 214 class TouchHandleWindowTargeter : public wm::MaskedWindowTargeter { |
131 public: | 215 public: |
(...skipping 11 matching lines...) Expand all Loading... | |
143 DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter); | 227 DISALLOW_COPY_AND_ASSIGN(TouchHandleWindowTargeter); |
144 }; | 228 }; |
145 | 229 |
146 // A View that displays the text selection handle. | 230 // A View that displays the text selection handle. |
147 class TouchSelectionControllerImpl::EditingHandleView | 231 class TouchSelectionControllerImpl::EditingHandleView |
148 : public views::WidgetDelegateView { | 232 : public views::WidgetDelegateView { |
149 public: | 233 public: |
150 EditingHandleView(TouchSelectionControllerImpl* controller, | 234 EditingHandleView(TouchSelectionControllerImpl* controller, |
151 gfx::NativeView context) | 235 gfx::NativeView context) |
152 : controller_(controller), | 236 : controller_(controller), |
153 drag_offset_(0), | 237 image_(GetCenterHandleImage()), |
mohsen
2014/11/07 16:52:27
Can't we initialize image_ with nullptr?
mfomitchev
2014/11/10 04:04:12
I had that initially, but I feel better not having
| |
154 draw_invisible_(false) { | 238 draw_invisible_(false) { |
155 widget_.reset(CreateTouchSelectionPopupWidget(context, this)); | 239 widget_.reset(CreateTouchSelectionPopupWidget(context, this)); |
156 widget_->SetContentsView(this); | 240 widget_->SetContentsView(this); |
157 | 241 |
158 aura::Window* window = widget_->GetNativeWindow(); | 242 aura::Window* window = widget_->GetNativeWindow(); |
159 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>( | 243 window->SetEventTargeter(scoped_ptr<ui::EventTargeter>( |
160 new TouchHandleWindowTargeter(window, this))); | 244 new TouchHandleWindowTargeter(window, this))); |
161 | 245 |
162 // We are owned by the TouchSelectionController. | 246 // We are owned by the TouchSelectionController. |
163 set_owned_by_client(); | 247 set_owned_by_client(); |
164 } | 248 } |
165 | 249 |
166 ~EditingHandleView() override { SetWidgetVisible(false, false); } | 250 ~EditingHandleView() override { SetWidgetVisible(false, false); } |
167 | 251 |
252 const gfx::Image* image() const { return image_; } | |
253 | |
254 const ui::SelectionBound& selection_bound() { return selection_bound_; } | |
mohsen
2014/11/07 16:52:27
Apparently it is not used anywhere. So, you can re
mfomitchev
2014/11/10 04:04:12
Done.
| |
255 | |
168 // Overridden from views::WidgetDelegateView: | 256 // Overridden from views::WidgetDelegateView: |
169 bool WidgetHasHitTestMask() const override { return true; } | 257 bool WidgetHasHitTestMask() const override { return true; } |
170 | 258 |
171 void GetWidgetHitTestMask(gfx::Path* mask) const override { | 259 void GetWidgetHitTestMask(gfx::Path* mask) const override { |
172 gfx::Size image_size = GetHandleImageSize(); | 260 gfx::Size image_size = image_->Size(); |
173 mask->addRect(SkIntToScalar(0), SkIntToScalar(selection_rect_.height()), | 261 mask->addRect( |
262 SkIntToScalar(0), | |
263 SkIntToScalar(selection_bound_.GetHeight()), | |
174 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding, | 264 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding, |
175 SkIntToScalar(selection_rect_.height() + image_size.height() + | 265 SkIntToScalar(selection_bound_.GetHeight() + image_size.height() + |
176 kSelectionHandleVertPadding)); | 266 kSelectionHandleVertPadding)); |
177 } | 267 } |
178 | 268 |
179 void DeleteDelegate() override { | 269 void DeleteDelegate() override { |
180 // We are owned and deleted by TouchSelectionController. | 270 // We are owned and deleted by TouchSelectionController. |
181 } | 271 } |
182 | 272 |
183 // Overridden from views::View: | 273 // Overridden from views::View: |
184 void OnPaint(gfx::Canvas* canvas) override { | 274 void OnPaint(gfx::Canvas* canvas) override { |
185 if (draw_invisible_) | 275 if (draw_invisible_) |
186 return; | 276 return; |
187 gfx::Size image_size = GetHandleImageSize(); | |
188 int cursor_pos_x = image_size.width() / 2 - kSelectionHandleLineWidth + | |
189 kSelectionHandleHorizPadding; | |
190 | 277 |
278 Alignment cursor_alignment = GetCursorAlignment(selection_bound_.type); | |
279 int cursor_x = 0; | |
280 switch (cursor_alignment) { | |
281 case ALIGN_RIGHT: | |
282 cursor_x = selection_bound_.edge_top.x() - kSelectionHandleLineWidth; | |
283 break; | |
284 case ALIGN_LEFT: | |
285 cursor_x = selection_bound_.edge_top.x(); | |
286 break; | |
287 case ALIGN_CENTER: | |
288 cursor_x = | |
289 selection_bound_.edge_top.x() - kSelectionHandleLineWidth / 2; | |
290 break; | |
291 }; | |
191 // Draw the cursor line. | 292 // Draw the cursor line. |
192 canvas->FillRect( | 293 canvas->FillRect(gfx::Rect(cursor_x, |
193 gfx::Rect(cursor_pos_x, 0, | 294 0, |
194 2 * kSelectionHandleLineWidth + 1, selection_rect_.height()), | 295 kSelectionHandleLineWidth, |
195 kSelectionHandleLineColor); | 296 selection_bound_.GetHeight()), |
196 | 297 kSelectionHandleLineColor); |
197 // Draw the handle image. | 298 // Draw the handle image. |
198 canvas->DrawImageInt(*GetHandleImage()->ToImageSkia(), | 299 canvas->DrawImageInt(*image_->ToImageSkia(), |
199 kSelectionHandleHorizPadding, selection_rect_.height()); | 300 kSelectionHandleHorizPadding, selection_bound_.GetHeight()); |
200 } | 301 } |
201 | 302 |
202 void OnGestureEvent(ui::GestureEvent* event) override { | 303 void OnGestureEvent(ui::GestureEvent* event) override { |
203 event->SetHandled(); | 304 event->SetHandled(); |
204 switch (event->type()) { | 305 switch (event->type()) { |
205 case ui::ET_GESTURE_SCROLL_BEGIN: | 306 case ui::ET_GESTURE_SCROLL_BEGIN: { |
206 widget_->SetCapture(this); | 307 widget_->SetCapture(this); |
207 controller_->SetDraggingHandle(this); | 308 controller_->SetDraggingHandle(this); |
208 drag_offset_ = event->y() - selection_rect_.height() + | 309 gfx::Point selection_bound_center(selection_bound_.edge_top.x(), |
mohsen
2014/11/07 16:52:27
Height of selection bound might change during drag
mfomitchev
2014/11/10 04:04:12
That's a great point. I have tried a couple of thi
| |
209 kSelectionHandleVerticalDragOffset; | 310 selection_bound_.GetHeight() / 2); |
311 drag_offset_ = selection_bound_center - event->location(); | |
210 break; | 312 break; |
313 } | |
211 case ui::ET_GESTURE_SCROLL_UPDATE: { | 314 case ui::ET_GESTURE_SCROLL_UPDATE: { |
212 gfx::Point drag_pos(event->location().x(), | 315 controller_->SelectionHandleDragged(event->location() + drag_offset_); |
213 event->location().y() - drag_offset_); | |
214 controller_->SelectionHandleDragged(drag_pos); | |
215 break; | 316 break; |
216 } | 317 } |
217 case ui::ET_GESTURE_SCROLL_END: | 318 case ui::ET_GESTURE_SCROLL_END: |
218 case ui::ET_SCROLL_FLING_START: | 319 case ui::ET_SCROLL_FLING_START: |
219 widget_->ReleaseCapture(); | 320 widget_->ReleaseCapture(); |
220 controller_->SetDraggingHandle(NULL); | 321 controller_->SetDraggingHandle(nullptr); |
221 break; | 322 break; |
222 default: | 323 default: |
223 break; | 324 break; |
224 } | 325 } |
225 } | 326 } |
226 | 327 |
227 gfx::Size GetPreferredSize() const override { | 328 gfx::Size GetPreferredSize() const override { |
228 gfx::Size image_size = GetHandleImageSize(); | 329 gfx::Size image_size = image_->Size(); |
229 return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding, | 330 return gfx::Size(image_size.width() + 2 * kSelectionHandleHorizPadding, |
230 image_size.height() + selection_rect_.height() + | 331 image_size.height() + selection_bound_.GetHeight() + |
231 kSelectionHandleVertPadding); | 332 kSelectionHandleVertPadding); |
232 } | 333 } |
233 | 334 |
234 bool IsWidgetVisible() const { | 335 bool IsWidgetVisible() const { |
235 return widget_->IsVisible(); | 336 return widget_->IsVisible(); |
236 } | 337 } |
237 | 338 |
238 void SetWidgetVisible(bool visible, bool quick) { | 339 void SetWidgetVisible(bool visible, bool quick) { |
239 if (widget_->IsVisible() == visible) | 340 if (widget_->IsVisible() == visible) |
240 return; | 341 return; |
241 widget_->SetVisibilityAnimationDuration( | 342 widget_->SetVisibilityAnimationDuration( |
242 base::TimeDelta::FromMilliseconds( | 343 base::TimeDelta::FromMilliseconds( |
243 quick ? kSelectionHandleQuickFadeDurationMs : 0)); | 344 quick ? kSelectionHandleQuickFadeDurationMs : 0)); |
244 if (visible) | 345 if (visible) |
245 widget_->Show(); | 346 widget_->Show(); |
246 else | 347 else |
247 widget_->Hide(); | 348 widget_->Hide(); |
248 } | 349 } |
249 | 350 |
250 void SetSelectionRectInScreen(const gfx::Rect& rect) { | 351 void SetBoundInScreen(const ui::SelectionBound& bound) { |
251 gfx::Size image_size = GetHandleImageSize(); | 352 if (bound.type != selection_bound_.type) { |
252 selection_rect_ = rect; | 353 image_ = GetHandleImage(bound); |
253 gfx::Rect widget_bounds( | 354 // TODO(mfomitchev): Ideally we should update drag_offset_ as well: as the |
254 rect.x() - image_size.width() / 2 - kSelectionHandleHorizPadding, | 355 // bound type changes, the position of the line cursor in the handle view |
255 rect.y(), | 356 // changes as well. We don't do this, because it would cause a "flicker" |
256 image_size.width() + 2 * kSelectionHandleHorizPadding, | 357 // effect every time the handle orientation changes as the user is |
257 rect.height() + image_size.height() + kSelectionHandleVertPadding); | 358 // dragging the handle. So instead the issue we have is that the position |
258 widget_->SetBounds(widget_bounds); | 359 // of the handle relative to your finger changes slightly every time the |
259 } | 360 // handle changes its orientation. |
260 | 361 // This should be possible to fix once crbug.com/399721 is resolved. |
mohsen
2014/11/07 16:52:27
How is it possible to fix after crbug.com/399721?
mfomitchev
2014/11/10 04:04:12
Got rid of this comment, since the offset no longe
| |
261 gfx::Point GetScreenPosition() { | 362 SchedulePaint(); |
262 return widget_->GetClientAreaBoundsInScreen().origin(); | 363 } |
364 widget_->SetBounds(GetSelectionWidgetBounds(bound)); | |
365 selection_bound_ = bound; | |
366 aura::Window* window = widget_->GetNativeView(); | |
367 wm::ConvertPointFromScreen(window, &selection_bound_.edge_top); | |
368 wm::ConvertPointFromScreen(window, &selection_bound_.edge_bottom); | |
263 } | 369 } |
264 | 370 |
265 void SetDrawInvisible(bool draw_invisible) { | 371 void SetDrawInvisible(bool draw_invisible) { |
266 if (draw_invisible_ == draw_invisible) | 372 if (draw_invisible_ == draw_invisible) |
267 return; | 373 return; |
268 draw_invisible_ = draw_invisible; | 374 draw_invisible_ = draw_invisible; |
269 SchedulePaint(); | 375 SchedulePaint(); |
270 } | 376 } |
271 | 377 |
272 const gfx::Rect& selection_rect() const { return selection_rect_; } | |
273 | |
274 private: | 378 private: |
275 scoped_ptr<Widget> widget_; | 379 scoped_ptr<Widget> widget_; |
276 TouchSelectionControllerImpl* controller_; | 380 TouchSelectionControllerImpl* controller_; |
277 gfx::Rect selection_rect_; | |
278 | 381 |
279 // Vertical offset between the scroll event position and the drag position | 382 // In local coordinates |
280 // reported to the client view (see the ASCII figure at the top of the file | 383 ui::SelectionBound selection_bound_; |
281 // and its description for more details). | 384 gfx::Image* image_; |
282 int drag_offset_; | 385 |
386 // Distance from the touch-drag point to the middle of the handle's cursor | |
387 // line. | |
388 gfx::Vector2d drag_offset_; | |
283 | 389 |
284 // If set to true, the handle will not draw anything, hence providing an empty | 390 // If set to true, the handle will not draw anything, hence providing an empty |
285 // widget. We need this because we may want to stop showing the handle while | 391 // widget. We need this because we may want to stop showing the handle while |
286 // it is being dragged. Since it is being dragged, we cannot destroy the | 392 // it is being dragged. Since it is being dragged, we cannot destroy the |
287 // handle. | 393 // handle. |
288 bool draw_invisible_; | 394 bool draw_invisible_; |
289 | 395 |
290 DISALLOW_COPY_AND_ASSIGN(EditingHandleView); | 396 DISALLOW_COPY_AND_ASSIGN(EditingHandleView); |
291 }; | 397 }; |
292 | 398 |
293 TouchHandleWindowTargeter::TouchHandleWindowTargeter( | 399 TouchHandleWindowTargeter::TouchHandleWindowTargeter( |
294 aura::Window* window, | 400 aura::Window* window, |
295 EditingHandleView* handle_view) | 401 EditingHandleView* handle_view) |
296 : wm::MaskedWindowTargeter(window), | 402 : wm::MaskedWindowTargeter(window), |
297 handle_view_(handle_view) { | 403 handle_view_(handle_view) { |
298 } | 404 } |
299 | 405 |
300 bool TouchHandleWindowTargeter::GetHitTestMask(aura::Window* window, | 406 bool TouchHandleWindowTargeter::GetHitTestMask(aura::Window* window, |
301 gfx::Path* mask) const { | 407 gfx::Path* mask) const { |
302 const gfx::Rect& selection_rect = handle_view_->selection_rect(); | 408 handle_view_->GetWidgetHitTestMask(mask); |
303 gfx::Size image_size = GetHandleImageSize(); | |
304 mask->addRect(SkIntToScalar(0), SkIntToScalar(selection_rect.height()), | |
305 SkIntToScalar(image_size.width()) + 2 * kSelectionHandleHorizPadding, | |
306 SkIntToScalar(selection_rect.height() + image_size.height() + | |
307 kSelectionHandleVertPadding)); | |
308 return true; | 409 return true; |
309 } | 410 } |
310 | 411 |
311 TouchSelectionControllerImpl::TouchSelectionControllerImpl( | 412 TouchSelectionControllerImpl::TouchSelectionControllerImpl( |
312 ui::TouchEditable* client_view) | 413 ui::TouchEditable* client_view) |
313 : client_view_(client_view), | 414 : client_view_(client_view), |
314 client_widget_(NULL), | 415 client_widget_(nullptr), |
315 selection_handle_1_(new EditingHandleView(this, | 416 selection_handle_1_(new EditingHandleView(this, |
316 client_view->GetNativeView())), | 417 client_view->GetNativeView())), |
317 selection_handle_2_(new EditingHandleView(this, | 418 selection_handle_2_(new EditingHandleView(this, |
318 client_view->GetNativeView())), | 419 client_view->GetNativeView())), |
319 cursor_handle_(new EditingHandleView(this, | 420 cursor_handle_(new EditingHandleView(this, |
320 client_view->GetNativeView())), | 421 client_view->GetNativeView())), |
321 context_menu_(NULL), | 422 context_menu_(nullptr), |
322 dragging_handle_(NULL) { | 423 dragging_handle_(nullptr) { |
323 aura::Window* client_window = client_view_->GetNativeView(); | 424 aura::Window* client_window = client_view_->GetNativeView(); |
324 client_window->AddObserver(this); | 425 client_window->AddObserver(this); |
325 client_widget_ = Widget::GetTopLevelWidgetForNativeView(client_window); | 426 client_widget_ = Widget::GetTopLevelWidgetForNativeView(client_window); |
326 if (client_widget_) | 427 if (client_widget_) |
327 client_widget_->AddObserver(this); | 428 client_widget_->AddObserver(this); |
328 aura::Env::GetInstance()->AddPreTargetHandler(this); | 429 aura::Env::GetInstance()->AddPreTargetHandler(this); |
329 } | 430 } |
330 | 431 |
331 TouchSelectionControllerImpl::~TouchSelectionControllerImpl() { | 432 TouchSelectionControllerImpl::~TouchSelectionControllerImpl() { |
332 HideContextMenu(); | 433 HideContextMenu(); |
333 aura::Env::GetInstance()->RemovePreTargetHandler(this); | 434 aura::Env::GetInstance()->RemovePreTargetHandler(this); |
334 if (client_widget_) | 435 if (client_widget_) |
335 client_widget_->RemoveObserver(this); | 436 client_widget_->RemoveObserver(this); |
336 client_view_->GetNativeView()->RemoveObserver(this); | 437 client_view_->GetNativeView()->RemoveObserver(this); |
337 } | 438 } |
338 | 439 |
339 void TouchSelectionControllerImpl::SelectionChanged() { | 440 void TouchSelectionControllerImpl::SelectionChanged() { |
340 gfx::Rect r1, r2; | 441 ui::SelectionBound anchor, focus; |
341 client_view_->GetSelectionEndPoints(&r1, &r2); | 442 client_view_->GetSelectionEndPoints(&anchor, &focus); |
342 gfx::Rect screen_rect_1 = ConvertToScreen(client_view_, r1); | 443 ui::SelectionBound screen_bound_anchor = |
343 gfx::Rect screen_rect_2 = ConvertToScreen(client_view_, r2); | 444 ConvertToScreen(client_view_, anchor); |
445 ui::SelectionBound screen_bound_focus = ConvertToScreen(client_view_, focus); | |
344 gfx::Rect client_bounds = client_view_->GetBounds(); | 446 gfx::Rect client_bounds = client_view_->GetBounds(); |
345 if (r1.y() < client_bounds.y()) | 447 if (anchor.edge_top.y() < client_bounds.y()) |
346 r1.Inset(0, client_bounds.y() - r1.y(), 0, 0); | 448 anchor.edge_top.set_y(client_bounds.y()); |
347 if (r2.y() < client_bounds.y()) | 449 if (focus.edge_top.y() < client_bounds.y()) |
348 r2.Inset(0, client_bounds.y() - r2.y(), 0, 0); | 450 focus.edge_top.set_y(client_bounds.y()); |
349 gfx::Rect screen_rect_1_clipped = ConvertToScreen(client_view_, r1); | 451 ui::SelectionBound screen_bound_anchor_clipped = |
350 gfx::Rect screen_rect_2_clipped = ConvertToScreen(client_view_, r2); | 452 ConvertToScreen(client_view_, anchor); |
351 if (screen_rect_1_clipped == selection_end_point_1_clipped_ && | 453 ui::SelectionBound screen_bound_focus_clipped = |
352 screen_rect_2_clipped == selection_end_point_2_clipped_) | 454 ConvertToScreen(client_view_, focus); |
455 if (screen_bound_anchor_clipped == selection_bound_1_clipped_ && | |
456 screen_bound_focus_clipped == selection_bound_2_clipped_) | |
353 return; | 457 return; |
354 | 458 |
355 selection_end_point_1_ = screen_rect_1; | 459 selection_bound_1_ = screen_bound_anchor; |
356 selection_end_point_2_ = screen_rect_2; | 460 selection_bound_2_ = screen_bound_focus; |
357 selection_end_point_1_clipped_ = screen_rect_1_clipped; | 461 selection_bound_1_clipped_ = screen_bound_anchor_clipped; |
358 selection_end_point_2_clipped_ = screen_rect_2_clipped; | 462 selection_bound_2_clipped_ = screen_bound_focus_clipped; |
359 | 463 |
360 if (client_view_->DrawsHandles()) { | 464 if (client_view_->DrawsHandles()) { |
361 UpdateContextMenu(); | 465 UpdateContextMenu(); |
362 return; | 466 return; |
363 } | 467 } |
468 | |
364 if (dragging_handle_) { | 469 if (dragging_handle_) { |
mohsen
2014/11/07 16:52:27
During a drag handles might temporarily overlap, i
mfomitchev
2014/11/10 04:04:12
Another good catch. Fixed.
| |
365 // We need to reposition only the selection handle that is being dragged. | 470 // We need to reposition only the selection handle that is being dragged. |
366 // The other handle stays the same. Also, the selection handle being dragged | 471 // The other handle stays the same. Also, the selection handle being dragged |
367 // will always be at the end of selection, while the other handle will be at | 472 // will always be at the end of selection, while the other handle will be at |
368 // the start. | 473 // the start. |
369 // If the new location of this handle is out of client view, its widget | 474 // If the new location of this handle is out of client view, its widget |
370 // should not get hidden, since it should still receive touch events. | 475 // should not get hidden, since it should still receive touch events. |
371 // Hence, we are not using |SetHandleSelectionRect()| method here. | 476 // Hence, we are not using |SetHandleSelectionRect()| method here. |
372 dragging_handle_->SetSelectionRectInScreen(screen_rect_2_clipped); | 477 dragging_handle_->SetBoundInScreen(screen_bound_focus_clipped); |
373 | 478 |
374 // Temporary fix for selection handle going outside a window. On a webpage, | 479 // Temporary fix for selection handle going outside a window. On a webpage, |
375 // the page should scroll if the selection handle is dragged outside the | 480 // the page should scroll if the selection handle is dragged outside the |
376 // window. That does not happen currently. So we just hide the handle for | 481 // window. That does not happen currently. So we just hide the handle for |
377 // now. | 482 // now. |
378 // TODO(varunjain): Fix this: crbug.com/269003 | 483 // TODO(varunjain): Fix this: crbug.com/269003 |
379 dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(r2)); | 484 dragging_handle_->SetDrawInvisible(!ShouldShowHandleFor(focus)); |
380 | 485 |
381 if (dragging_handle_ != cursor_handle_.get()) { | 486 if (dragging_handle_ != cursor_handle_.get()) { |
382 // The non-dragging-handle might have recently become visible. | 487 // The non-dragging-handle might have recently become visible. |
383 EditingHandleView* non_dragging_handle = selection_handle_1_.get(); | 488 EditingHandleView* non_dragging_handle = selection_handle_1_.get(); |
384 if (dragging_handle_ == selection_handle_1_) { | 489 if (dragging_handle_ == selection_handle_1_) { |
385 non_dragging_handle = selection_handle_2_.get(); | 490 non_dragging_handle = selection_handle_2_.get(); |
386 // if handle 1 is being dragged, it is corresponding to the end of | 491 // if handle 1 is being dragged, it is corresponding to the end of |
387 // selection and the other handle to the start of selection. | 492 // selection and the other handle to the start of selection. |
388 selection_end_point_1_ = screen_rect_2; | 493 selection_bound_1_ = screen_bound_focus; |
389 selection_end_point_2_ = screen_rect_1; | 494 selection_bound_2_ = screen_bound_anchor; |
390 selection_end_point_1_clipped_ = screen_rect_2_clipped; | 495 selection_bound_1_clipped_ = screen_bound_focus_clipped; |
391 selection_end_point_2_clipped_ = screen_rect_1_clipped; | 496 selection_bound_2_clipped_ = screen_bound_anchor_clipped; |
392 } | 497 } |
393 SetHandleSelectionRect(non_dragging_handle, r1, screen_rect_1_clipped); | 498 SetHandleBound(non_dragging_handle, anchor, screen_bound_anchor_clipped); |
394 } | 499 } |
395 } else { | 500 } else { |
396 UpdateContextMenu(); | 501 UpdateContextMenu(); |
397 | 502 |
398 // Check if there is any selection at all. | 503 // Check if there is any selection at all. |
399 if (screen_rect_1.origin() == screen_rect_2.origin()) { | 504 if (screen_bound_anchor.edge_top == screen_bound_focus.edge_top) { |
400 selection_handle_1_->SetWidgetVisible(false, false); | 505 selection_handle_1_->SetWidgetVisible(false, false); |
401 selection_handle_2_->SetWidgetVisible(false, false); | 506 selection_handle_2_->SetWidgetVisible(false, false); |
402 SetHandleSelectionRect(cursor_handle_.get(), r1, screen_rect_1_clipped); | 507 SetHandleBound(cursor_handle_.get(), anchor, screen_bound_anchor_clipped); |
403 return; | 508 return; |
404 } | 509 } |
405 | 510 |
406 cursor_handle_->SetWidgetVisible(false, false); | 511 cursor_handle_->SetWidgetVisible(false, false); |
407 SetHandleSelectionRect(selection_handle_1_.get(), r1, | 512 SetHandleBound( |
408 screen_rect_1_clipped); | 513 selection_handle_1_.get(), anchor, screen_bound_anchor_clipped); |
409 SetHandleSelectionRect(selection_handle_2_.get(), r2, | 514 SetHandleBound( |
410 screen_rect_2_clipped); | 515 selection_handle_2_.get(), focus, screen_bound_focus_clipped); |
411 } | 516 } |
412 } | 517 } |
413 | 518 |
414 bool TouchSelectionControllerImpl::IsHandleDragInProgress() { | 519 bool TouchSelectionControllerImpl::IsHandleDragInProgress() { |
415 return !!dragging_handle_; | 520 return !!dragging_handle_; |
416 } | 521 } |
417 | 522 |
418 void TouchSelectionControllerImpl::HideHandles(bool quick) { | 523 void TouchSelectionControllerImpl::HideHandles(bool quick) { |
419 selection_handle_1_->SetWidgetVisible(false, quick); | 524 selection_handle_1_->SetWidgetVisible(false, quick); |
420 selection_handle_2_->SetWidgetVisible(false, quick); | 525 selection_handle_2_->SetWidgetVisible(false, quick); |
(...skipping 14 matching lines...) Expand all Loading... | |
435 DCHECK(dragging_handle_); | 540 DCHECK(dragging_handle_); |
436 gfx::Point drag_pos_in_client = drag_pos; | 541 gfx::Point drag_pos_in_client = drag_pos; |
437 ConvertPointToClientView(dragging_handle_, &drag_pos_in_client); | 542 ConvertPointToClientView(dragging_handle_, &drag_pos_in_client); |
438 | 543 |
439 if (dragging_handle_ == cursor_handle_.get()) { | 544 if (dragging_handle_ == cursor_handle_.get()) { |
440 client_view_->MoveCaretTo(drag_pos_in_client); | 545 client_view_->MoveCaretTo(drag_pos_in_client); |
441 return; | 546 return; |
442 } | 547 } |
443 | 548 |
444 // Find the stationary selection handle. | 549 // Find the stationary selection handle. |
445 gfx::Rect fixed_handle_rect = selection_end_point_1_; | 550 ui::SelectionBound anchor_bound = |
446 if (selection_handle_1_ == dragging_handle_) | 551 selection_handle_1_ == dragging_handle_ ? selection_bound_2_ |
447 fixed_handle_rect = selection_end_point_2_; | 552 : selection_bound_1_; |
448 | 553 |
449 // Find selection end points in client_view's coordinate system. | 554 // Find selection end points in client_view's coordinate system. |
450 gfx::Point p2 = fixed_handle_rect.origin(); | 555 gfx::Point p2 = anchor_bound.edge_top; |
451 p2.Offset(0, fixed_handle_rect.height() / 2); | 556 p2.Offset(0, (anchor_bound.edge_bottom.y() - anchor_bound.edge_top.y()) / 2); |
mohsen
2014/11/07 16:52:27
anchor_bound.GetHeight() / 2
mfomitchev
2014/11/10 04:04:12
Done.
| |
452 client_view_->ConvertPointFromScreen(&p2); | 557 client_view_->ConvertPointFromScreen(&p2); |
453 | 558 |
454 // Instruct client_view to select the region between p1 and p2. The position | 559 // Instruct client_view to select the region between p1 and p2. The position |
455 // of |fixed_handle| is the start and that of |dragging_handle| is the end | 560 // of |fixed_handle| is the start and that of |dragging_handle| is the end |
456 // of selection. | 561 // of selection. |
457 client_view_->SelectRect(p2, drag_pos_in_client); | 562 client_view_->SelectRect(p2, drag_pos_in_client); |
458 } | 563 } |
459 | 564 |
460 void TouchSelectionControllerImpl::ConvertPointToClientView( | 565 void TouchSelectionControllerImpl::ConvertPointToClientView( |
461 EditingHandleView* source, gfx::Point* point) { | 566 EditingHandleView* source, gfx::Point* point) { |
462 View::ConvertPointToScreen(source, point); | 567 View::ConvertPointToScreen(source, point); |
463 client_view_->ConvertPointFromScreen(point); | 568 client_view_->ConvertPointFromScreen(point); |
464 } | 569 } |
465 | 570 |
466 void TouchSelectionControllerImpl::SetHandleSelectionRect( | 571 void TouchSelectionControllerImpl::SetHandleBound( |
467 EditingHandleView* handle, | 572 EditingHandleView* handle, |
468 const gfx::Rect& rect, | 573 const ui::SelectionBound& bound, |
469 const gfx::Rect& rect_in_screen) { | 574 const ui::SelectionBound& bound_in_screen) { |
470 handle->SetWidgetVisible(ShouldShowHandleFor(rect), false); | 575 handle->SetWidgetVisible(ShouldShowHandleFor(bound), false); |
471 if (handle->IsWidgetVisible()) | 576 if (handle->IsWidgetVisible()) |
472 handle->SetSelectionRectInScreen(rect_in_screen); | 577 handle->SetBoundInScreen(bound_in_screen); |
473 } | 578 } |
474 | 579 |
475 bool TouchSelectionControllerImpl::ShouldShowHandleFor( | 580 bool TouchSelectionControllerImpl::ShouldShowHandleFor( |
476 const gfx::Rect& rect) const { | 581 const ui::SelectionBound& bound) const { |
477 if (rect.height() < kSelectionHandleBarMinHeight) | 582 if (bound.edge_bottom.y() - bound.edge_top.y() < kSelectionHandleBarMinHeight) |
mohsen
2014/11/07 16:52:27
GetHeight()
mfomitchev
2014/11/10 04:04:12
Done.
| |
478 return false; | 583 return false; |
479 gfx::Rect bounds = client_view_->GetBounds(); | 584 gfx::Rect client_bounds = client_view_->GetBounds(); |
480 bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance); | 585 client_bounds.Inset(0, 0, 0, -kSelectionHandleBarBottomAllowance); |
481 return bounds.Contains(rect); | 586 gfx::Rect selection_rect = |
587 gfx::Rect(bound.edge_top, gfx::Size(0, bound.GetHeight())); | |
mohsen
2014/11/07 16:52:27
gfx::BoundingRect()
mfomitchev
2014/11/10 04:04:12
Done.
| |
588 return client_bounds.Contains(selection_rect); | |
482 } | 589 } |
483 | 590 |
484 bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const { | 591 bool TouchSelectionControllerImpl::IsCommandIdEnabled(int command_id) const { |
485 return client_view_->IsCommandIdEnabled(command_id); | 592 return client_view_->IsCommandIdEnabled(command_id); |
486 } | 593 } |
487 | 594 |
488 void TouchSelectionControllerImpl::ExecuteCommand(int command_id, | 595 void TouchSelectionControllerImpl::ExecuteCommand(int command_id, |
489 int event_flags) { | 596 int event_flags) { |
490 HideContextMenu(); | 597 HideContextMenu(); |
491 client_view_->ExecuteCommand(command_id, event_flags); | 598 client_view_->ExecuteCommand(command_id, event_flags); |
492 } | 599 } |
493 | 600 |
494 void TouchSelectionControllerImpl::OpenContextMenu() { | 601 void TouchSelectionControllerImpl::OpenContextMenu() { |
495 // Context menu should appear centered on top of the selected region. | 602 // Context menu should appear centered on top of the selected region. |
496 const gfx::Rect rect = context_menu_->GetAnchorRect(); | 603 const gfx::Rect rect = context_menu_->GetAnchorRect(); |
497 const gfx::Point anchor(rect.CenterPoint().x(), rect.y()); | 604 const gfx::Point anchor(rect.CenterPoint().x(), rect.y()); |
498 HideContextMenu(); | 605 HideContextMenu(); |
499 client_view_->OpenContextMenu(anchor); | 606 client_view_->OpenContextMenu(anchor); |
500 } | 607 } |
501 | 608 |
502 void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) { | 609 void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) { |
503 if (menu == context_menu_) | 610 if (menu == context_menu_) |
504 context_menu_ = NULL; | 611 context_menu_ = nullptr; |
505 } | 612 } |
506 | 613 |
507 void TouchSelectionControllerImpl::OnAncestorWindowTransformed( | 614 void TouchSelectionControllerImpl::OnAncestorWindowTransformed( |
508 aura::Window* window, | 615 aura::Window* window, |
509 aura::Window* ancestor) { | 616 aura::Window* ancestor) { |
510 client_view_->DestroyTouchSelection(); | 617 client_view_->DestroyTouchSelection(); |
511 } | 618 } |
512 | 619 |
513 void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) { | 620 void TouchSelectionControllerImpl::OnWidgetClosing(Widget* widget) { |
514 DCHECK_EQ(client_widget_, widget); | 621 DCHECK_EQ(client_widget_, widget); |
515 client_widget_ = NULL; | 622 client_widget_ = nullptr; |
516 } | 623 } |
517 | 624 |
518 void TouchSelectionControllerImpl::OnWidgetBoundsChanged( | 625 void TouchSelectionControllerImpl::OnWidgetBoundsChanged( |
519 Widget* widget, | 626 Widget* widget, |
520 const gfx::Rect& new_bounds) { | 627 const gfx::Rect& new_bounds) { |
521 DCHECK_EQ(client_widget_, widget); | 628 DCHECK_EQ(client_widget_, widget); |
522 SelectionChanged(); | 629 SelectionChanged(); |
523 } | 630 } |
524 | 631 |
525 void TouchSelectionControllerImpl::OnKeyEvent(ui::KeyEvent* event) { | 632 void TouchSelectionControllerImpl::OnKeyEvent(ui::KeyEvent* event) { |
526 client_view_->DestroyTouchSelection(); | 633 client_view_->DestroyTouchSelection(); |
527 } | 634 } |
528 | 635 |
529 void TouchSelectionControllerImpl::OnMouseEvent(ui::MouseEvent* event) { | 636 void TouchSelectionControllerImpl::OnMouseEvent(ui::MouseEvent* event) { |
530 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient( | 637 aura::client::CursorClient* cursor_client = aura::client::GetCursorClient( |
531 client_view_->GetNativeView()->GetRootWindow()); | 638 client_view_->GetNativeView()->GetRootWindow()); |
532 if (!cursor_client || cursor_client->IsMouseEventsEnabled()) | 639 if (!cursor_client || cursor_client->IsMouseEventsEnabled()) |
533 client_view_->DestroyTouchSelection(); | 640 client_view_->DestroyTouchSelection(); |
534 } | 641 } |
535 | 642 |
536 void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) { | 643 void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) { |
537 client_view_->DestroyTouchSelection(); | 644 client_view_->DestroyTouchSelection(); |
538 } | 645 } |
539 | 646 |
540 void TouchSelectionControllerImpl::ContextMenuTimerFired() { | 647 void TouchSelectionControllerImpl::ContextMenuTimerFired() { |
541 // Get selection end points in client_view's space. | 648 // Get selection end points in client_view's space. |
542 gfx::Rect end_rect_1_in_screen; | 649 ui::SelectionBound b1_in_screen = selection_bound_1_clipped_; |
543 gfx::Rect end_rect_2_in_screen; | 650 ui::SelectionBound b2_in_screen = |
544 if (cursor_handle_->IsWidgetVisible()) { | 651 cursor_handle_->IsWidgetVisible() ? b1_in_screen |
545 end_rect_1_in_screen = selection_end_point_1_clipped_; | 652 : selection_bound_2_clipped_; |
546 end_rect_2_in_screen = end_rect_1_in_screen; | |
547 } else { | |
548 end_rect_1_in_screen = selection_end_point_1_clipped_; | |
549 end_rect_2_in_screen = selection_end_point_2_clipped_; | |
550 } | |
551 | |
552 // Convert from screen to client. | 653 // Convert from screen to client. |
553 gfx::Rect end_rect_1(ConvertFromScreen(client_view_, end_rect_1_in_screen)); | 654 ui::SelectionBound b1 = ConvertFromScreen(client_view_, b1_in_screen); |
554 gfx::Rect end_rect_2(ConvertFromScreen(client_view_, end_rect_2_in_screen)); | 655 ui::SelectionBound b2 = ConvertFromScreen(client_view_, b2_in_screen); |
555 | 656 |
556 // if selection is completely inside the view, we display the context menu | 657 // if selection is completely inside the view, we display the context menu |
557 // in the middle of the end points on the top. Else, we show it above the | 658 // in the middle of the end points on the top. Else, we show it above the |
558 // visible handle. If no handle is visible, we do not show the menu. | 659 // visible handle. If no handle is visible, we do not show the menu. |
559 gfx::Rect menu_anchor; | 660 gfx::Rect menu_anchor; |
560 if (ShouldShowHandleFor(end_rect_1) && | 661 if (ShouldShowHandleFor(b1) && ShouldShowHandleFor(b2)) |
561 ShouldShowHandleFor(end_rect_2)) | 662 menu_anchor = ui::RectBetweenSelectionBounds(b1_in_screen, b2_in_screen); |
562 menu_anchor = Union(end_rect_1_in_screen,end_rect_2_in_screen); | 663 else if (ShouldShowHandleFor(b1)) |
563 else if (ShouldShowHandleFor(end_rect_1)) | 664 menu_anchor = BoundToRect(b1_in_screen); |
564 menu_anchor = end_rect_1_in_screen; | 665 else if (ShouldShowHandleFor(b2)) |
565 else if (ShouldShowHandleFor(end_rect_2)) | 666 menu_anchor = BoundToRect(b2_in_screen); |
566 menu_anchor = end_rect_2_in_screen; | |
567 else | 667 else |
568 return; | 668 return; |
569 | 669 |
570 DCHECK(!context_menu_); | 670 DCHECK(!context_menu_); |
571 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor, | 671 context_menu_ = TouchEditingMenuView::Create(this, menu_anchor, |
572 GetHandleImageSize(), | 672 GetMaxHandleImageSize(), |
573 client_view_->GetNativeView()); | 673 client_view_->GetNativeView()); |
574 } | 674 } |
575 | 675 |
576 void TouchSelectionControllerImpl::StartContextMenuTimer() { | 676 void TouchSelectionControllerImpl::StartContextMenuTimer() { |
577 if (context_menu_timer_.IsRunning()) | 677 if (context_menu_timer_.IsRunning()) |
578 return; | 678 return; |
579 context_menu_timer_.Start( | 679 context_menu_timer_.Start( |
580 FROM_HERE, | 680 FROM_HERE, |
581 base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs), | 681 base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs), |
582 this, | 682 this, |
583 &TouchSelectionControllerImpl::ContextMenuTimerFired); | 683 &TouchSelectionControllerImpl::ContextMenuTimerFired); |
584 } | 684 } |
585 | 685 |
586 void TouchSelectionControllerImpl::UpdateContextMenu() { | 686 void TouchSelectionControllerImpl::UpdateContextMenu() { |
587 // Hide context menu to be shown when the timer fires. | 687 // Hide context menu to be shown when the timer fires. |
588 HideContextMenu(); | 688 HideContextMenu(); |
589 StartContextMenuTimer(); | 689 StartContextMenuTimer(); |
590 } | 690 } |
591 | 691 |
592 void TouchSelectionControllerImpl::HideContextMenu() { | 692 void TouchSelectionControllerImpl::HideContextMenu() { |
593 if (context_menu_) | 693 if (context_menu_) |
594 context_menu_->Close(); | 694 context_menu_->Close(); |
595 context_menu_ = NULL; | 695 context_menu_ = nullptr; |
596 context_menu_timer_.Stop(); | 696 context_menu_timer_.Stop(); |
597 } | 697 } |
598 | 698 |
599 gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() { | 699 gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() { |
600 return cursor_handle_->GetWidget()->GetNativeView(); | 700 return cursor_handle_->GetWidget()->GetNativeView(); |
601 } | 701 } |
602 | 702 |
603 gfx::Point TouchSelectionControllerImpl::GetSelectionHandle1Position() { | 703 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle1Bounds() { |
604 return selection_handle_1_->GetScreenPosition(); | 704 return selection_handle_1_->GetBoundsInScreen(); |
605 } | 705 } |
606 | 706 |
607 gfx::Point TouchSelectionControllerImpl::GetSelectionHandle2Position() { | 707 gfx::Rect TouchSelectionControllerImpl::GetSelectionHandle2Bounds() { |
608 return selection_handle_2_->GetScreenPosition(); | 708 return selection_handle_2_->GetBoundsInScreen(); |
609 } | 709 } |
610 | 710 |
611 gfx::Point TouchSelectionControllerImpl::GetCursorHandlePosition() { | 711 gfx::Rect TouchSelectionControllerImpl::GetCursorHandleBounds() { |
612 return cursor_handle_->GetScreenPosition(); | 712 return cursor_handle_->GetBoundsInScreen(); |
613 } | 713 } |
614 | 714 |
615 bool TouchSelectionControllerImpl::IsSelectionHandle1Visible() { | 715 bool TouchSelectionControllerImpl::IsSelectionHandle1Visible() { |
616 return selection_handle_1_->IsWidgetVisible(); | 716 return selection_handle_1_->IsWidgetVisible(); |
617 } | 717 } |
618 | 718 |
619 bool TouchSelectionControllerImpl::IsSelectionHandle2Visible() { | 719 bool TouchSelectionControllerImpl::IsSelectionHandle2Visible() { |
620 return selection_handle_2_->IsWidgetVisible(); | 720 return selection_handle_2_->IsWidgetVisible(); |
621 } | 721 } |
622 | 722 |
623 bool TouchSelectionControllerImpl::IsCursorHandleVisible() { | 723 bool TouchSelectionControllerImpl::IsCursorHandleVisible() { |
624 return cursor_handle_->IsWidgetVisible(); | 724 return cursor_handle_->IsWidgetVisible(); |
625 } | 725 } |
626 | 726 |
727 gfx::Rect TouchSelectionControllerImpl::GetExpectedHandleBounds( | |
728 const ui::SelectionBound& bound) { | |
729 return GetSelectionWidgetBounds(bound); | |
730 } | |
731 | |
732 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle1View() { | |
733 return selection_handle_1_.get(); | |
734 } | |
735 | |
736 views::WidgetDelegateView* TouchSelectionControllerImpl::GetHandle2View() { | |
737 return selection_handle_2_.get(); | |
738 } | |
739 | |
627 } // namespace views | 740 } // namespace views |
OLD | NEW |