diff options
author | mohsen <mohsen@chromium.org> | 2015-05-28 21:12:40 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-29 04:13:09 +0000 |
commit | 1d0063dd4fcc1d4ec66af570c8e41d4416649159 (patch) | |
tree | 86d0dcff66f0a7ffefda3b23456992936b9330f8 | |
parent | 7a6acf6c7d45e24f07781c69249d90967013bbe4 (diff) | |
download | chromium_src-1d0063dd4fcc1d4ec66af570c8e41d4416649159.zip chromium_src-1d0063dd4fcc1d4ec66af570c8e41d4416649159.tar.gz chromium_src-1d0063dd4fcc1d4ec66af570c8e41d4416649159.tar.bz2 |
Refactor touch selection quick menu
To use the touch selection quick menu in the upcoming unified touch
selection, a new interface is added to ui/touch_selection with an
implementation for Views. The implementation mostly copied code from the
old implementation.
COLLABORATOR=mfomitchev
BUG=399721
Review URL: https://codereview.chromium.org/1019353003
Cr-Commit-Position: refs/heads/master@{#331924}
20 files changed, 624 insertions, 411 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 0a1156b..d02c0d6 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1624,6 +1624,13 @@ '../ui/views/views.gyp:views', '../ui/views/views.gyp:views_test_support', ], + 'conditions': [ + ['use_aura==1', { + 'dependencies': [ + '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection', + ], + }], + ], }], ['use_aura==0 or chromeos==1', { 'sources!': [ diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 1dca8e1..1d5314f 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn @@ -302,6 +302,9 @@ if (!is_android) { "../../ui/views/widget/desktop_aura/x11_topmost_window_finder_interactive_uitest.cc", ] } + if (use_aura) { + deps += [ "//ui/touch_selection" ] + } } if (is_linux && !is_chromeos) { diff --git a/ui/touch_selection/BUILD.gn b/ui/touch_selection/BUILD.gn index e79c563..d680429 100644 --- a/ui/touch_selection/BUILD.gn +++ b/ui/touch_selection/BUILD.gn @@ -16,8 +16,6 @@ component("touch_selection") { "selection_event_type.h", "touch_handle.cc", "touch_handle.h", - "touch_handle_drawable_aura.cc", - "touch_handle_drawable_aura.h", "touch_handle_orientation.h", "touch_selection_controller.cc", "touch_selection_controller.h", @@ -27,20 +25,15 @@ component("touch_selection") { defines = [ "UI_TOUCH_SELECTION_IMPLEMENTATION" ] deps = [ - "//skia:skia", "//base:base", - "//ui/aura:aura", - "//ui/aura_extra:aura_extra", "//ui/base:base", - "//ui/compositor:compositor", "//ui/events:events", "//ui/events:gesture_detection", - "//ui/gfx:gfx", "//ui/gfx/geometry:geometry", ] - if (!use_aura) { - deps -= [ + if (use_aura) { + deps += [ "//skia:skia", "//ui/aura:aura", "//ui/aura_extra:aura_extra", @@ -48,9 +41,11 @@ component("touch_selection") { "//ui/gfx:gfx", ] - sources -= [ + sources += [ "touch_handle_drawable_aura.cc", "touch_handle_drawable_aura.h", + "touch_selection_menu_runner.cc", + "touch_selection_menu_runner.h", ] } } diff --git a/ui/touch_selection/touch_selection_menu_runner.cc b/ui/touch_selection/touch_selection_menu_runner.cc new file mode 100644 index 0000000..860a24b --- /dev/null +++ b/ui/touch_selection/touch_selection_menu_runner.cc @@ -0,0 +1,31 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/touch_selection/touch_selection_menu_runner.h" + +namespace ui { +namespace { + +TouchSelectionMenuRunner* g_touch_selection_menu_runner = nullptr; + +} // namespace + +TouchSelectionMenuRunner::~TouchSelectionMenuRunner() { + g_touch_selection_menu_runner = nullptr; +} + +TouchSelectionMenuRunner* TouchSelectionMenuRunner::GetInstance() { + return g_touch_selection_menu_runner; +} + +TouchSelectionMenuRunner::TouchSelectionMenuRunner() { + // TODO(mohsen): Ideally we should DCHECK that |g_touch_selection_menu_runner| + // is not set here, in order to make sure we don't create multiple menu + // runners accidentally. Currently, this is not possible because we can have + // multiple ViewsDelegate's at the same time which should not happen. See + // crbug.com/492991. + g_touch_selection_menu_runner = this; +} + +} // namespace ui diff --git a/ui/touch_selection/touch_selection_menu_runner.h b/ui/touch_selection/touch_selection_menu_runner.h new file mode 100644 index 0000000..8db3213 --- /dev/null +++ b/ui/touch_selection/touch_selection_menu_runner.h @@ -0,0 +1,65 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_TOUCH_SELECTION_TOUCH_SELECTION_MENU_RUNNER_H_ +#define UI_TOUCH_SELECTION_TOUCH_SELECTION_MENU_RUNNER_H_ + +#include "base/macros.h" +#include "ui/touch_selection/ui_touch_selection_export.h" + +namespace aura { +class Window; +} + +namespace gfx { +class Rect; +class Size; +} + +namespace ui { + +// Client interface for TouchSelectionMenuRunner. +class UI_TOUCH_SELECTION_EXPORT TouchSelectionMenuClient { + public: + virtual ~TouchSelectionMenuClient() {} + + virtual bool IsCommandIdEnabled(int command_id) const = 0; + virtual void ExecuteCommand(int command_id, int event_flags) = 0; + + // Called when the quick menu needs to run a context menu. Depending on the + // implementation, this may run the context menu synchronously, or request the + // menu to show up in which case the menu will run asynchronously at a later + // time. + virtual void RunContextMenu() = 0; +}; + +// An interface for the singleton object responsible for running touch selection +// quick menu. +class UI_TOUCH_SELECTION_EXPORT TouchSelectionMenuRunner { + public: + virtual ~TouchSelectionMenuRunner(); + + static TouchSelectionMenuRunner* GetInstance(); + + // Creates and displays the quick menu, if there is any command available. + // |anchor_rect| is in screen coordinates. + virtual void OpenMenu(TouchSelectionMenuClient* client, + const gfx::Rect& anchor_rect, + const gfx::Size& handle_image_size, + aura::Window* context) = 0; + + virtual void CloseMenu() = 0; + + virtual bool IsRunning() const = 0; + + protected: + TouchSelectionMenuRunner(); + + private: + DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuRunner); +}; + +} // namespace ui + +#endif // UI_TOUCH_SELECTION_TOUCH_SELECTION_MENU_RUNNER_H_ diff --git a/ui/touch_selection/ui_touch_selection.gyp b/ui/touch_selection/ui_touch_selection.gyp index 11cca1f..c615ff5 100644 --- a/ui/touch_selection/ui_touch_selection.gyp +++ b/ui/touch_selection/ui_touch_selection.gyp @@ -34,6 +34,8 @@ 'touch_handle_orientation.h', 'touch_selection_controller.cc', 'touch_selection_controller.h', + 'touch_selection_menu_runner.cc', + 'touch_selection_menu_runner.h', 'ui_touch_selection_export.h', ], 'include_dirs': [ @@ -51,6 +53,8 @@ 'sources!': [ 'touch_handle_drawable_aura.cc', 'touch_handle_drawable_aura.h', + 'touch_selection_menu_runner.cc', + 'touch_selection_menu_runner.h', ], }], ], diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 76e70cd..2769a11 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn @@ -99,6 +99,7 @@ component("views") { sources += gypi_values.views_aura_sources deps += [ "//ui/aura", + "//ui/touch_selection", "//ui/wm", ] if (!is_chromeos) { @@ -235,6 +236,7 @@ test("views_unittests") { deps += [ "//ui/aura", "//ui/aura:test_support", + "//ui/touch_selection", "//ui/wm", ] if (!is_chromeos) { diff --git a/ui/views/DEPS b/ui/views/DEPS index 6f7d8abb6..c1d3570 100644 --- a/ui/views/DEPS +++ b/ui/views/DEPS @@ -14,6 +14,7 @@ include_rules = [ "+ui/ozone/public", "+ui/resources/grit/ui_resources.h", "+ui/strings/grit/ui_strings.h", + "+ui/touch_selection", "+ui/wm/core", "+ui/wm/public", diff --git a/ui/views/touchui/touch_editing_menu.cc b/ui/views/touchui/touch_editing_menu.cc deleted file mode 100644 index 7b2c5b6..0000000 --- a/ui/views/touchui/touch_editing_menu.cc +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ui/views/touchui/touch_editing_menu.h" - -#include "base/strings/utf_string_conversions.h" -#include "ui/base/l10n/l10n_util.h" -#include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/canvas.h" -#include "ui/gfx/font_list.h" -#include "ui/gfx/geometry/insets.h" -#include "ui/gfx/text_utils.h" -#include "ui/strings/grit/ui_strings.h" -#include "ui/views/bubble/bubble_border.h" -#include "ui/views/bubble/bubble_frame_view.h" -#include "ui/views/controls/button/custom_button.h" -#include "ui/views/controls/button/label_button.h" -#include "ui/views/layout/box_layout.h" -#include "ui/views/widget/widget.h" - -namespace { - -const int kMenuCommands[] = {IDS_APP_CUT, - IDS_APP_COPY, - IDS_APP_PASTE}; -const int kSpacingBetweenButtons = 2; -const int kButtonSeparatorColor = SkColorSetARGB(13, 0, 0, 0); -const int kMenuButtonMinHeight = 38; -const int kMenuButtonMinWidth = 63; -const int kMenuMargin = 1; - -const char* kEllipsesButtonText = "..."; -const int kEllipsesButtonTag = -1; -} // namespace - -namespace views { - -TouchEditingMenuView::TouchEditingMenuView( - TouchEditingMenuController* controller, - const gfx::Rect& anchor_rect, - const gfx::Size& handle_image_size, - gfx::NativeView context) - : BubbleDelegateView(NULL, views::BubbleBorder::BOTTOM_CENTER), - controller_(controller) { - set_shadow(views::BubbleBorder::SMALL_SHADOW); - set_parent_window(context); - set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin)); - set_can_activate(false); - set_adjust_if_offscreen(true); - - SetLayoutManager(new BoxLayout(BoxLayout::kHorizontal, 0, 0, - kSpacingBetweenButtons)); - CreateButtons(); - - // After buttons are created, check if there is enough room between handles to - // show the menu and adjust anchor rect properly if needed, just in case the - // menu is needed to be shown under the selection. - gfx::Rect adjusted_anchor_rect(anchor_rect); - int menu_width = GetPreferredSize().width(); - if (menu_width > anchor_rect.width() - handle_image_size.width()) - adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height()); - SetAnchorRect(adjusted_anchor_rect); - - views::BubbleDelegateView::CreateBubble(this); - GetWidget()->Show(); -} - -TouchEditingMenuView::~TouchEditingMenuView() { -} - -// static -TouchEditingMenuView* TouchEditingMenuView::Create( - TouchEditingMenuController* controller, - const gfx::Rect& anchor_rect, - const gfx::Size& handle_image_size, - gfx::NativeView context) { - if (controller) { - for (size_t i = 0; i < arraysize(kMenuCommands); i++) { - if (controller->IsCommandIdEnabled(kMenuCommands[i])) { - return new TouchEditingMenuView(controller, anchor_rect, - handle_image_size, context); - } - } - } - return NULL; -} - -void TouchEditingMenuView::Close() { - if (GetWidget()) { - controller_ = NULL; - GetWidget()->Close(); - } -} - -void TouchEditingMenuView::WindowClosing() { - views::BubbleDelegateView::WindowClosing(); - if (controller_) - controller_->OnMenuClosed(this); -} - -void TouchEditingMenuView::ButtonPressed(Button* sender, - const ui::Event& event) { - if (controller_) { - if (sender->tag() != kEllipsesButtonTag) - controller_->ExecuteCommand(sender->tag(), event.flags()); - else - controller_->OpenContextMenu(); - } -} - -void TouchEditingMenuView::OnPaint(gfx::Canvas* canvas) { - BubbleDelegateView::OnPaint(canvas); - - // Draw separator bars. - for (int i = 0; i < child_count() - 1; ++i) { - View* child = child_at(i); - int x = child->bounds().right() + kSpacingBetweenButtons / 2; - canvas->FillRect(gfx::Rect(x, 0, 1, child->height()), - kButtonSeparatorColor); - } -} - -void TouchEditingMenuView::CreateButtons() { - RemoveAllChildViews(true); - for (size_t i = 0; i < arraysize(kMenuCommands); i++) { - int command_id = kMenuCommands[i]; - if (controller_ && controller_->IsCommandIdEnabled(command_id)) { - Button* button = CreateButton(l10n_util::GetStringUTF16(command_id), - command_id); - AddChildView(button); - } - } - - // Finally, add ellipses button. - AddChildView(CreateButton( - base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag)); - Layout(); -} - -Button* TouchEditingMenuView::CreateButton(const base::string16& title, - int tag) { - base::string16 label = gfx::RemoveAcceleratorChar(title, '&', NULL, NULL); - LabelButton* button = new LabelButton(this, label); - button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight)); - button->SetFocusable(true); - button->set_request_focus_on_press(false); - const gfx::FontList& font_list = - ui::ResourceBundle::GetSharedInstance().GetFontList( - ui::ResourceBundle::SmallFont); - button->SetFontList(font_list); - button->SetHorizontalAlignment(gfx::ALIGN_CENTER); - button->set_tag(tag); - return button; -} - -} // namespace views diff --git a/ui/views/touchui/touch_editing_menu.h b/ui/views/touchui/touch_editing_menu.h deleted file mode 100644 index 6aa1343..0000000 --- a/ui/views/touchui/touch_editing_menu.h +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_VIEWS_TOUCHUI_TOUCH_EDITING_MENU_H_ -#define UI_VIEWS_TOUCHUI_TOUCH_EDITING_MENU_H_ - -#include "ui/gfx/geometry/point.h" -#include "ui/views/bubble/bubble_delegate.h" -#include "ui/views/controls/button/button.h" -#include "ui/views/views_export.h" - -namespace gfx { -class Canvas; -} - -namespace views { -class TouchEditingMenuView; -class Widget; - -class VIEWS_EXPORT TouchEditingMenuController { - public: - // Checks if the specified menu command is supported. - virtual bool IsCommandIdEnabled(int command_id) const = 0; - - // Send a context menu command to the controller. - virtual void ExecuteCommand(int command_id, int event_flags) = 0; - - // Tell the controller that user has selected the context menu button. - virtual void OpenContextMenu() = 0; - - // Called when the menu is closed. - virtual void OnMenuClosed(TouchEditingMenuView* menu) = 0; - - protected: - virtual ~TouchEditingMenuController() {} -}; - -// A View that displays the touch context menu. -class VIEWS_EXPORT TouchEditingMenuView : public BubbleDelegateView, - public ButtonListener { - public: - ~TouchEditingMenuView() override; - - // If there are no actions available for the menu, returns NULL. Otherwise, - // returns a new instance of TouchEditingMenuView. - static TouchEditingMenuView* Create(TouchEditingMenuController* controller, - const gfx::Rect& anchor_rect, - const gfx::Size& handle_image_size, - gfx::NativeView context); - - void Close(); - - private: - TouchEditingMenuView(TouchEditingMenuController* controller, - const gfx::Rect& anchor_rect, - const gfx::Size& handle_image_size, - gfx::NativeView context); - - // views::WidgetDelegate overrides: - void WindowClosing() override; - - // Overridden from ButtonListener. - void ButtonPressed(Button* sender, const ui::Event& event) override; - - // Overridden from BubbleDelegateView. - void OnPaint(gfx::Canvas* canvas) override; - - // Queries the |controller_| for what elements to show in the menu and sizes - // the menu appropriately. - void CreateButtons(); - - // Helper method to create a single button. - Button* CreateButton(const base::string16& title, int tag); - - TouchEditingMenuController* controller_; - - DISALLOW_COPY_AND_ASSIGN(TouchEditingMenuView); -}; - -} // namespace views - -#endif // UI_VIEWS_TOUCHUI_TOUCH_SELECTION_CONTROLLER_IMPL_H_ diff --git a/ui/views/touchui/touch_selection_controller_impl.cc b/ui/views/touchui/touch_selection_controller_impl.cc index baf8118..4078728 100644 --- a/ui/views/touchui/touch_selection_controller_impl.cc +++ b/ui/views/touchui/touch_selection_controller_impl.cc @@ -19,6 +19,7 @@ #include "ui/resources/grit/ui_resources.h" #include "ui/strings/grit/ui_strings.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" #include "ui/wm/core/coordinate_conversion.h" #include "ui/wm/core/masked_window_targeter.h" @@ -60,7 +61,7 @@ const int kSelectionHandleVerticalDragOffset = 5; const int kSelectionHandleHorizPadding = 10; const int kSelectionHandleVertPadding = 20; -const int kContextMenuTimoutMs = 200; +const int kQuickMenuTimoutMs = 200; const int kSelectionHandleQuickFadeDurationMs = 50; @@ -415,7 +416,6 @@ TouchSelectionControllerImpl::TouchSelectionControllerImpl( cursor_handle_(new EditingHandleView(this, client_view->GetNativeView(), true)), - context_menu_(nullptr), command_executed_(false), dragging_handle_(nullptr) { selection_start_time_ = base::TimeTicks::Now(); @@ -430,7 +430,7 @@ TouchSelectionControllerImpl::TouchSelectionControllerImpl( TouchSelectionControllerImpl::~TouchSelectionControllerImpl() { UMA_HISTOGRAM_BOOLEAN("Event.TouchSelection.EndedWithAction", command_executed_); - HideContextMenu(); + HideQuickMenu(); aura::Env::GetInstance()->RemovePreTargetHandler(this); if (client_widget_) client_widget_->RemoveObserver(this); @@ -468,7 +468,7 @@ void TouchSelectionControllerImpl::SelectionChanged() { selection_bound_2_clipped_ = screen_bound_focus_clipped; if (client_view_->DrawsHandles()) { - UpdateContextMenu(); + UpdateQuickMenu(); return; } @@ -504,7 +504,7 @@ void TouchSelectionControllerImpl::SelectionChanged() { SetHandleBound(non_dragging_handle, anchor, screen_bound_anchor_clipped); } } else { - UpdateContextMenu(); + UpdateQuickMenu(); // Check if there is any selection at all. if (screen_bound_anchor.edge_top() == screen_bound_focus.edge_top() && @@ -537,9 +537,9 @@ void TouchSelectionControllerImpl::SetDraggingHandle( EditingHandleView* handle) { dragging_handle_ = handle; if (dragging_handle_) - HideContextMenu(); + HideQuickMenu(); else - StartContextMenuTimer(); + StartQuickMenuTimer(); } void TouchSelectionControllerImpl::SelectionHandleDragged( @@ -608,23 +608,16 @@ void TouchSelectionControllerImpl::ExecuteCommand(int command_id, base::TimeDelta::FromMilliseconds(500), base::TimeDelta::FromSeconds(60), 60); - HideContextMenu(); client_view_->ExecuteCommand(command_id, event_flags); } -void TouchSelectionControllerImpl::OpenContextMenu() { +void TouchSelectionControllerImpl::RunContextMenu() { // Context menu should appear centered on top of the selected region. - const gfx::Rect rect = context_menu_->GetAnchorRect(); + const gfx::Rect rect = GetQuickMenuAnchorRect(); const gfx::Point anchor(rect.CenterPoint().x(), rect.y()); - HideContextMenu(); client_view_->OpenContextMenu(anchor); } -void TouchSelectionControllerImpl::OnMenuClosed(TouchEditingMenuView* menu) { - if (menu == context_menu_) - context_menu_ = nullptr; -} - void TouchSelectionControllerImpl::OnAncestorWindowTransformed( aura::Window* window, aura::Window* ancestor) { @@ -659,19 +652,51 @@ void TouchSelectionControllerImpl::OnScrollEvent(ui::ScrollEvent* event) { client_view_->DestroyTouchSelection(); } -void TouchSelectionControllerImpl::ContextMenuTimerFired() { +void TouchSelectionControllerImpl::QuickMenuTimerFired() { + gfx::Rect menu_anchor = GetQuickMenuAnchorRect(); + if (menu_anchor == gfx::Rect()) + return; + + ui::TouchSelectionMenuRunner::GetInstance()->OpenMenu( + this, menu_anchor, GetMaxHandleImageSize(), + client_view_->GetNativeView()); +} + +void TouchSelectionControllerImpl::StartQuickMenuTimer() { + if (quick_menu_timer_.IsRunning()) + return; + quick_menu_timer_.Start( + FROM_HERE, + base::TimeDelta::FromMilliseconds(kQuickMenuTimoutMs), + this, + &TouchSelectionControllerImpl::QuickMenuTimerFired); +} + +void TouchSelectionControllerImpl::UpdateQuickMenu() { + // Hide quick menu to be shown when the timer fires. + HideQuickMenu(); + StartQuickMenuTimer(); +} + +void TouchSelectionControllerImpl::HideQuickMenu() { + if (ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()) + ui::TouchSelectionMenuRunner::GetInstance()->CloseMenu(); + quick_menu_timer_.Stop(); +} + +gfx::Rect TouchSelectionControllerImpl::GetQuickMenuAnchorRect() const { // Get selection end points in client_view's space. ui::SelectionBound b1_in_screen = selection_bound_1_clipped_; - ui::SelectionBound b2_in_screen = - cursor_handle_->IsWidgetVisible() ? b1_in_screen + ui::SelectionBound b2_in_screen = cursor_handle_->IsWidgetVisible() + ? b1_in_screen : selection_bound_2_clipped_; // Convert from screen to client. ui::SelectionBound b1 = ConvertFromScreen(client_view_, b1_in_screen); ui::SelectionBound b2 = ConvertFromScreen(client_view_, b2_in_screen); - // if selection is completely inside the view, we display the context menu - // in the middle of the end points on the top. Else, we show it above the - // visible handle. If no handle is visible, we do not show the menu. + // if selection is completely inside the view, we display the quick menu in + // the middle of the end points on the top. Else, we show it above the visible + // handle. If no handle is visible, we do not show the menu. gfx::Rect menu_anchor; if (ShouldShowHandleFor(b1) && ShouldShowHandleFor(b2)) menu_anchor = ui::RectBetweenSelectionBounds(b1_in_screen, b2_in_screen); @@ -680,39 +705,13 @@ void TouchSelectionControllerImpl::ContextMenuTimerFired() { else if (ShouldShowHandleFor(b2)) menu_anchor = BoundToRect(b2_in_screen); else - return; + return menu_anchor; // Enlarge the anchor rect so that the menu is offset from the text at least // by the same distance the handles are offset from the text. menu_anchor.Inset(0, -kSelectionHandleVerticalVisualOffset); - DCHECK(!context_menu_); - context_menu_ = TouchEditingMenuView::Create(this, menu_anchor, - GetMaxHandleImageSize(), - client_view_->GetNativeView()); -} - -void TouchSelectionControllerImpl::StartContextMenuTimer() { - if (context_menu_timer_.IsRunning()) - return; - context_menu_timer_.Start( - FROM_HERE, - base::TimeDelta::FromMilliseconds(kContextMenuTimoutMs), - this, - &TouchSelectionControllerImpl::ContextMenuTimerFired); -} - -void TouchSelectionControllerImpl::UpdateContextMenu() { - // Hide context menu to be shown when the timer fires. - HideContextMenu(); - StartContextMenuTimer(); -} - -void TouchSelectionControllerImpl::HideContextMenu() { - if (context_menu_) - context_menu_->Close(); - context_menu_ = nullptr; - context_menu_timer_.Stop(); + return menu_anchor; } gfx::NativeView TouchSelectionControllerImpl::GetCursorHandleNativeView() { diff --git a/ui/views/touchui/touch_selection_controller_impl.h b/ui/views/touchui/touch_selection_controller_impl.h index d7bad80..deafbd6 100644 --- a/ui/views/touchui/touch_selection_controller_impl.h +++ b/ui/views/touchui/touch_selection_controller_impl.h @@ -10,11 +10,13 @@ #include "ui/base/touch/selection_bound.h" #include "ui/base/touch/touch_editing_controller.h" #include "ui/gfx/geometry/point.h" -#include "ui/views/touchui/touch_editing_menu.h" +#include "ui/touch_selection/touch_selection_menu_runner.h" #include "ui/views/view.h" #include "ui/views/views_export.h" +#include "ui/views/widget/widget_observer.h" namespace views { +class WidgetDelegateView; namespace test { class WidgetTestInteractive; @@ -25,7 +27,7 @@ class WidgetTestInteractive; // touch interface. class VIEWS_EXPORT TouchSelectionControllerImpl : public ui::TouchEditingControllerDeprecated, - public TouchEditingMenuController, + public ui::TouchSelectionMenuClient, public aura::WindowObserver, public WidgetObserver, public ui::EventHandler { @@ -69,11 +71,10 @@ class VIEWS_EXPORT TouchSelectionControllerImpl // |bound| should be the clipped version of the selection bound. bool ShouldShowHandleFor(const ui::SelectionBound& bound) const; - // Overridden from TouchEditingMenuController. + // Overridden from ui::TouchSelectionMenuClient. bool IsCommandIdEnabled(int command_id) const override; void ExecuteCommand(int command_id, int event_flags) override; - void OpenContextMenu() override; - void OnMenuClosed(TouchEditingMenuView* menu) override; + void RunContextMenu() override; // Overriden from aura::WindowObserver. void OnAncestorWindowTransformed(aura::Window* source, @@ -91,16 +92,20 @@ class VIEWS_EXPORT TouchSelectionControllerImpl void OnMouseEvent(ui::MouseEvent* event) override; void OnScrollEvent(ui::ScrollEvent* event) override; - // Time to show context menu. - void ContextMenuTimerFired(); + // Time to show quick menu. + void QuickMenuTimerFired(); - void StartContextMenuTimer(); + void StartQuickMenuTimer(); - // Convenience method to update the position/visibility of the context menu. - void UpdateContextMenu(); + // Convenience method to update the position/visibility of the quick menu. + void UpdateQuickMenu(); - // Convenience method for hiding context menu. - void HideContextMenu(); + // Convenience method for hiding quick menu. + void HideQuickMenu(); + + // Convenience method to calculate anchor rect for quick menu, in screen + // coordinates. + gfx::Rect GetQuickMenuAnchorRect() const; // Convenience methods for testing. gfx::NativeView GetCursorHandleNativeView(); @@ -119,14 +124,13 @@ class VIEWS_EXPORT TouchSelectionControllerImpl scoped_ptr<EditingHandleView> selection_handle_1_; scoped_ptr<EditingHandleView> selection_handle_2_; scoped_ptr<EditingHandleView> cursor_handle_; - TouchEditingMenuView* context_menu_; bool command_executed_; base::TimeTicks selection_start_time_; - // Timer to trigger |context_menu| (|context_menu| is not shown if the - // selection handles are being updated. It appears only when the handles are - // stationary for a certain amount of time). - base::OneShotTimer<TouchSelectionControllerImpl> context_menu_timer_; + // Timer to trigger quick menu (Quick menu is not shown if the selection + // handles are being updated. It appears only when the handles are stationary + // for a certain amount of time). + base::OneShotTimer<TouchSelectionControllerImpl> quick_menu_timer_; // Pointer to the SelectionHandleView being dragged during a drag session. EditingHandleView* dragging_handle_; diff --git a/ui/views/touchui/touch_selection_controller_impl_unittest.cc b/ui/views/touchui/touch_selection_controller_impl_unittest.cc index 3c9a9cc..78de052 100644 --- a/ui/views/touchui/touch_selection_controller_impl_unittest.cc +++ b/ui/views/touchui/touch_selection_controller_impl_unittest.cc @@ -23,6 +23,7 @@ #include "ui/views/touchui/touch_selection_controller_impl.h" #include "ui/views/views_touch_selection_controller_factory.h" #include "ui/views/widget/widget.h" +#include "ui/views/widget/widget_delegate.h" using base::ASCIIToUTF16; using base::UTF16ToUTF8; @@ -36,12 +37,6 @@ const int kBarMinHeight = 5; // touch_selection_controller. const int kBarBottomAllowance = 3; -// Should match kMenuButtonWidth in touch_editing_menu. -const int kMenuButtonWidth = 63; - -// Should match size of kMenuCommands array in touch_editing_menu. -const int kMenuCommandCount = 3; - // For selection bounds |b1| and |b2| in a paragraph of text, returns -1 if |b1| // is physically before |b2|, +1 if |b2| is before |b1|, and 0 if they are at // the same location. @@ -762,69 +757,6 @@ TEST_F(TouchSelectionControllerImplTest, HandlesStackAboveParent) { targeter->FindTargetForEvent(root, &test_event3)); } -// A simple implementation of TouchEditingMenuController that enables all -// available commands. -class TestTouchEditingMenuController : public TouchEditingMenuController { - public: - TestTouchEditingMenuController() {} - ~TestTouchEditingMenuController() override {} - - // Overriden from TouchEditingMenuController. - bool IsCommandIdEnabled(int command_id) const override { - // Return true, since we want the menu to have all |kMenuCommandCount| - // available commands. - return true; - } - void ExecuteCommand(int command_id, int event_flags) override { - NOTREACHED(); - } - void OpenContextMenu() override { NOTREACHED(); } - void OnMenuClosed(TouchEditingMenuView* menu) override {} - - private: - DISALLOW_COPY_AND_ASSIGN(TestTouchEditingMenuController); -}; - -// Tests if anchor rect for touch editing quick menu is adjusted correctly based -// on the distance of handles. -TEST_F(TouchSelectionControllerImplTest, QuickMenuAdjustsAnchorRect) { - CreateWidget(); - aura::Window* window = widget_->GetNativeView(); - - scoped_ptr<TestTouchEditingMenuController> quick_menu_controller( - new TestTouchEditingMenuController()); - - // Some arbitrary size for touch editing handle image. - gfx::Size handle_image_size(10, 10); - - // Calculate the width of quick menu. In addition to |kMenuCommandCount| - // commands, there is an item for ellipsis. - int quick_menu_width = (kMenuCommandCount + 1) * kMenuButtonWidth + - kMenuCommandCount; - - // Set anchor rect's width a bit smaller than the quick menu width plus handle - // image width and check that anchor rect's height is adjusted. - gfx::Rect anchor_rect( - 0, 0, quick_menu_width + handle_image_size.width() - 10, 20); - TouchEditingMenuView* quick_menu(TouchEditingMenuView::Create( - quick_menu_controller.get(), anchor_rect, handle_image_size, window)); - anchor_rect.Inset(0, 0, 0, -handle_image_size.height()); - EXPECT_EQ(anchor_rect.ToString(), quick_menu->GetAnchorRect().ToString()); - - // Set anchor rect's width a bit greater than the quick menu width plus handle - // image width and check that anchor rect's height is not adjusted. - anchor_rect = - gfx::Rect(0, 0, quick_menu_width + handle_image_size.width() + 10, 20); - quick_menu = TouchEditingMenuView::Create( - quick_menu_controller.get(), anchor_rect, handle_image_size, window); - EXPECT_EQ(anchor_rect.ToString(), quick_menu->GetAnchorRect().ToString()); - - // Close the widget, hence quick menus, before quick menu controller goes out - // of scope. - widget_->CloseNow(); - widget_ = nullptr; -} - TEST_F(TouchSelectionControllerImplTest, MouseEventDeactivatesTouchSelection) { CreateTextfield(); EXPECT_FALSE(GetSelectionController()); diff --git a/ui/views/touchui/touch_selection_menu_runner_views.cc b/ui/views/touchui/touch_selection_menu_runner_views.cc new file mode 100644 index 0000000..6f44e52 --- /dev/null +++ b/ui/views/touchui/touch_selection_menu_runner_views.cc @@ -0,0 +1,249 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/touchui/touch_selection_menu_runner_views.h" + +#include "base/strings/utf_string_conversions.h" +#include "ui/aura/window.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/size.h" +#include "ui/gfx/text_utils.h" +#include "ui/strings/grit/ui_strings.h" +#include "ui/views/bubble/bubble_delegate.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/label_button.h" +#include "ui/views/layout/box_layout.h" + +namespace views { +namespace { + +const int kMenuCommands[] = {IDS_APP_CUT, IDS_APP_COPY, IDS_APP_PASTE}; +const int kSpacingBetweenButtons = 2; +const int kButtonSeparatorColor = SkColorSetARGB(13, 0, 0, 0); +const int kMenuButtonMinHeight = 38; +const int kMenuButtonMinWidth = 63; +const int kMenuMargin = 1; + +const char kEllipsesButtonText[] = "..."; +const int kEllipsesButtonTag = -1; + +} // namespace + +// A bubble that contains actions available for the selected text. An object of +// this type, as a BubbleDelegateView, manages its own lifetime. +class TouchSelectionMenuRunnerViews::Menu : public BubbleDelegateView, + public ButtonListener { + public: + // Closes the menu. This will eventually self-destroy the object. + void Close(); + + // Returns a new instance of Menu if there is any command available; + // otherwise, returns |nullptr|. + static Menu* Create(TouchSelectionMenuRunnerViews* owner, + ui::TouchSelectionMenuClient* client, + const gfx::Rect& anchor_rect, + const gfx::Size& handle_image_size, + aura::Window* context); + + private: + Menu(TouchSelectionMenuRunnerViews* owner, + ui::TouchSelectionMenuClient* client, + const gfx::Rect& anchor_rect, + const gfx::Size& handle_image_size, + aura::Window* context); + + ~Menu() override; + + // Queries the |client_| for what commands to show in the menu and sizes the + // menu appropriately. + void CreateButtons(); + + // Helper method to create a single button. + Button* CreateButton(const base::string16& title, int tag); + + // BubbleDelegateView: + void OnPaint(gfx::Canvas* canvas) override; + void WindowClosing() override; + + // ButtonListener: + void ButtonPressed(Button* sender, const ui::Event& event) override; + + TouchSelectionMenuRunnerViews* owner_; + ui::TouchSelectionMenuClient* const client_; + + DISALLOW_COPY_AND_ASSIGN(Menu); +}; + +TouchSelectionMenuRunnerViews::Menu* +TouchSelectionMenuRunnerViews::Menu::Create( + TouchSelectionMenuRunnerViews* owner, + ui::TouchSelectionMenuClient* client, + const gfx::Rect& anchor_rect, + const gfx::Size& handle_image_size, + aura::Window* context) { + DCHECK(client); + + for (size_t i = 0; i < arraysize(kMenuCommands); i++) { + if (client->IsCommandIdEnabled(kMenuCommands[i])) + return new Menu(owner, client, anchor_rect, handle_image_size, context); + } + + // No command is available, so return |nullptr|. + return nullptr; +} + +TouchSelectionMenuRunnerViews::Menu::Menu(TouchSelectionMenuRunnerViews* owner, + ui::TouchSelectionMenuClient* client, + const gfx::Rect& anchor_rect, + const gfx::Size& handle_image_size, + aura::Window* context) + : BubbleDelegateView(nullptr, BubbleBorder::BOTTOM_CENTER), + owner_(owner), + client_(client) { + DCHECK(owner_); + DCHECK(client_); + + set_shadow(BubbleBorder::SMALL_SHADOW); + set_parent_window(context); + set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin)); + set_can_activate(false); + set_adjust_if_offscreen(true); + EnableCanvasFlippingForRTLUI(true); + + SetLayoutManager( + new BoxLayout(BoxLayout::kHorizontal, 0, 0, kSpacingBetweenButtons)); + CreateButtons(); + + // After buttons are created, check if there is enough room between handles to + // show the menu and adjust anchor rect properly if needed, just in case the + // menu is needed to be shown under the selection. + gfx::Rect adjusted_anchor_rect(anchor_rect); + int menu_width = GetPreferredSize().width(); + // TODO(mfomitchev): This assumes that the handles are center-aligned to the + // |achor_rect| edges, which is not true. We should fix this, perhaps by + // passing down the cumulative width occupied by the handles within + // |anchor_rect| plus the handle image height instead of |handle_image_size|. + // Perhaps we should also allow for some minimum padding. + if (menu_width > anchor_rect.width() - handle_image_size.width()) + adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height()); + SetAnchorRect(adjusted_anchor_rect); + + BubbleDelegateView::CreateBubble(this); + GetWidget()->Show(); +} + +TouchSelectionMenuRunnerViews::Menu::~Menu() { +} + +void TouchSelectionMenuRunnerViews::Menu::CreateButtons() { + for (size_t i = 0; i < arraysize(kMenuCommands); i++) { + int command_id = kMenuCommands[i]; + if (!client_->IsCommandIdEnabled(command_id)) + continue; + + Button* button = + CreateButton(l10n_util::GetStringUTF16(command_id), command_id); + AddChildView(button); + } + + // Finally, add ellipses button. + AddChildView( + CreateButton(base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag)); + Layout(); +} + +Button* TouchSelectionMenuRunnerViews::Menu::CreateButton( + const base::string16& title, + int tag) { + base::string16 label = + gfx::RemoveAcceleratorChar(title, '&', nullptr, nullptr); + LabelButton* button = new LabelButton(this, label); + button->SetMinSize(gfx::Size(kMenuButtonMinWidth, kMenuButtonMinHeight)); + button->SetFocusable(true); + button->set_request_focus_on_press(false); + const gfx::FontList& font_list = + ui::ResourceBundle::GetSharedInstance().GetFontList( + ui::ResourceBundle::SmallFont); + button->SetFontList(font_list); + button->SetHorizontalAlignment(gfx::ALIGN_CENTER); + button->set_tag(tag); + return button; +} + +void TouchSelectionMenuRunnerViews::Menu::Close() { + // Closing the widget will self-destroy this object. + Widget* widget = GetWidget(); + if (widget && !widget->IsClosed()) + widget->Close(); + owner_ = nullptr; +} + +void TouchSelectionMenuRunnerViews::Menu::OnPaint(gfx::Canvas* canvas) { + BubbleDelegateView::OnPaint(canvas); + + // Draw separator bars. + for (int i = 0; i < child_count() - 1; ++i) { + View* child = child_at(i); + int x = child->bounds().right() + kSpacingBetweenButtons / 2; + canvas->FillRect(gfx::Rect(x, 0, 1, child->height()), + kButtonSeparatorColor); + } +} + +void TouchSelectionMenuRunnerViews::Menu::WindowClosing() { + DCHECK_IMPLIES(owner_, owner_->menu_ == this); + BubbleDelegateView::WindowClosing(); + if (owner_) + owner_->menu_ = nullptr; +} + +void TouchSelectionMenuRunnerViews::Menu::ButtonPressed( + Button* sender, + const ui::Event& event) { + Close(); + if (sender->tag() != kEllipsesButtonTag) + client_->ExecuteCommand(sender->tag(), event.flags()); + else + client_->RunContextMenu(); +} + +TouchSelectionMenuRunnerViews::TouchSelectionMenuRunnerViews() + : menu_(nullptr) { +} + +TouchSelectionMenuRunnerViews::~TouchSelectionMenuRunnerViews() { + CloseMenu(); +} + +gfx::Rect TouchSelectionMenuRunnerViews::GetAnchorRectForTest() const { + return menu_ ? menu_->GetAnchorRect() : gfx::Rect(); +} + +void TouchSelectionMenuRunnerViews::OpenMenu( + ui::TouchSelectionMenuClient* client, + const gfx::Rect& anchor_rect, + const gfx::Size& handle_image_size, + aura::Window* context) { + CloseMenu(); + + menu_ = Menu::Create(this, client, anchor_rect, handle_image_size, context); +} + +void TouchSelectionMenuRunnerViews::CloseMenu() { + if (!menu_) + return; + + // Closing the menu will eventually delete the object. + menu_->Close(); + menu_ = nullptr; +} + +bool TouchSelectionMenuRunnerViews::IsRunning() const { + return menu_ != nullptr; +} + +} // namespace views diff --git a/ui/views/touchui/touch_selection_menu_runner_views.h b/ui/views/touchui/touch_selection_menu_runner_views.h new file mode 100644 index 0000000..46032ee --- /dev/null +++ b/ui/views/touchui/touch_selection_menu_runner_views.h @@ -0,0 +1,45 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_RUNNER_VIEWS_H_ +#define UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_RUNNER_VIEWS_H_ + +#include "base/memory/scoped_ptr.h" +#include "ui/touch_selection/touch_selection_menu_runner.h" +#include "ui/views/views_export.h" + +namespace views { + +// Views implementation for TouchSelectionMenuRunner. +class VIEWS_EXPORT TouchSelectionMenuRunnerViews + : public ui::TouchSelectionMenuRunner { + public: + TouchSelectionMenuRunnerViews(); + ~TouchSelectionMenuRunnerViews() override; + + private: + friend class TouchSelectionMenuRunnerViewsTest; + class Menu; + + // Helper for tests. + gfx::Rect GetAnchorRectForTest() const; + + // ui::TouchSelectionMenuRunner: + void OpenMenu(ui::TouchSelectionMenuClient* client, + const gfx::Rect& anchor_rect, + const gfx::Size& handle_image_size, + aura::Window* context) override; + void CloseMenu() override; + bool IsRunning() const override; + + // A pointer to the currently running menu, or |nullptr| if no menu is + // running. The menu manages its own lifetime and deletes itself when closed. + Menu* menu_; + + DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuRunnerViews); +}; + +} // namespace views + +#endif // UI_VIEWS_TOUCHUI_TOUCH_SELECTION_MENU_RUNNER_VIEWS_H_ diff --git a/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc b/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc new file mode 100644 index 0000000..ab1a88f --- /dev/null +++ b/ui/views/touchui/touch_selection_menu_runner_views_unittest.cc @@ -0,0 +1,110 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/strings/grit/ui_strings.h" +#include "ui/touch_selection/touch_selection_menu_runner.h" +#include "ui/views/test/views_test_base.h" +#include "ui/views/touchui/touch_selection_menu_runner_views.h" +#include "ui/views/views_delegate.h" + +namespace views { +namespace { + +// Should match |kMenuButtonWidth| in touch_selection_menu_runner_views.cc. +const int kMenuButtonWidth = 63; + +// Should match size of |kMenuCommands| array in +// touch_selection_menu_runner_views.cc. +const int kMenuCommandCount = 3; + +} + +class TouchSelectionMenuRunnerViewsTest : public ViewsTestBase, + public ui::TouchSelectionMenuClient { + public: + TouchSelectionMenuRunnerViewsTest() : no_command_available_(false) {} + ~TouchSelectionMenuRunnerViewsTest() override {} + + protected: + void set_no_commmand_available(bool no_command) { + no_command_available_ = no_command; + } + + gfx::Rect GetMenuAnchorRect() { + TouchSelectionMenuRunnerViews* menu_runner = + static_cast<TouchSelectionMenuRunnerViews*>( + ui::TouchSelectionMenuRunner::GetInstance()); + return menu_runner->GetAnchorRectForTest(); + } + + private: + // ui::TouchSelectionMenuClient: + bool IsCommandIdEnabled(int command_id) const override { + return !no_command_available_; + } + + void ExecuteCommand(int command_id, int event_flags) override {} + + void RunContextMenu() override {} + + // When set to true, no command would be availble and menu should not be + // shown. + bool no_command_available_; + + DISALLOW_COPY_AND_ASSIGN(TouchSelectionMenuRunnerViewsTest); +}; + +TEST_F(TouchSelectionMenuRunnerViewsTest, InstalledAndWorksProperly) { + gfx::Rect menu_anchor(0, 0, 10, 10); + gfx::Size handle_size(10, 10); + + // Menu runner instance should be installed, but no menu should be running. + EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()); + EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); + + // Run menu. Since commands are availble, this should bring up menus. + ui::TouchSelectionMenuRunner::GetInstance()->OpenMenu( + this, menu_anchor, handle_size, GetContext()); + EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); + + // Close menu. + ui::TouchSelectionMenuRunner::GetInstance()->CloseMenu(); + RunPendingMessages(); + EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); + + // Try running menu when no commands is available. Menu should not be shown. + set_no_commmand_available(true); + ui::TouchSelectionMenuRunner::GetInstance()->OpenMenu( + this, menu_anchor, handle_size, GetContext()); + EXPECT_FALSE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); +} + +// Tests if anchor rect for the quick menu is adjusted correctly based on the +// distance of handles. +TEST_F(TouchSelectionMenuRunnerViewsTest, QuickMenuAdjustsAnchorRect) { + gfx::Size handle_size(10, 10); + + // Calculate the width of quick menu. In addition to |kMenuCommandCount| + // commands, there is an item for ellipsis. + int quick_menu_width = + (kMenuCommandCount + 1) * kMenuButtonWidth + kMenuCommandCount; + + // Set anchor rect's width a bit smaller than the quick menu width plus handle + // image width and check that anchor rect's height is adjusted. + gfx::Rect anchor_rect(0, 0, quick_menu_width + handle_size.width() - 10, 20); + ui::TouchSelectionMenuRunner::GetInstance()->OpenMenu( + this, anchor_rect, handle_size, GetContext()); + anchor_rect.Inset(0, 0, 0, -handle_size.height()); + EXPECT_EQ(anchor_rect, GetMenuAnchorRect()); + + // Set anchor rect's width a bit greater than the quick menu width plus handle + // image width and check that anchor rect's height is not adjusted. + anchor_rect = + gfx::Rect(0, 0, quick_menu_width + handle_size.width() + 10, 20); + ui::TouchSelectionMenuRunner::GetInstance()->OpenMenu( + this, anchor_rect, handle_size, GetContext()); + EXPECT_EQ(anchor_rect, GetMenuAnchorRect()); +} + +} // namespace views diff --git a/ui/views/views.gyp b/ui/views/views.gyp index 100bad9..6da0fa7 100644 --- a/ui/views/views.gyp +++ b/ui/views/views.gyp @@ -388,10 +388,10 @@ 'event_monitor_aura.h', 'metrics_aura.cc', 'native_cursor_aura.cc', - 'touchui/touch_editing_menu.cc', - 'touchui/touch_editing_menu.h', 'touchui/touch_selection_controller_impl.cc', 'touchui/touch_selection_controller_impl.h', + 'touchui/touch_selection_menu_runner_views.cc', + 'touchui/touch_selection_menu_runner_views.h', 'view_constants_aura.cc', 'view_constants_aura.h', 'views_touch_selection_controller_factory_aura.cc', @@ -581,6 +581,7 @@ 'controls/native/native_view_host_aura_unittest.cc', 'corewm/tooltip_controller_unittest.cc', 'touchui/touch_selection_controller_impl_unittest.cc', + 'touchui/touch_selection_menu_runner_views_unittest.cc', 'view_unittest_aura.cc', 'widget/native_widget_aura_unittest.cc', ], @@ -706,6 +707,7 @@ ], 'dependencies': [ '../aura/aura.gyp:aura', + '../touch_selection/ui_touch_selection.gyp:ui_touch_selection', '../wm/wm.gyp:wm', ], }], @@ -864,6 +866,7 @@ 'dependencies': [ '../aura/aura.gyp:aura', '../aura/aura.gyp:aura_test_support', + '../touch_selection/ui_touch_selection.gyp:ui_touch_selection', '../wm/wm.gyp:wm', ], 'conditions': [ diff --git a/ui/views/views_delegate.cc b/ui/views/views_delegate.cc index 7c34470..507b038 100644 --- a/ui/views/views_delegate.cc +++ b/ui/views/views_delegate.cc @@ -7,11 +7,19 @@ #include "base/command_line.h" #include "ui/views/views_touch_selection_controller_factory.h" +#if defined(USE_AURA) +#include "ui/views/touchui/touch_selection_menu_runner_views.h" +#endif + namespace views { ViewsDelegate::ViewsDelegate() : views_tsc_factory_(new ViewsTouchEditingControllerFactory) { ui::TouchEditingControllerFactory::SetInstance(views_tsc_factory_.get()); + +#if defined(USE_AURA) + touch_selection_menu_runner_.reset(new TouchSelectionMenuRunnerViews()); +#endif } ViewsDelegate::~ViewsDelegate() { diff --git a/ui/views/views_delegate.h b/ui/views/views_delegate.h index 5013715..39c7f5a 100644 --- a/ui/views/views_delegate.h +++ b/ui/views/views_delegate.h @@ -47,6 +47,11 @@ class NonClientFrameView; class ViewsTouchEditingControllerFactory; class View; class Widget; + +#if defined(USE_AURA) +class TouchSelectionMenuRunnerViews; +#endif + namespace internal { class NativeWidgetDelegate; } @@ -161,6 +166,10 @@ class VIEWS_EXPORT ViewsDelegate { private: scoped_ptr<ViewsTouchEditingControllerFactory> views_tsc_factory_; +#if defined(USE_AURA) + scoped_ptr<TouchSelectionMenuRunnerViews> touch_selection_menu_runner_; +#endif + DISALLOW_COPY_AND_ASSIGN(ViewsDelegate); }; diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc index 5c27773..b8f138d 100644 --- a/ui/views/widget/widget_interactive_uitest.cc +++ b/ui/views/widget/widget_interactive_uitest.cc @@ -284,22 +284,16 @@ class WidgetTestInteractive : public WidgetTest { } protected: +#if defined(USE_AURA) static void ShowQuickMenuImmediately( TouchSelectionControllerImpl* controller) { DCHECK(controller); - if (controller->context_menu_timer_.IsRunning()) { - controller->context_menu_timer_.Stop(); -// TODO(tapted): Enable this when porting ui/views/touchui to Mac. -#if !defined(OS_MACOSX) - controller->ContextMenuTimerFired(); -#endif + if (controller->quick_menu_timer_.IsRunning()) { + controller->quick_menu_timer_.Stop(); + controller->QuickMenuTimerFired(); } } - - static bool IsQuickMenuVisible(TouchSelectionControllerImpl* controller) { - DCHECK(controller); - return controller->context_menu_ && controller->context_menu_->visible(); - } +#endif // defined (USE_AURA) Widget* CreateWidget() { Widget* widget = CreateNativeDesktopWidget(); @@ -894,17 +888,9 @@ TEST_F(WidgetTestInteractive, CanActivateFlagIsHonored) { EXPECT_FALSE(widget.IsActive()); } -// No touch on desktop Mac. Tracked in http://crbug.com/445520. -#if defined(OS_MACOSX) && !defined(USE_AURA) -#define MAYBE_TouchSelectionQuickMenuIsNotActivated \ - DISABLED_TouchSelectionQuickMenuIsNotActivated -#else -#define MAYBE_TouchSelectionQuickMenuIsNotActivated \ - TouchSelectionQuickMenuIsNotActivated -#endif - +#if defined(USE_AURA) // Test that touch selection quick menu is not activated when opened. -TEST_F(WidgetTestInteractive, MAYBE_TouchSelectionQuickMenuIsNotActivated) { +TEST_F(WidgetTestInteractive, TouchSelectionQuickMenuIsNotActivated) { base::CommandLine::ForCurrentProcess()->AppendSwitch( switches::kEnableTouchEditing); #if defined(OS_WIN) @@ -932,10 +918,10 @@ TEST_F(WidgetTestInteractive, MAYBE_TouchSelectionQuickMenuIsNotActivated) { EXPECT_TRUE(textfield->HasFocus()); EXPECT_TRUE(widget->IsActive()); - EXPECT_TRUE(IsQuickMenuVisible(static_cast<TouchSelectionControllerImpl*>( - textfield_test_api.touch_selection_controller()))); + EXPECT_TRUE(ui::TouchSelectionMenuRunner::GetInstance()->IsRunning()); widget->CloseNow(); } +#endif // defined(USE_AURA) TEST_F(WidgetTestInteractive, DisableViewDoesNotActivateWidget) { #if defined(OS_WIN) |