Chromium Code Reviews| 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/label.h" | 5 #include "ui/views/controls/label.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <cmath> | 10 #include <cmath> |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 22 #include "ui/base/clipboard/scoped_clipboard_writer.h" | 22 #include "ui/base/clipboard/scoped_clipboard_writer.h" |
| 23 #include "ui/base/cursor/cursor.h" | 23 #include "ui/base/cursor/cursor.h" |
| 24 #include "ui/base/default_style.h" | 24 #include "ui/base/default_style.h" |
| 25 #include "ui/base/material_design/material_design_controller.h" | 25 #include "ui/base/material_design/material_design_controller.h" |
| 26 #include "ui/base/resource/resource_bundle.h" | 26 #include "ui/base/resource/resource_bundle.h" |
| 27 #include "ui/gfx/canvas.h" | 27 #include "ui/gfx/canvas.h" |
| 28 #include "ui/gfx/color_utils.h" | 28 #include "ui/gfx/color_utils.h" |
| 29 #include "ui/gfx/geometry/insets.h" | 29 #include "ui/gfx/geometry/insets.h" |
| 30 #include "ui/gfx/text_elider.h" | 30 #include "ui/gfx/text_elider.h" |
| 31 #include "ui/native_theme/native_theme.h" | 31 #include "ui/native_theme/native_theme.h" |
| 32 #include "ui/strings/grit/ui_strings.h" | |
| 33 #include "ui/views/controls/menu/menu_runner.h" | |
| 32 #include "ui/views/focus/focus_manager.h" | 34 #include "ui/views/focus/focus_manager.h" |
| 33 #include "ui/views/native_cursor.h" | 35 #include "ui/views/native_cursor.h" |
| 34 #include "ui/views/selection_controller.h" | 36 #include "ui/views/selection_controller.h" |
| 35 | 37 |
| 36 namespace views { | 38 namespace views { |
| 37 // static | 39 // static |
| 38 const char Label::kViewClassName[] = "Label"; | 40 const char Label::kViewClassName[] = "Label"; |
| 39 const int Label::kFocusBorderPadding = 1; | 41 const int Label::kFocusBorderPadding = 1; |
| 40 | 42 |
| 41 Label::Label() : Label(base::string16()) { | 43 Label::Label() : Label(base::string16()) { |
| (...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 537 selection_controller_->OnMouseReleased(event); | 539 selection_controller_->OnMouseReleased(event); |
| 538 } | 540 } |
| 539 | 541 |
| 540 void Label::OnMouseCaptureLost() { | 542 void Label::OnMouseCaptureLost() { |
| 541 if (!GetRenderTextForSelectionController()) | 543 if (!GetRenderTextForSelectionController()) |
| 542 return; | 544 return; |
| 543 | 545 |
| 544 selection_controller_->OnMouseCaptureLost(); | 546 selection_controller_->OnMouseCaptureLost(); |
| 545 } | 547 } |
| 546 | 548 |
| 549 bool Label::AcceleratorPressed(const ui::Accelerator& accelerator) { | |
| 550 // The only accelerator a Label needs to handle is the Copy command from the | |
|
msw
2016/11/09 18:32:52
Not CTRL+A for select all?
karandeepb
2016/11/15 10:54:32
My understanding of accelerators is that they are
msw
2016/11/15 20:06:44
Acknowledged, thanks for the explanation. 'Chrome
| |
| 551 // Chrome menu. | |
| 552 if(accelerator.key_code() == ui::VKEY_C && accelerator.IsCtrlDown()) { | |
|
msw
2016/11/09 18:32:52
nit: space after if, git cl format
karandeepb
2016/11/15 10:54:32
Done.
| |
| 553 CopyToClipboard(); | |
| 554 return true; | |
| 555 } | |
| 556 return false; | |
| 557 } | |
| 558 | |
| 559 bool Label::CanHandleAccelerators() const { | |
| 560 // See related comment in BrowserView::CutCopyPaste. | |
|
msw
2016/11/09 18:32:53
nit: please explain a bit more here; I'm not sure
karandeepb
2016/11/15 10:54:32
Done. I was referring to the following comment in
| |
| 561 return HasFocus() && GetRenderTextForSelectionController() && | |
| 562 View::CanHandleAccelerators(); | |
| 563 } | |
| 564 | |
| 565 bool Label::OnKeyPressed(const ui::KeyEvent& event) { | |
|
msw
2016/11/09 18:32:52
Should this use Textfield's GetCommandForKeyEvent
karandeepb
2016/11/15 10:54:32
Currently the TextEditCommand enum is only being u
msw
2016/11/15 20:06:44
Hmm, this is okay for now; worth considering some
| |
| 566 if (!GetRenderTextForSelectionController()) | |
| 567 return false; | |
| 568 | |
| 569 const bool shift = event.IsShiftDown(); | |
| 570 const bool control = event.IsControlDown(); | |
| 571 const bool alt = event.IsAltDown() || event.IsAltGrDown(); | |
| 572 | |
| 573 switch (event.key_code()) { | |
| 574 case ui::VKEY_C: | |
| 575 if (control && !alt && HasSelection()) { | |
|
msw
2016/11/09 18:32:53
nit && !obscured()? here and below?
karandeepb
2016/11/15 10:54:32
But shouldn't we consume the event (by returning t
msw
2016/11/15 20:06:44
Okay, that's fair, and the CopyToClipboard's early
| |
| 576 CopyToClipboard(); | |
| 577 return true; | |
| 578 } | |
| 579 break; | |
| 580 case ui::VKEY_INSERT: | |
| 581 if (control && !shift && HasSelection()) { | |
| 582 CopyToClipboard(); | |
| 583 return true; | |
| 584 } | |
| 585 break; | |
| 586 case ui::VKEY_A: | |
| 587 if (control && !alt && !text().empty()) { | |
| 588 SelectAll(); | |
| 589 if (HasSelection()) | |
|
msw
2016/11/09 18:32:53
Should this be a DCHECK given the !text().empty()
karandeepb
2016/11/15 10:54:32
Oh yeah, done.
| |
| 590 UpdateSelectionClipboard(); | |
|
msw
2016/11/09 18:32:53
Should this be a part of SelectAll?
karandeepb
2016/11/15 10:54:32
Don't think so. SelectAll is a part of the public
msw
2016/11/15 20:06:44
Acknowledged.
| |
| 591 return true; | |
| 592 } | |
| 593 break; | |
| 594 default: | |
| 595 break; | |
| 596 } | |
| 597 | |
| 598 return false; | |
| 599 } | |
| 600 | |
| 547 void Label::OnDeviceScaleFactorChanged(float device_scale_factor) { | 601 void Label::OnDeviceScaleFactorChanged(float device_scale_factor) { |
| 548 View::OnDeviceScaleFactorChanged(device_scale_factor); | 602 View::OnDeviceScaleFactorChanged(device_scale_factor); |
| 549 // When the device scale factor is changed, some font rendering parameters is | 603 // When the device scale factor is changed, some font rendering parameters is |
| 550 // changed (especially, hinting). The bounding box of the text has to be | 604 // changed (especially, hinting). The bounding box of the text has to be |
| 551 // re-computed based on the new parameters. See crbug.com/441439 | 605 // re-computed based on the new parameters. See crbug.com/441439 |
| 552 ResetLayout(); | 606 ResetLayout(); |
| 553 } | 607 } |
| 554 | 608 |
| 555 void Label::VisibilityChanged(View* starting_from, bool is_visible) { | 609 void Label::VisibilityChanged(View* starting_from, bool is_visible) { |
| 556 if (!is_visible) | 610 if (!is_visible) |
| 557 ClearRenderTextLines(); | 611 ClearRenderTextLines(); |
| 558 } | 612 } |
| 559 | 613 |
| 614 bool Label::IsCommandIdChecked(int command_id) const { | |
| 615 return true; | |
| 616 } | |
| 617 | |
| 618 bool Label::IsCommandIdEnabled(int command_id) const { | |
| 619 switch (command_id) { | |
| 620 case IDS_APP_COPY: | |
| 621 return HasSelection() && !obscured(); | |
| 622 case IDS_APP_SELECT_ALL: | |
| 623 return GetRenderTextForSelectionController() && !text().empty(); | |
| 624 } | |
| 625 return false; | |
| 626 } | |
| 627 | |
| 628 void Label::ExecuteCommand(int command_id, int event_flags) { | |
| 629 switch (command_id) { | |
| 630 case IDS_APP_COPY: | |
| 631 CopyToClipboard(); | |
| 632 break; | |
| 633 case IDS_APP_SELECT_ALL: | |
| 634 SelectAll(); | |
| 635 if (HasSelection()) | |
| 636 UpdateSelectionClipboard(); | |
| 637 break; | |
| 638 default: | |
| 639 NOTREACHED(); | |
| 640 } | |
| 641 } | |
| 642 | |
| 643 bool Label::GetAcceleratorForCommandId(int command_id, | |
|
msw
2016/11/09 18:32:52
nit: Share a helper with textfield if feasible.
karandeepb
2016/11/15 10:54:32
Do you think it's still necessary now that we are
msw
2016/11/15 20:06:44
Nope, the simpler inlined impl here makes sense fo
| |
| 644 ui::Accelerator* accelerator) const { | |
| 645 switch (command_id) { | |
| 646 case IDS_APP_UNDO: | |
| 647 *accelerator = ui::Accelerator(ui::VKEY_Z, ui::EF_CONTROL_DOWN); | |
| 648 return true; | |
| 649 | |
| 650 case IDS_APP_CUT: | |
| 651 *accelerator = ui::Accelerator(ui::VKEY_X, ui::EF_CONTROL_DOWN); | |
| 652 return true; | |
| 653 | |
| 654 case IDS_APP_COPY: | |
| 655 *accelerator = ui::Accelerator(ui::VKEY_C, ui::EF_CONTROL_DOWN); | |
| 656 return true; | |
| 657 | |
| 658 case IDS_APP_PASTE: | |
| 659 *accelerator = ui::Accelerator(ui::VKEY_V, ui::EF_CONTROL_DOWN); | |
| 660 return true; | |
| 661 | |
| 662 case IDS_APP_SELECT_ALL: | |
| 663 *accelerator = ui::Accelerator(ui::VKEY_A, ui::EF_CONTROL_DOWN); | |
| 664 return true; | |
| 665 | |
| 666 default: | |
| 667 return false; | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 void Label::ShowContextMenuForView(View* source, | |
| 672 const gfx::Point& point, | |
| 673 ui::MenuSourceType source_type) { | |
| 674 DCHECK(context_menu_contents_); | |
| 675 if (!GetRenderTextForSelectionController()) | |
| 676 return; | |
| 677 | |
| 678 context_menu_runner_.reset(new MenuRunner(context_menu_contents_.get(), | |
|
msw
2016/11/09 18:32:52
Would it suffice to initialize the runner once in/
karandeepb
2016/11/15 10:54:32
Although the MenuRunner documentation does not sta
msw
2016/11/15 20:06:44
Acknowledged.
| |
| 679 MenuRunner::HAS_MNEMONICS | | |
| 680 MenuRunner::CONTEXT_MENU | | |
| 681 MenuRunner::ASYNC)); | |
| 682 ignore_result(context_menu_runner_->RunMenuAt( | |
|
msw
2016/11/09 18:32:53
Perhaps we should check that the result isn't MENU
karandeepb
2016/11/15 10:54:32
But what to do if it is MENU_DELETED?
msw
2016/11/15 20:06:44
Right, it doesn't actually matter now, since the f
| |
| 683 GetWidget(), nullptr, gfx::Rect(point, gfx::Size()), MENU_ANCHOR_TOPLEFT, | |
| 684 source_type)); | |
| 685 } | |
| 686 | |
| 560 gfx::RenderText* Label::GetRenderTextForSelectionController() { | 687 gfx::RenderText* Label::GetRenderTextForSelectionController() { |
| 561 return const_cast<gfx::RenderText*>( | 688 return const_cast<gfx::RenderText*>( |
| 562 static_cast<const Label*>(this)->GetRenderTextForSelectionController()); | 689 static_cast<const Label*>(this)->GetRenderTextForSelectionController()); |
| 563 } | 690 } |
| 564 | 691 |
| 565 bool Label::IsReadOnly() const { | 692 bool Label::IsReadOnly() const { |
| 566 return true; | 693 return true; |
| 567 } | 694 } |
| 568 | 695 |
| 569 bool Label::SupportsDrag() const { | 696 bool Label::SupportsDrag() const { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 604 } | 731 } |
| 605 | 732 |
| 606 bool Label::PasteSelectionClipboard() { | 733 bool Label::PasteSelectionClipboard() { |
| 607 NOTREACHED(); | 734 NOTREACHED(); |
| 608 return false; | 735 return false; |
| 609 } | 736 } |
| 610 | 737 |
| 611 void Label::UpdateSelectionClipboard() { | 738 void Label::UpdateSelectionClipboard() { |
| 612 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) | 739 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) |
| 613 if (!obscured()) { | 740 if (!obscured()) { |
| 614 const gfx::RenderText* render_text = GetRenderTextForSelectionController(); | |
| 615 DCHECK(render_text); | |
| 616 const base::string16 selected_text = | |
| 617 render_text->GetTextFromRange(render_text->selection()); | |
| 618 ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_SELECTION) | 741 ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_SELECTION) |
| 619 .WriteText(selected_text); | 742 .WriteText(GetSelectedText()); |
| 620 } | 743 } |
| 621 #endif | 744 #endif |
| 622 } | 745 } |
| 623 | 746 |
| 624 const gfx::RenderText* Label::GetRenderTextForSelectionController() const { | 747 const gfx::RenderText* Label::GetRenderTextForSelectionController() const { |
| 625 if (!selectable()) | 748 if (!selectable()) |
| 626 return nullptr; | 749 return nullptr; |
| 627 MaybeBuildRenderTextLines(); | 750 MaybeBuildRenderTextLines(); |
| 628 | 751 |
| 629 // This may happen when the content bounds of the view are empty. | 752 // This may happen when the content bounds of the view are empty. |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 652 subpixel_rendering_enabled_ = true; | 775 subpixel_rendering_enabled_ = true; |
| 653 auto_color_readability_ = true; | 776 auto_color_readability_ = true; |
| 654 multi_line_ = false; | 777 multi_line_ = false; |
| 655 UpdateColorsFromTheme(GetNativeTheme()); | 778 UpdateColorsFromTheme(GetNativeTheme()); |
| 656 handles_tooltips_ = true; | 779 handles_tooltips_ = true; |
| 657 collapse_when_hidden_ = false; | 780 collapse_when_hidden_ = false; |
| 658 fixed_width_ = 0; | 781 fixed_width_ = 0; |
| 659 max_width_ = 0; | 782 max_width_ = 0; |
| 660 is_first_paint_text_ = true; | 783 is_first_paint_text_ = true; |
| 661 SetText(text); | 784 SetText(text); |
| 785 | |
| 786 // Only selectable labels will get requests to show the context menu, due to | |
| 787 // CanProcessEventsWithinSubtree. | |
| 788 BuildContextMenuContents(); | |
| 789 set_context_menu_controller(this); | |
| 790 | |
| 791 // This allows the BrowserView to pass the copy command from the Chrome menu | |
|
msw
2016/11/09 18:32:53
Should we also add CTRL+A and Ctrl+Insert? It seem
karandeepb
2016/11/15 10:54:32
See my comment above for "Not CTRL+A for select al
msw
2016/11/15 20:06:44
Acknowledged.
| |
| 792 // to the Label. | |
| 793 AddAccelerator(ui::Accelerator(ui::VKEY_C, ui::EF_CONTROL_DOWN)); | |
| 662 } | 794 } |
| 663 | 795 |
| 664 void Label::ResetLayout() { | 796 void Label::ResetLayout() { |
| 665 InvalidateLayout(); | 797 InvalidateLayout(); |
| 666 PreferredSizeChanged(); | 798 PreferredSizeChanged(); |
| 667 SchedulePaint(); | 799 SchedulePaint(); |
| 668 ClearRenderTextLines(); | 800 ClearRenderTextLines(); |
| 669 } | 801 } |
| 670 | 802 |
| 671 void Label::MaybeBuildRenderTextLines() const { | 803 void Label::MaybeBuildRenderTextLines() const { |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 863 | 995 |
| 864 void Label::ClearRenderTextLines() const { | 996 void Label::ClearRenderTextLines() const { |
| 865 // Persist the selection range if there is an active selection. | 997 // Persist the selection range if there is an active selection. |
| 866 if (HasSelection()) { | 998 if (HasSelection()) { |
| 867 stored_selection_range_ = | 999 stored_selection_range_ = |
| 868 GetRenderTextForSelectionController()->selection(); | 1000 GetRenderTextForSelectionController()->selection(); |
| 869 } | 1001 } |
| 870 lines_.clear(); | 1002 lines_.clear(); |
| 871 } | 1003 } |
| 872 | 1004 |
| 1005 base::string16 Label::GetSelectedText() const { | |
| 1006 const gfx::RenderText* render_text = GetRenderTextForSelectionController(); | |
| 1007 return render_text ? render_text->GetTextFromRange(render_text->selection()) | |
| 1008 : base::string16(); | |
| 1009 } | |
| 1010 | |
| 1011 void Label::CopyToClipboard() { | |
| 1012 if (!HasSelection() || obscured()) | |
| 1013 return; | |
| 1014 ui::ScopedClipboardWriter(ui::CLIPBOARD_TYPE_COPY_PASTE) | |
| 1015 .WriteText(GetSelectedText()); | |
| 1016 } | |
| 1017 | |
| 1018 void Label::BuildContextMenuContents() { | |
| 1019 DCHECK(!context_menu_contents_); | |
| 1020 context_menu_contents_.reset(new ui::SimpleMenuModel(this)); | |
|
karandeepb
2016/11/09 10:20:00
Do we want to show only Copy/SelectAll in the cont
msw
2016/11/09 18:32:52
Yeah, I think we should only show copy and select
karandeepb
2016/11/15 10:54:32
Done.
| |
| 1021 context_menu_contents_->AddItemWithStringId(IDS_APP_UNDO, IDS_APP_UNDO); | |
| 1022 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); | |
| 1023 context_menu_contents_->AddItemWithStringId(IDS_APP_CUT, IDS_APP_CUT); | |
| 1024 context_menu_contents_->AddItemWithStringId(IDS_APP_COPY, IDS_APP_COPY); | |
| 1025 context_menu_contents_->AddItemWithStringId(IDS_APP_PASTE, IDS_APP_PASTE); | |
| 1026 context_menu_contents_->AddItemWithStringId(IDS_APP_DELETE, IDS_APP_DELETE); | |
| 1027 context_menu_contents_->AddSeparator(ui::NORMAL_SEPARATOR); | |
| 1028 context_menu_contents_->AddItemWithStringId(IDS_APP_SELECT_ALL, | |
| 1029 IDS_APP_SELECT_ALL); | |
| 1030 } | |
| 1031 | |
| 873 } // namespace views | 1032 } // namespace views |
| OLD | NEW |