OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/controls/textfield/textfield.h" | 5 #include "ui/views/controls/textfield/textfield.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "grit/ui_strings.h" | 10 #include "grit/ui_strings.h" |
11 #include "ui/accessibility/ax_view_state.h" | 11 #include "ui/accessibility/ax_view_state.h" |
12 #include "ui/base/clipboard/scoped_clipboard_writer.h" | 12 #include "ui/base/clipboard/scoped_clipboard_writer.h" |
13 #include "ui/base/cursor/cursor.h" | 13 #include "ui/base/cursor/cursor.h" |
14 #include "ui/base/dragdrop/drag_drop_types.h" | 14 #include "ui/base/dragdrop/drag_drop_types.h" |
15 #include "ui/base/dragdrop/drag_utils.h" | 15 #include "ui/base/dragdrop/drag_utils.h" |
16 #include "ui/base/resource/resource_bundle.h" | 16 #include "ui/base/resource/resource_bundle.h" |
17 #include "ui/base/ui_base_switches_util.h" | 17 #include "ui/base/ui_base_switches_util.h" |
| 18 #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
18 #include "ui/events/event.h" | 19 #include "ui/events/event.h" |
19 #include "ui/events/keycodes/keyboard_codes.h" | 20 #include "ui/events/keycodes/keyboard_codes.h" |
20 #include "ui/gfx/canvas.h" | 21 #include "ui/gfx/canvas.h" |
21 #include "ui/gfx/display.h" | 22 #include "ui/gfx/display.h" |
22 #include "ui/gfx/insets.h" | 23 #include "ui/gfx/insets.h" |
23 #include "ui/gfx/screen.h" | 24 #include "ui/gfx/screen.h" |
24 #include "ui/native_theme/native_theme.h" | 25 #include "ui/native_theme/native_theme.h" |
25 #include "ui/views/background.h" | 26 #include "ui/views/background.h" |
26 #include "ui/views/controls/focusable_border.h" | 27 #include "ui/views/controls/focusable_border.h" |
27 #include "ui/views/controls/label.h" | 28 #include "ui/views/controls/label.h" |
(...skipping 28 matching lines...) Expand all Loading... |
56 const int kNoCommand = 0; | 57 const int kNoCommand = 0; |
57 | 58 |
58 void ConvertRectToScreen(const View* src, gfx::Rect* r) { | 59 void ConvertRectToScreen(const View* src, gfx::Rect* r) { |
59 DCHECK(src); | 60 DCHECK(src); |
60 | 61 |
61 gfx::Point new_origin = r->origin(); | 62 gfx::Point new_origin = r->origin(); |
62 View::ConvertPointToScreen(src, &new_origin); | 63 View::ConvertPointToScreen(src, &new_origin); |
63 r->set_origin(new_origin); | 64 r->set_origin(new_origin); |
64 } | 65 } |
65 | 66 |
| 67 // Get the drag selection timer delay, respecting animation scaling for testing. |
| 68 int GetDragSelectionDelay() { |
| 69 switch (ui::ScopedAnimationDurationScaleMode::duration_scale_mode()) { |
| 70 case ui::ScopedAnimationDurationScaleMode::NORMAL_DURATION: return 100; |
| 71 case ui::ScopedAnimationDurationScaleMode::FAST_DURATION: return 25; |
| 72 case ui::ScopedAnimationDurationScaleMode::SLOW_DURATION: return 400; |
| 73 case ui::ScopedAnimationDurationScaleMode::ZERO_DURATION: return 0; |
| 74 } |
| 75 return 100; |
| 76 } |
| 77 |
66 int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) { | 78 int GetCommandForKeyEvent(const ui::KeyEvent& event, bool has_selection) { |
67 if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode()) | 79 if (event.type() != ui::ET_KEY_PRESSED || event.IsUnicodeKeyCode()) |
68 return kNoCommand; | 80 return kNoCommand; |
69 | 81 |
70 const bool shift = event.IsShiftDown(); | 82 const bool shift = event.IsShiftDown(); |
71 const bool control = event.IsControlDown(); | 83 const bool control = event.IsControlDown(); |
72 const bool alt = event.IsAltDown() || event.IsAltGrDown(); | 84 const bool alt = event.IsAltDown() || event.IsAltGrDown(); |
73 switch (event.key_code()) { | 85 switch (event.key_code()) { |
74 case ui::VKEY_Z: | 86 case ui::VKEY_Z: |
75 if (control && !shift && !alt) | 87 if (control && !shift && !alt) |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
305 return; | 317 return; |
306 model_->InsertText(new_text); | 318 model_->InsertText(new_text); |
307 OnCaretBoundsChanged(); | 319 OnCaretBoundsChanged(); |
308 SchedulePaint(); | 320 SchedulePaint(); |
309 } | 321 } |
310 | 322 |
311 base::i18n::TextDirection Textfield::GetTextDirection() const { | 323 base::i18n::TextDirection Textfield::GetTextDirection() const { |
312 return GetRenderText()->GetTextDirection(); | 324 return GetRenderText()->GetTextDirection(); |
313 } | 325 } |
314 | 326 |
| 327 base::string16 Textfield::GetSelectedText() const { |
| 328 return model_->GetSelectedText(); |
| 329 } |
| 330 |
315 void Textfield::SelectAll(bool reversed) { | 331 void Textfield::SelectAll(bool reversed) { |
316 model_->SelectAll(reversed); | 332 model_->SelectAll(reversed); |
317 UpdateSelectionClipboard(); | 333 UpdateSelectionClipboard(); |
318 UpdateAfterChange(false, true); | 334 UpdateAfterChange(false, true); |
319 } | 335 } |
320 | 336 |
321 base::string16 Textfield::GetSelectedText() const { | |
322 return model_->GetSelectedText(); | |
323 } | |
324 | |
325 void Textfield::ClearSelection() { | 337 void Textfield::ClearSelection() { |
326 model_->ClearSelection(); | 338 model_->ClearSelection(); |
327 UpdateAfterChange(false, true); | 339 UpdateAfterChange(false, true); |
328 } | 340 } |
329 | 341 |
330 bool Textfield::HasSelection() const { | 342 bool Textfield::HasSelection() const { |
331 return !GetSelectedRange().is_empty(); | 343 return !GetSelectedRange().is_empty(); |
332 } | 344 } |
333 | 345 |
334 SkColor Textfield::GetTextColor() const { | 346 SkColor Textfield::GetTextColor() const { |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
545 PasteSelectionClipboard(event); | 557 PasteSelectionClipboard(event); |
546 } | 558 } |
547 } | 559 } |
548 #endif | 560 #endif |
549 } | 561 } |
550 | 562 |
551 return true; | 563 return true; |
552 } | 564 } |
553 | 565 |
554 bool Textfield::OnMouseDragged(const ui::MouseEvent& event) { | 566 bool Textfield::OnMouseDragged(const ui::MouseEvent& event) { |
| 567 last_drag_location_ = event.location(); |
| 568 |
555 // Don't adjust the cursor on a potential drag and drop, or if the mouse | 569 // Don't adjust the cursor on a potential drag and drop, or if the mouse |
556 // movement from the last mouse click does not exceed the drag threshold. | 570 // movement from the last mouse click does not exceed the drag threshold. |
557 if (initiating_drag_ || !event.IsOnlyLeftMouseButton() || | 571 if (initiating_drag_ || !event.IsOnlyLeftMouseButton() || |
558 !ExceededDragThreshold(event.location() - last_click_location_)) { | 572 !ExceededDragThreshold(last_drag_location_ - last_click_location_)) { |
559 return true; | 573 return true; |
560 } | 574 } |
561 | 575 |
562 OnBeforeUserAction(); | 576 // A timer is used to continuously scroll while selecting beyond side edges. |
563 model_->MoveCursorTo(event.location(), true); | 577 if ((event.location().x() > 0 && event.location().x() < size().width()) || |
564 if (aggregated_clicks_ == 1) { | 578 GetDragSelectionDelay() == 0) { |
565 model_->SelectWord(); | 579 drag_selection_timer_.Stop(); |
566 // Expand the selection so the initially selected word remains selected. | 580 SelectThroughLastDragLocation(); |
567 gfx::Range selection = GetRenderText()->selection(); | 581 } else if (!drag_selection_timer_.IsRunning()) { |
568 const size_t min = std::min(selection.GetMin(), | 582 drag_selection_timer_.Start( |
569 double_click_word_.GetMin()); | 583 FROM_HERE, base::TimeDelta::FromMilliseconds(GetDragSelectionDelay()), |
570 const size_t max = std::max(selection.GetMax(), | 584 this, &Textfield::SelectThroughLastDragLocation); |
571 double_click_word_.GetMax()); | |
572 const bool reversed = selection.is_reversed(); | |
573 selection.set_start(reversed ? max : min); | |
574 selection.set_end(reversed ? min : max); | |
575 model_->SelectRange(selection); | |
576 } | 585 } |
577 UpdateAfterChange(false, true); | 586 |
578 OnAfterUserAction(); | |
579 return true; | 587 return true; |
580 } | 588 } |
581 | 589 |
582 void Textfield::OnMouseReleased(const ui::MouseEvent& event) { | 590 void Textfield::OnMouseReleased(const ui::MouseEvent& event) { |
583 OnBeforeUserAction(); | 591 OnBeforeUserAction(); |
| 592 drag_selection_timer_.Stop(); |
584 // Cancel suspected drag initiations, the user was clicking in the selection. | 593 // Cancel suspected drag initiations, the user was clicking in the selection. |
585 if (initiating_drag_) | 594 if (initiating_drag_) |
586 MoveCursorTo(event.location(), false); | 595 MoveCursorTo(event.location(), false); |
587 initiating_drag_ = false; | 596 initiating_drag_ = false; |
588 UpdateSelectionClipboard(); | 597 UpdateSelectionClipboard(); |
589 OnAfterUserAction(); | 598 OnAfterUserAction(); |
590 } | 599 } |
591 | 600 |
592 bool Textfield::OnKeyPressed(const ui::KeyEvent& event) { | 601 bool Textfield::OnKeyPressed(const ui::KeyEvent& event) { |
593 bool handled = controller_ && controller_->HandleKeyEvent(this, event); | 602 bool handled = controller_ && controller_->HandleKeyEvent(this, event); |
(...skipping 941 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1535 render_text->DrawCursor(canvas, drop_cursor_position_); | 1544 render_text->DrawCursor(canvas, drop_cursor_position_); |
1536 | 1545 |
1537 canvas->Restore(); | 1546 canvas->Restore(); |
1538 } | 1547 } |
1539 | 1548 |
1540 void Textfield::MoveCursorTo(const gfx::Point& point, bool select) { | 1549 void Textfield::MoveCursorTo(const gfx::Point& point, bool select) { |
1541 if (model_->MoveCursorTo(point, select)) | 1550 if (model_->MoveCursorTo(point, select)) |
1542 UpdateAfterChange(false, true); | 1551 UpdateAfterChange(false, true); |
1543 } | 1552 } |
1544 | 1553 |
| 1554 void Textfield::SelectThroughLastDragLocation() { |
| 1555 OnBeforeUserAction(); |
| 1556 model_->MoveCursorTo(last_drag_location_, true); |
| 1557 if (aggregated_clicks_ == 1) { |
| 1558 model_->SelectWord(); |
| 1559 // Expand the selection so the initially selected word remains selected. |
| 1560 gfx::Range selection = GetRenderText()->selection(); |
| 1561 const size_t min = std::min(selection.GetMin(), |
| 1562 double_click_word_.GetMin()); |
| 1563 const size_t max = std::max(selection.GetMax(), |
| 1564 double_click_word_.GetMax()); |
| 1565 const bool reversed = selection.is_reversed(); |
| 1566 selection.set_start(reversed ? max : min); |
| 1567 selection.set_end(reversed ? min : max); |
| 1568 model_->SelectRange(selection); |
| 1569 } |
| 1570 UpdateAfterChange(false, true); |
| 1571 OnAfterUserAction(); |
| 1572 } |
| 1573 |
1545 void Textfield::OnCaretBoundsChanged() { | 1574 void Textfield::OnCaretBoundsChanged() { |
1546 if (GetInputMethod()) | 1575 if (GetInputMethod()) |
1547 GetInputMethod()->OnCaretBoundsChanged(this); | 1576 GetInputMethod()->OnCaretBoundsChanged(this); |
1548 if (touch_selection_controller_) | 1577 if (touch_selection_controller_) |
1549 touch_selection_controller_->SelectionChanged(); | 1578 touch_selection_controller_->SelectionChanged(); |
1550 } | 1579 } |
1551 | 1580 |
1552 void Textfield::OnBeforeUserAction() { | 1581 void Textfield::OnBeforeUserAction() { |
1553 DCHECK(!performing_user_action_); | 1582 DCHECK(!performing_user_action_); |
1554 performing_user_action_ = true; | 1583 performing_user_action_ = true; |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1681 const size_t length = selection_clipboard_text.length(); | 1710 const size_t length = selection_clipboard_text.length(); |
1682 range = gfx::Range(range.start() + length, range.end() + length); | 1711 range = gfx::Range(range.start() + length, range.end() + length); |
1683 } | 1712 } |
1684 model_->MoveCursorTo(gfx::SelectionModel(range, affinity)); | 1713 model_->MoveCursorTo(gfx::SelectionModel(range, affinity)); |
1685 UpdateAfterChange(true, true); | 1714 UpdateAfterChange(true, true); |
1686 OnAfterUserAction(); | 1715 OnAfterUserAction(); |
1687 } | 1716 } |
1688 } | 1717 } |
1689 | 1718 |
1690 } // namespace views | 1719 } // namespace views |
OLD | NEW |