diff options
author | msw <msw@chromium.org> | 2016-03-23 16:48:50 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-23 23:50:35 +0000 |
commit | e9d901efb5bc6bbf434ac67b70f90e9ef73419d8 (patch) | |
tree | 97c9e4909019d18b900220c7c4cfcbb42836656e /ash | |
parent | fbaed4750ac46ce84d4b5d361b2601447db5390d (diff) | |
download | chromium_src-e9d901efb5bc6bbf434ac67b70f90e9ef73419d8.zip chromium_src-e9d901efb5bc6bbf434ac67b70f90e9ef73419d8.tar.gz chromium_src-e9d901efb5bc6bbf434ac67b70f90e9ef73419d8.tar.bz2 |
Enable mash shelf tooltips.
Make ShelfItemDelegateMus::ShouldShowTooltip() return true.
Put sysui menu/bubble widgets in mus's MENUS container.
(bubbles are used for shelf tooltips and volume/etc. settings)
Put sysui tooltip widgets in mus's TOOLTIPS container.
Rewrite ShelfTooltipManager as an aura::Window pre-target handler.
(can't install itself as a pre-target handler for the desktop root...)
Remove ShelfButtonHost; simplify ShelfButton and AppListButton.
(contain event observation logic within ShelfTooltipManager)
Update unit tests and helper classes; note currently broken behavior:
TODO: Make tooltips close on touch events outside the shelf.
TODO: Push item state to items; avoid shelf item delegates, etc.
BUG=595853
TEST=mash shelf shows tooltips; no cros regressions (except not closing on touch/gesture outside shelf).
R=sky@chromium.org
Review URL: https://codereview.chromium.org/1816753002
Cr-Commit-Position: refs/heads/master@{#382976}
Diffstat (limited to 'ash')
-rw-r--r-- | ash/ash.gyp | 1 | ||||
-rw-r--r-- | ash/mus/shelf_delegate_mus.cc | 5 | ||||
-rw-r--r-- | ash/mus/sysui_application.cc | 22 | ||||
-rw-r--r-- | ash/shelf/app_list_button.cc | 59 | ||||
-rw-r--r-- | ash/shelf/app_list_button.h | 22 | ||||
-rw-r--r-- | ash/shelf/shelf_button.cc | 152 | ||||
-rw-r--r-- | ash/shelf/shelf_button.h | 56 | ||||
-rw-r--r-- | ash/shelf/shelf_button_host.h | 65 | ||||
-rw-r--r-- | ash/shelf/shelf_tooltip_manager.cc | 332 | ||||
-rw-r--r-- | ash/shelf/shelf_tooltip_manager.h | 84 | ||||
-rw-r--r-- | ash/shelf/shelf_tooltip_manager_unittest.cc | 197 | ||||
-rw-r--r-- | ash/shelf/shelf_view.cc | 302 | ||||
-rw-r--r-- | ash/shelf/shelf_view.h | 48 | ||||
-rw-r--r-- | ash/shelf/shelf_view_unittest.cc | 167 | ||||
-rw-r--r-- | ash/test/shelf_test_api.cc | 7 | ||||
-rw-r--r-- | ash/test/shelf_view_test_api.cc | 4 | ||||
-rw-r--r-- | ash/test/shelf_view_test_api.h | 4 |
17 files changed, 500 insertions, 1027 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index 3a8f474..4b49388 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -232,7 +232,6 @@ 'shelf/shelf_bezel_event_filter.h', 'shelf/shelf_button.cc', 'shelf/shelf_button.h', - 'shelf/shelf_button_host.h', 'shelf/shelf_constants.cc', 'shelf/shelf_constants.h', 'shelf/shelf_delegate.h', diff --git a/ash/mus/shelf_delegate_mus.cc b/ash/mus/shelf_delegate_mus.cc index ce3698a..510bb1b 100644 --- a/ash/mus/shelf_delegate_mus.cc +++ b/ash/mus/shelf_delegate_mus.cc @@ -66,10 +66,7 @@ class ShelfItemDelegateMus : public ShelfItemDelegate { return false; } - bool ShouldShowTooltip() override { - // NOTIMPLEMENTED(); very noisy - return false; - } + bool ShouldShowTooltip() override { return true; } void Close() override { NOTIMPLEMENTED(); } diff --git a/ash/mus/sysui_application.cc b/ash/mus/sysui_application.cc index 16585a3..5fd5aac 100644 --- a/ash/mus/sysui_application.cc +++ b/ash/mus/sysui_application.cc @@ -45,11 +45,11 @@ namespace sysui { namespace { -// Tries to determine the corresponding container in mash from the ash container -// for the widget. -mash::wm::mojom::Container GetContainerId(aura::Window* container) { - DCHECK(container); - int id = container->id(); +// Tries to determine the corresponding mash container from widget init params. +mash::wm::mojom::Container GetContainerId( + const views::Widget::InitParams& params) { + DCHECK(params.parent); + const int id = params.parent->id(); if (id == kShellWindowId_DesktopBackgroundContainer) return mash::wm::mojom::Container::USER_BACKGROUND; // mash::wm::ShelfLayout manages both the shelf and the status area. @@ -57,6 +57,16 @@ mash::wm::mojom::Container GetContainerId(aura::Window* container) { id == kShellWindowId_StatusContainer) { return mash::wm::mojom::Container::USER_SHELF; } + + // Show mash shelf tooltips and settings bubbles in the menu container. + if (params.type == views::Widget::InitParams::Type::TYPE_MENU || + params.type == views::Widget::InitParams::Type::TYPE_BUBBLE) { + return mash::wm::mojom::Container::MENUS; + } + + if (params.type == views::Widget::InitParams::Type::TYPE_TOOLTIP) + return mash::wm::mojom::Container::TOOLTIPS; + return mash::wm::mojom::Container::COUNT; } @@ -118,7 +128,7 @@ class NativeWidgetFactory { views::internal::NativeWidgetDelegate* delegate) { std::map<std::string, std::vector<uint8_t>> properties; if (params.parent) { - mash::wm::mojom::Container container = GetContainerId(params.parent); + mash::wm::mojom::Container container = GetContainerId(params); if (container != mash::wm::mojom::Container::COUNT) { properties[mash::wm::mojom::kWindowContainer_Property] = mojo::TypeConverter<const std::vector<uint8_t>, int32_t>::Convert( diff --git a/ash/shelf/app_list_button.cc b/ash/shelf/app_list_button.cc index acb0dd3..d1ee54b 100644 --- a/ash/shelf/app_list_button.cc +++ b/ash/shelf/app_list_button.cc @@ -5,10 +5,9 @@ #include "ash/shelf/app_list_button.h" #include "ash/ash_constants.h" -#include "ash/shelf/shelf_button.h" -#include "ash/shelf/shelf_button_host.h" #include "ash/shelf/shelf_item_types.h" #include "ash/shelf/shelf_layout_manager.h" +#include "ash/shelf/shelf_view.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "base/command_line.h" @@ -19,27 +18,15 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" #include "ui/base/ui_base_switches_util.h" -#include "ui/compositor/layer.h" -#include "ui/compositor/layer_animation_element.h" -#include "ui/compositor/layer_animation_sequence.h" -#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/image/image_skia_operations.h" -#include "ui/views/controls/button/image_button.h" #include "ui/views/painter.h" namespace ash { -// static -const int AppListButton::kImageBoundsSize = 7; - -AppListButton::AppListButton(views::ButtonListener* listener, - ShelfButtonHost* host, - ShelfWidget* shelf_widget) - : views::ImageButton(listener), +AppListButton::AppListButton(ShelfView* shelf_view) + : views::ImageButton(shelf_view), draw_background_as_active_(false), - host_(host), - shelf_widget_(shelf_widget) { + shelf_view_(shelf_view) { SetAccessibleName( app_list::switches::IsExperimentalAppListEnabled() ? l10n_util::GetStringUTF16(IDS_ASH_SHELF_APP_LIST_LAUNCHER_TITLE) @@ -50,61 +37,45 @@ AppListButton::AppListButton(views::ButtonListener* listener, set_notify_action(CustomButton::NOTIFY_ON_PRESS); } -AppListButton::~AppListButton() { -} +AppListButton::~AppListButton() {} bool AppListButton::OnMousePressed(const ui::MouseEvent& event) { ImageButton::OnMousePressed(event); - host_->PointerPressedOnButton(this, ShelfButtonHost::MOUSE, event); + shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); return true; } void AppListButton::OnMouseReleased(const ui::MouseEvent& event) { ImageButton::OnMouseReleased(event); - host_->PointerReleasedOnButton(this, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); } void AppListButton::OnMouseCaptureLost() { - host_->PointerReleasedOnButton(this, ShelfButtonHost::MOUSE, true); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, true); ImageButton::OnMouseCaptureLost(); } bool AppListButton::OnMouseDragged(const ui::MouseEvent& event) { ImageButton::OnMouseDragged(event); - host_->PointerDraggedOnButton(this, ShelfButtonHost::MOUSE, event); + shelf_view_->PointerDraggedOnButton(this, ShelfView::MOUSE, event); return true; } -void AppListButton::OnMouseMoved(const ui::MouseEvent& event) { - ImageButton::OnMouseMoved(event); - host_->MouseMovedOverButton(this); -} - -void AppListButton::OnMouseEntered(const ui::MouseEvent& event) { - ImageButton::OnMouseEntered(event); - host_->MouseEnteredButton(this); -} - -void AppListButton::OnMouseExited(const ui::MouseEvent& event) { - ImageButton::OnMouseExited(event); - host_->MouseExitedButton(this); -} - void AppListButton::OnGestureEvent(ui::GestureEvent* event) { switch (event->type()) { case ui::ET_GESTURE_SCROLL_BEGIN: if (switches::IsTouchFeedbackEnabled()) SetDrawBackgroundAsActive(false); - host_->PointerPressedOnButton(this, ShelfButtonHost::TOUCH, *event); + shelf_view_->PointerPressedOnButton(this, ShelfView::TOUCH, *event); event->SetHandled(); return; case ui::ET_GESTURE_SCROLL_UPDATE: - host_->PointerDraggedOnButton(this, ShelfButtonHost::TOUCH, *event); + shelf_view_->PointerDraggedOnButton(this, ShelfView::TOUCH, *event); event->SetHandled(); return; case ui::ET_GESTURE_SCROLL_END: case ui::ET_SCROLL_FLING_START: - host_->PointerReleasedOnButton(this, ShelfButtonHost::TOUCH, false); + shelf_view_->PointerReleasedOnButton(this, ShelfView::TOUCH, false); event->SetHandled(); return; case ui::ET_GESTURE_TAP_DOWN: @@ -133,7 +104,7 @@ void AppListButton::OnPaint(gfx::Canvas* canvas) { draw_background_as_active_) { background_image_id = IDR_AURA_NOTIFICATION_BACKGROUND_PRESSED; } else { - if (shelf_widget_->GetDimsShelf()) + if (shelf_view_->shelf()->shelf_widget()->GetDimsShelf()) background_image_id = IDR_AURA_NOTIFICATION_BACKGROUND_ON_BLACK; else background_image_id = IDR_AURA_NOTIFICATION_BACKGROUND_NORMAL; @@ -152,7 +123,7 @@ void AppListButton::OnPaint(gfx::Canvas* canvas) { gfx::Rect contents_bounds = GetContentsBounds(); gfx::Rect background_bounds, forground_bounds; - ShelfAlignment alignment = shelf_widget_->GetAlignment(); + ShelfAlignment alignment = shelf_view_->shelf()->alignment(); background_bounds.set_size(background_image->size()); if (alignment == SHELF_ALIGNMENT_LEFT) { background_bounds.set_x(contents_bounds.width() - @@ -189,7 +160,7 @@ void AppListButton::OnPaint(gfx::Canvas* canvas) { void AppListButton::GetAccessibleState(ui::AXViewState* state) { state->role = ui::AX_ROLE_BUTTON; - state->name = host_->GetAccessibleName(this); + state->name = shelf_view_->GetTitleForView(this); } void AppListButton::SetDrawBackgroundAsActive( diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h index e0e5cd8..52fafe6 100644 --- a/ash/shelf/app_list_button.h +++ b/ash/shelf/app_list_button.h @@ -9,23 +9,15 @@ #include "ui/views/controls/button/image_button.h" namespace ash { -class ShelfButtonHost; -class ShelfWidget; +class ShelfView; // Button used for the AppList icon on the shelf. class AppListButton : public views::ImageButton { public: - // Bounds size (inset) required for the app icon image (in pixels). - static const int kImageBoundsSize; - - AppListButton(views::ButtonListener* listener, - ShelfButtonHost* host, - ShelfWidget* shelf_widget); + explicit AppListButton(ShelfView* shelf_view); ~AppListButton() override; - bool draw_background_as_active() { - return draw_background_as_active_; - } + bool draw_background_as_active() { return draw_background_as_active_; } protected: // views::ImageButton overrides: @@ -33,9 +25,6 @@ class AppListButton : public views::ImageButton { void OnMouseReleased(const ui::MouseEvent& event) override; void OnMouseCaptureLost() override; bool OnMouseDragged(const ui::MouseEvent& event) override; - void OnMouseMoved(const ui::MouseEvent& event) override; - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; void OnPaint(gfx::Canvas* canvas) override; void GetAccessibleState(ui::AXViewState* state) override; @@ -50,10 +39,7 @@ class AppListButton : public views::ImageButton { // the application list. bool draw_background_as_active_; - ShelfButtonHost* host_; - // Reference to the shelf widget containing this button, owned by the - // root window controller. - ShelfWidget* shelf_widget_; + ShelfView* shelf_view_; DISALLOW_COPY_AND_ASSIGN(AppListButton); }; diff --git a/ash/shelf/shelf_button.cc b/ash/shelf/shelf_button.cc index 5d44aa5..ff7b139 100644 --- a/ash/shelf/shelf_button.cc +++ b/ash/shelf/shelf_button.cc @@ -9,7 +9,7 @@ #include "ash/ash_constants.h" #include "ash/ash_switches.h" #include "ash/shelf/shelf.h" -#include "ash/shelf/shelf_button_host.h" +#include "ash/shelf/shelf_view.h" #include "base/time/time.h" #include "grit/ash_resources.h" #include "skia/ext/image_operations.h" @@ -115,8 +115,8 @@ namespace ash { class ShelfButton::BarView : public views::ImageView, public ShelfButtonAnimation::Observer { public: - BarView(ShelfButton* host) - : host_(host), + BarView(Shelf* shelf) + : shelf_(shelf), show_attention_(false), animation_end_time_(base::TimeTicks()), animating_(false) { @@ -180,7 +180,7 @@ class ShelfButton::BarView : public views::ImageView, double animation = animating_ ? ShelfButtonAnimation::GetInstance()->GetAnimation() : 1.0; double scale = .35 + .65 * animation; - if (host_->shelf()->alignment() == SHELF_ALIGNMENT_BOTTOM) { + if (shelf_->alignment() == SHELF_ALIGNMENT_BOTTOM) { int width = base_bounds_.width() * scale; bounds.set_width(std::min(width, kIconSize)); int x_offset = (base_bounds_.width() - bounds.width()) / 2; @@ -206,7 +206,7 @@ class ShelfButton::BarView : public views::ImageView, } } - ShelfButton* host_; + Shelf* shelf_; bool show_attention_; base::TimeTicks animation_end_time_; // For attention throbbing underline. bool animating_; // Is time-limited attention animation running? @@ -216,41 +216,18 @@ class ShelfButton::BarView : public views::ImageView, }; //////////////////////////////////////////////////////////////////////////////// -// ShelfButton::IconView - -ShelfButton::IconView::IconView() : icon_size_(kIconSize) { - // Do not make this interactive, so that events are sent to ShelfView for - // handling. - set_interactive(false); -} - -ShelfButton::IconView::~IconView() { -} - -//////////////////////////////////////////////////////////////////////////////// // ShelfButton // static const char ShelfButton::kViewClassName[] = "ash/ShelfButton"; -ShelfButton* ShelfButton::Create(views::ButtonListener* listener, - ShelfButtonHost* host, - Shelf* shelf) { - ShelfButton* button = new ShelfButton(listener, host, shelf); - button->Init(); - return button; -} - -ShelfButton::ShelfButton(views::ButtonListener* listener, - ShelfButtonHost* host, - Shelf* shelf) - : CustomButton(listener), - host_(host), - icon_view_(NULL), - bar_(new BarView(this)), +ShelfButton::ShelfButton(ShelfView* shelf_view) + : CustomButton(shelf_view), + shelf_view_(shelf_view), + icon_view_(new views::ImageView()), + bar_(new BarView(shelf_view->shelf())), state_(STATE_NORMAL), - shelf_(shelf), - destroyed_flag_(NULL) { + destroyed_flag_(nullptr) { SetAccessibilityFocusable(true); const gfx::ShadowValue kShadows[] = { @@ -260,7 +237,16 @@ ShelfButton::ShelfButton(views::ButtonListener* listener, }; icon_shadows_.assign(kShadows, kShadows + arraysize(kShadows)); + // TODO: refactor the layers so each button doesn't require 2. + icon_view_->SetPaintToLayer(true); + icon_view_->layer()->SetFillsBoundsOpaquely(false); + icon_view_->SetHorizontalAlignment(views::ImageView::CENTER); + icon_view_->SetVerticalAlignment(views::ImageView::LEADING); + // Do not make this interactive, so that events are sent to ShelfView. + icon_view_->set_interactive(false); + AddChildView(bar_); + AddChildView(icon_view_); } ShelfButton::~ShelfButton() { @@ -280,19 +266,13 @@ void ShelfButton::SetImage(const gfx::ImageSkia& image) { return; } - if (icon_view_->icon_size() == 0) { - SetShadowedImage(image); - return; - } - // Resize the image maintaining our aspect ratio. - int pref = icon_view_->icon_size(); float aspect_ratio = static_cast<float>(image.width()) / static_cast<float>(image.height()); - int height = pref; + int height = kIconSize; int width = static_cast<int>(aspect_ratio * height); - if (width > pref) { - width = pref; + if (width > kIconSize) { + width = kIconSize; height = static_cast<int>(width / aspect_ratio); } @@ -342,7 +322,7 @@ void ShelfButton::ShowContextMenu(const gfx::Point& p, CustomButton::ShowContextMenu(p, source_type); if (!destroyed) { - destroyed_flag_ = NULL; + destroyed_flag_ = nullptr; // The menu will not propagate mouse events while its shown. To address, // the hover state gets cleared once the menu was shown (and this was not // destroyed). @@ -356,71 +336,53 @@ const char* ShelfButton::GetClassName() const { bool ShelfButton::OnMousePressed(const ui::MouseEvent& event) { CustomButton::OnMousePressed(event); - host_->PointerPressedOnButton(this, ShelfButtonHost::MOUSE, event); + shelf_view_->PointerPressedOnButton(this, ShelfView::MOUSE, event); return true; } void ShelfButton::OnMouseReleased(const ui::MouseEvent& event) { CustomButton::OnMouseReleased(event); - host_->PointerReleasedOnButton(this, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, false); } void ShelfButton::OnMouseCaptureLost() { ClearState(STATE_HOVERED); - host_->PointerReleasedOnButton(this, ShelfButtonHost::MOUSE, true); + shelf_view_->PointerReleasedOnButton(this, ShelfView::MOUSE, true); CustomButton::OnMouseCaptureLost(); } bool ShelfButton::OnMouseDragged(const ui::MouseEvent& event) { CustomButton::OnMouseDragged(event); - host_->PointerDraggedOnButton(this, ShelfButtonHost::MOUSE, event); + shelf_view_->PointerDraggedOnButton(this, ShelfView::MOUSE, event); return true; } -void ShelfButton::OnMouseMoved(const ui::MouseEvent& event) { - CustomButton::OnMouseMoved(event); - host_->MouseMovedOverButton(this); -} - -void ShelfButton::OnMouseEntered(const ui::MouseEvent& event) { - AddState(STATE_HOVERED); - CustomButton::OnMouseEntered(event); - host_->MouseEnteredButton(this); -} - -void ShelfButton::OnMouseExited(const ui::MouseEvent& event) { - ClearState(STATE_HOVERED); - CustomButton::OnMouseExited(event); - host_->MouseExitedButton(this); -} - void ShelfButton::GetAccessibleState(ui::AXViewState* state) { state->role = ui::AX_ROLE_BUTTON; - state->name = host_->GetAccessibleName(this); + state->name = shelf_view_->GetTitleForView(this); } void ShelfButton::Layout() { const gfx::Rect button_bounds(GetContentsBounds()); - int icon_pad = shelf_->IsHorizontalAlignment() ? kIconPad : kIconPadVertical; - int x_offset = shelf_->PrimaryAxisValue(0, icon_pad); - int y_offset = shelf_->PrimaryAxisValue(icon_pad, 0); + Shelf* shelf = shelf_view_->shelf(); + int icon_pad = shelf->PrimaryAxisValue(kIconPad, kIconPadVertical); + int x_offset = shelf->PrimaryAxisValue(0, icon_pad); + int y_offset = shelf->PrimaryAxisValue(icon_pad, 0); - int icon_width = std::min(kIconSize, - button_bounds.width() - x_offset); - int icon_height = std::min(kIconSize, - button_bounds.height() - y_offset); + int icon_width = std::min(kIconSize, button_bounds.width() - x_offset); + int icon_height = std::min(kIconSize, button_bounds.height() - y_offset); // If on the left or top 'invert' the inset so the constant gap is on // the interior (towards the center of display) edge of the shelf. - if (SHELF_ALIGNMENT_LEFT == shelf_->alignment()) + if (SHELF_ALIGNMENT_LEFT == shelf->alignment()) x_offset = button_bounds.width() - (kIconSize + icon_pad); - if (SHELF_ALIGNMENT_TOP == shelf_->alignment()) + if (SHELF_ALIGNMENT_TOP == shelf->alignment()) y_offset = button_bounds.height() - (kIconSize + icon_pad); // Center icon with respect to the secondary axis, and ensure // that the icon doesn't occlude the bar highlight. - if (shelf_->IsHorizontalAlignment()) { + if (shelf->IsHorizontalAlignment()) { x_offset = std::max(0, button_bounds.width() - icon_width) / 2; if (y_offset + icon_height + kBarSize > button_bounds.height()) icon_height = button_bounds.height() - (y_offset + kBarSize); @@ -484,16 +446,16 @@ void ShelfButton::OnGestureEvent(ui::GestureEvent* event) { ClearState(STATE_HOVERED); return CustomButton::OnGestureEvent(event); case ui::ET_GESTURE_SCROLL_BEGIN: - host_->PointerPressedOnButton(this, ShelfButtonHost::TOUCH, *event); + shelf_view_->PointerPressedOnButton(this, ShelfView::TOUCH, *event); event->SetHandled(); return; case ui::ET_GESTURE_SCROLL_UPDATE: - host_->PointerDraggedOnButton(this, ShelfButtonHost::TOUCH, *event); + shelf_view_->PointerDraggedOnButton(this, ShelfView::TOUCH, *event); event->SetHandled(); return; case ui::ET_GESTURE_SCROLL_END: case ui::ET_SCROLL_FLING_START: - host_->PointerReleasedOnButton(this, ShelfButtonHost::TOUCH, false); + shelf_view_->PointerReleasedOnButton(this, ShelfView::TOUCH, false); event->SetHandled(); return; default: @@ -501,28 +463,12 @@ void ShelfButton::OnGestureEvent(ui::GestureEvent* event) { } } -void ShelfButton::Init() { - icon_view_ = CreateIconView(); - - // TODO: refactor the layers so each button doesn't require 2. - icon_view_->SetPaintToLayer(true); - icon_view_->layer()->SetFillsBoundsOpaquely(false); - icon_view_->SetHorizontalAlignment(views::ImageView::CENTER); - icon_view_->SetVerticalAlignment(views::ImageView::LEADING); - - AddChildView(icon_view_); -} - -ShelfButton::IconView* ShelfButton::CreateIconView() { - return new IconView; -} - void ShelfButton::UpdateState() { UpdateBar(); - - icon_view_->SetHorizontalAlignment(shelf_->PrimaryAxisValue( + Shelf* shelf = shelf_view_->shelf(); + icon_view_->SetHorizontalAlignment(shelf->PrimaryAxisValue( views::ImageView::CENTER, views::ImageView::LEADING)); - icon_view_->SetVerticalAlignment(shelf_->PrimaryAxisValue( + icon_view_->SetVerticalAlignment(shelf->PrimaryAxisValue( views::ImageView::LEADING, views::ImageView::CENTER)); SchedulePaint(); } @@ -544,20 +490,22 @@ void ShelfButton::UpdateBar() { if (bar_id != 0) { ResourceBundle& rb = ResourceBundle::GetSharedInstance(); const gfx::ImageSkia* image = rb.GetImageNamed(bar_id).ToImageSkia(); - if (shelf_->alignment() == SHELF_ALIGNMENT_BOTTOM) { + + Shelf* shelf = shelf_view_->shelf(); + if (shelf->alignment() == SHELF_ALIGNMENT_BOTTOM) { bar_->SetImage(*image); } else { bar_->SetImage(gfx::ImageSkiaOperations::CreateRotatedImage( - *image, shelf_->SelectValueForShelfAlignment( + *image, shelf->SelectValueForShelfAlignment( SkBitmapOperations::ROTATION_90_CW, SkBitmapOperations::ROTATION_90_CW, SkBitmapOperations::ROTATION_270_CW, SkBitmapOperations::ROTATION_180_CW))); } - bar_->SetHorizontalAlignment(shelf_->SelectValueForShelfAlignment( + bar_->SetHorizontalAlignment(shelf->SelectValueForShelfAlignment( views::ImageView::CENTER, views::ImageView::LEADING, views::ImageView::TRAILING, views::ImageView::CENTER)); - bar_->SetVerticalAlignment(shelf_->SelectValueForShelfAlignment( + bar_->SetVerticalAlignment(shelf->SelectValueForShelfAlignment( views::ImageView::TRAILING, views::ImageView::CENTER, views::ImageView::CENTER, views::ImageView::LEADING)); bar_->SchedulePaint(); diff --git a/ash/shelf/shelf_button.h b/ash/shelf/shelf_button.h index 4e63e9e..4a84a61 100644 --- a/ash/shelf/shelf_button.h +++ b/ash/shelf/shelf_button.h @@ -12,8 +12,7 @@ #include "ui/views/controls/image_view.h" namespace ash { -class Shelf; -class ShelfButtonHost; +class ShelfView; // Button used for items on the launcher, except for the AppList. class ASH_EXPORT ShelfButton : public views::CustomButton { @@ -38,13 +37,9 @@ class ASH_EXPORT ShelfButton : public views::CustomButton { STATE_HIDDEN = 1 << 5, }; + explicit ShelfButton(ShelfView* shelf_view); ~ShelfButton() override; - // Called to create an instance of a ShelfButton. - static ShelfButton* Create(views::ButtonListener* listener, - ShelfButtonHost* host, - Shelf* shelf); - // Sets the image to display for this entry. void SetImage(const gfx::ImageSkia& image); @@ -55,7 +50,6 @@ class ASH_EXPORT ShelfButton : public views::CustomButton { void AddState(State state); void ClearState(State state); int state() const { return state_; } - const Shelf* shelf() const { return shelf_; } // Returns the bounds of the icon. gfx::Rect GetIconBounds() const; @@ -68,37 +62,11 @@ class ASH_EXPORT ShelfButton : public views::CustomButton { void OnMouseCaptureLost() override; protected: - ShelfButton(views::ButtonListener* listener, - ShelfButtonHost* host, - Shelf* shelf); - - // Class that draws the icon part of a button, so it can be animated - // independently of the rest. This can be subclassed to provide a custom - // implementation, by overriding CreateIconView(). - class IconView : public views::ImageView { - public: - IconView(); - ~IconView() override; - - void set_icon_size(int icon_size) { icon_size_ = icon_size; } - int icon_size() const { return icon_size_; } - - private: - // Set to non-zero to force icons to be resized to fit within a square, - // while maintaining original proportions. - int icon_size_; - - DISALLOW_COPY_AND_ASSIGN(IconView); - }; - // View overrides: const char* GetClassName() const override; bool OnMousePressed(const ui::MouseEvent& event) override; void OnMouseReleased(const ui::MouseEvent& event) override; bool OnMouseDragged(const ui::MouseEvent& event) override; - void OnMouseMoved(const ui::MouseEvent& event) override; - void OnMouseEntered(const ui::MouseEvent& event) override; - void OnMouseExited(const ui::MouseEvent& event) override; void GetAccessibleState(ui::AXViewState* state) override; void Layout() override; void ChildPreferredSizeChanged(views::View* child) override; @@ -111,12 +79,6 @@ class ASH_EXPORT ShelfButton : public views::CustomButton { // Sets the icon image with a shadow. void SetShadowedImage(const gfx::ImageSkia& bitmap); - // Override for custom initialization. - virtual void Init(); - // Override to subclass IconView. - virtual IconView* CreateIconView(); - IconView* icon_view() const { return icon_view_; } - ShelfButtonHost* host() const { return host_; } private: class BarView; @@ -128,15 +90,17 @@ class ASH_EXPORT ShelfButton : public views::CustomButton { // Updates the status bar (bitmap, orientation, visibility). void UpdateBar(); - ShelfButtonHost* host_; - IconView* icon_view_; + // The shelf view hosting this button. + ShelfView* shelf_view_; + + // The icon part of a button can be animated independently of the rest. + views::ImageView* icon_view_; + // Draws a bar underneath the image to represent the state of the application. BarView* bar_; - // The current state of the application, multiple values of AppState are or'd - // together. - int state_; - Shelf* shelf_; + // The current application state, a bitfield of State enum values. + int state_; gfx::ShadowValues icon_shadows_; diff --git a/ash/shelf/shelf_button_host.h b/ash/shelf/shelf_button_host.h deleted file mode 100644 index b664c7f..0000000 --- a/ash/shelf/shelf_button_host.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 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 ASH_SHELF_SHELF_BUTTON_HOST_H_ -#define ASH_SHELF_SHELF_BUTTON_HOST_H_ - -#include "ash/ash_export.h" -#include "base/strings/string16.h" - -namespace ui { -class LocatedEvent; -} - -namespace views { -class View; -} - -namespace ash { - -// The shelf buttons communicate back to the host by way of this interface. -// This interface is used to enable reordering the items on the shelf. -class ASH_EXPORT ShelfButtonHost { - public: - enum Pointer { - NONE, - DRAG_AND_DROP, - MOUSE, - TOUCH, - }; - - // Invoked when a pointer device is pressed on a view. - virtual void PointerPressedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) = 0; - - // Invoked when a pointer device is dragged over a view. - virtual void PointerDraggedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) = 0; - - // Invoked either if a pointer device is released or mouse capture canceled. - virtual void PointerReleasedOnButton(views::View* view, - Pointer pointer, - bool canceled) = 0; - - // Invoked when the mouse moves on the item. - virtual void MouseMovedOverButton(views::View* view) = 0; - - // Invoked when the mouse enters the item. - virtual void MouseEnteredButton(views::View* view) = 0; - - // Invoked when the mouse exits the item. - virtual void MouseExitedButton(views::View* view) = 0; - - // Invoked to get the accessible name of the item. - virtual base::string16 GetAccessibleName(const views::View* view) = 0; - - protected: - virtual ~ShelfButtonHost() {} -}; - -} // namespace ash - -#endif // ASH_SHELF_SHELF_BUTTON_HOST_H_ diff --git a/ash/shelf/shelf_tooltip_manager.cc b/ash/shelf/shelf_tooltip_manager.cc index 3252ae1c..5e25fb2 100644 --- a/ash/shelf/shelf_tooltip_manager.cc +++ b/ash/shelf/shelf_tooltip_manager.cc @@ -13,14 +13,11 @@ #include "base/bind.h" #include "base/thread_task_runner_handle.h" #include "base/time/time.h" -#include "base/timer/timer.h" #include "ui/aura/window.h" -#include "ui/aura/window_event_dispatcher.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" #include "ui/gfx/geometry/insets.h" #include "ui/views/bubble/bubble_delegate.h" -#include "ui/views/bubble/bubble_frame_view.h" #include "ui/views/controls/label.h" #include "ui/views/layout/fill_layout.h" #include "ui/views/widget/widget.h" @@ -50,36 +47,24 @@ class ShelfTooltipManager::ShelfTooltipBubble : public views::BubbleDelegateView { public: ShelfTooltipBubble(views::View* anchor, - views::BubbleBorder::Arrow arrow, - ShelfTooltipManager* host); - - void SetText(const base::string16& text); - void Close(); + views::BubbleBorder::Arrow arrow, + const base::string16& text); private: - // views::WidgetDelegate overrides: - void WindowClosing() override; - // views::View overrides: gfx::Size GetPreferredSize() const override; - ShelfTooltipManager* host_; - views::Label* label_; - DISALLOW_COPY_AND_ASSIGN(ShelfTooltipBubble); }; ShelfTooltipManager::ShelfTooltipBubble::ShelfTooltipBubble( views::View* anchor, views::BubbleBorder::Arrow arrow, - ShelfTooltipManager* host) - : views::BubbleDelegateView(anchor, arrow), host_(host) { + const base::string16& text) + : views::BubbleDelegateView(anchor, arrow) { gfx::Insets insets = gfx::Insets(kArrowOffsetTopBottom, - kArrowOffsetLeftRight, - kArrowOffsetTopBottom, kArrowOffsetLeftRight); - // Shelf items can have an asymmetrical border for spacing reasons. - // Adjust anchor location for this. + // Adjust the anchor location for asymmetrical borders of shelf item. if (anchor->border()) insets += anchor->border()->GetInsets(); @@ -88,286 +73,151 @@ ShelfTooltipManager::ShelfTooltipBubble::ShelfTooltipBubble( set_close_on_deactivate(false); set_can_activate(false); set_accept_events(false); - set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin, - kTooltipTopBottomMargin, kTooltipLeftRightMargin)); + set_margins(gfx::Insets(kTooltipTopBottomMargin, kTooltipLeftRightMargin)); set_shadow(views::BubbleBorder::SMALL_SHADOW); SetLayoutManager(new views::FillLayout()); // The anchor may not have the widget in tests. - if (anchor->GetWidget() && anchor->GetWidget()->GetNativeView()) { - aura::Window* root_window = - anchor->GetWidget()->GetNativeView()->GetRootWindow(); - set_parent_window(ash::Shell::GetInstance()->GetContainer( - root_window, ash::kShellWindowId_SettingBubbleContainer)); + if (anchor->GetWidget() && anchor->GetWidget()->GetNativeWindow()) { + set_parent_window(ash::Shell::GetContainer( + anchor->GetWidget()->GetNativeWindow()->GetRootWindow(), + ash::kShellWindowId_SettingBubbleContainer)); } - label_ = new views::Label; - label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); - label_->SetEnabledColor(kTooltipTextColor); - AddChildView(label_); + views::Label* label = new views::Label(text); + label->SetHorizontalAlignment(gfx::ALIGN_LEFT); + label->SetEnabledColor(kTooltipTextColor); + AddChildView(label); views::BubbleDelegateView::CreateBubble(this); -} - -void ShelfTooltipManager::ShelfTooltipBubble::SetText( - const base::string16& text) { - label_->SetText(text); SizeToContents(); } -void ShelfTooltipManager::ShelfTooltipBubble::Close() { - if (GetWidget()) { - host_ = NULL; - GetWidget()->Close(); - } -} - -void ShelfTooltipManager::ShelfTooltipBubble::WindowClosing() { - views::BubbleDelegateView::WindowClosing(); - if (host_) - host_->OnBubbleClosed(this); -} - gfx::Size ShelfTooltipManager::ShelfTooltipBubble::GetPreferredSize() const { - gfx::Size pref_size = views::BubbleDelegateView::GetPreferredSize(); - if (pref_size.height() < kTooltipMinHeight) - pref_size.set_height(kTooltipMinHeight); - if (pref_size.width() > kTooltipMaxWidth) - pref_size.set_width(kTooltipMaxWidth); - return pref_size; + const gfx::Size size = views::BubbleDelegateView::GetPreferredSize(); + return gfx::Size(std::min(size.width(), kTooltipMaxWidth), + std::max(size.height(), kTooltipMinHeight)); } -ShelfTooltipManager::ShelfTooltipManager( - ShelfLayoutManager* shelf_layout_manager, - ShelfView* shelf_view) - : view_(NULL), - widget_(NULL), - anchor_(NULL), - shelf_layout_manager_(shelf_layout_manager), +ShelfTooltipManager::ShelfTooltipManager(ShelfView* shelf_view) + : timer_delay_(kTooltipAppearanceDelay), shelf_view_(shelf_view), - weak_factory_(this) { - if (shelf_layout_manager) - shelf_layout_manager->AddObserver(this); - if (Shell::HasInstance()) - Shell::GetInstance()->AddPreTargetHandler(this); -} + shelf_layout_manager_(nullptr), + bubble_(nullptr), + weak_factory_(this) {} ShelfTooltipManager::~ShelfTooltipManager() { - CancelHidingAnimation(); - Close(); - if (shelf_layout_manager_) - shelf_layout_manager_->RemoveObserver(this); - if (Shell::HasInstance()) - Shell::GetInstance()->RemovePreTargetHandler(this); + WillDeleteShelf(); } -void ShelfTooltipManager::ShowDelayed(views::View* anchor, - const base::string16& text) { - if (view_) { - if (timer_.get() && timer_->IsRunning()) { - return; - } else { - CancelHidingAnimation(); - Close(); - } - } - - if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible()) - return; - - CreateBubble(anchor, text); - ResetTimer(); -} - -void ShelfTooltipManager::ShowImmediately(views::View* anchor, - const base::string16& text) { - if (view_) { - if (timer_.get() && timer_->IsRunning()) - StopTimer(); - CancelHidingAnimation(); - Close(); - } - - if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible()) - return; - - CreateBubble(anchor, text); - ShowInternal(); +void ShelfTooltipManager::Init() { + shelf_layout_manager_ = shelf_view_->shelf()->shelf_layout_manager(); + shelf_layout_manager_->AddObserver(this); + // TODO(msw): Capture events outside the shelf to close tooltips? + shelf_view_->GetWidget()->GetNativeWindow()->AddPreTargetHandler(this); } void ShelfTooltipManager::Close() { - StopTimer(); - if (view_) { - view_->Close(); - view_ = NULL; - widget_ = NULL; - } + timer_.Stop(); + if (bubble_) + bubble_->GetWidget()->Close(); + bubble_ = nullptr; } -void ShelfTooltipManager::OnBubbleClosed(views::BubbleDelegateView* view) { - if (view == view_) { - view_ = NULL; - widget_ = NULL; - } +bool ShelfTooltipManager::IsVisible() const { + return bubble_ && bubble_->GetWidget()->IsVisible(); } -void ShelfTooltipManager::UpdateArrow() { - if (view_) { - CancelHidingAnimation(); - Close(); - ShowImmediately(anchor_, text_); - } +views::View* ShelfTooltipManager::GetCurrentAnchorView() const { + return bubble_ ? bubble_->GetAnchorView() : nullptr; } -void ShelfTooltipManager::ResetTimer() { - if (timer_.get() && timer_->IsRunning()) { - timer_->Reset(); - return; +void ShelfTooltipManager::ShowTooltip(views::View* view) { + timer_.Stop(); + if (bubble_) { + // Cancel the hiding animation to hide the old bubble immediately. + gfx::NativeView native_view = bubble_->GetWidget()->GetNativeView(); + wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_NONE); + Close(); } - // We don't start the timer if the shelf isn't visible. if (shelf_layout_manager_ && !shelf_layout_manager_->IsVisible()) return; - CreateTimer(kTooltipAppearanceDelay); -} - -void ShelfTooltipManager::StopTimer() { - timer_.reset(); -} - -bool ShelfTooltipManager::IsVisible() { - if (timer_.get() && timer_->IsRunning()) - return false; + Shelf* shelf = shelf_view_->shelf(); + views::BubbleBorder::Arrow arrow = shelf->SelectValueForShelfAlignment( + views::BubbleBorder::BOTTOM_CENTER, views::BubbleBorder::LEFT_CENTER, + views::BubbleBorder::RIGHT_CENTER, views::BubbleBorder::TOP_CENTER); - return widget_ && widget_->IsVisible(); + base::string16 text = shelf_view_->GetTitleForView(view); + bubble_ = new ShelfTooltipBubble(view, arrow, text); + gfx::NativeView native_view = bubble_->GetWidget()->GetNativeView(); + wm::SetWindowVisibilityAnimationType( + native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); + wm::SetWindowVisibilityAnimationTransition(native_view, wm::ANIMATE_HIDE); + bubble_->GetWidget()->Show(); } -void ShelfTooltipManager::CreateZeroDelayTimerForTest() { - CreateTimer(0); +void ShelfTooltipManager::ShowTooltipWithDelay(views::View* view) { + if (!shelf_layout_manager_ || shelf_layout_manager_->IsVisible()) { + timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timer_delay_), + base::Bind(&ShelfTooltipManager::ShowTooltip, + weak_factory_.GetWeakPtr(), view)); + } } -void ShelfTooltipManager::OnMouseEvent(ui::MouseEvent* event) { - DCHECK(event); - DCHECK(event->target()); - if (!widget_ || !widget_->IsVisible()) - return; - - DCHECK(view_); - DCHECK(shelf_view_); - - // Pressing the mouse button anywhere should close the tooltip. - if (event->type() == ui::ET_MOUSE_PRESSED) { - CloseSoon(); +void ShelfTooltipManager::OnEvent(ui::Event* event) { + // Close the tooltip on mouse press or exit, and on most non-mouse events. + if (event->type() == ui::ET_MOUSE_PRESSED || + event->type() == ui::ET_MOUSE_EXITED || !event->IsMouseEvent()) { + if (!event->IsKeyEvent()) + Close(); return; } - aura::Window* target = static_cast<aura::Window*>(event->target()); - if (widget_->GetNativeWindow()->GetRootWindow() != target->GetRootWindow()) { - CloseSoon(); + gfx::Point point = static_cast<ui::LocatedEvent*>(event)->location(); + views::View::ConvertPointFromWidget(shelf_view_, &point); + if (IsVisible() && shelf_view_->ShouldHideTooltip(point)) { + Close(); return; } - gfx::Point location_in_shelf_view = event->location(); - aura::Window::ConvertPointToTarget( - target, shelf_view_->GetWidget()->GetNativeWindow(), - &location_in_shelf_view); - - if (shelf_view_->ShouldHideTooltip(location_in_shelf_view)) { - // Because this mouse event may arrive to |view_|, here we just schedule - // the closing event rather than directly calling Close(). - CloseSoon(); - } -} - -void ShelfTooltipManager::OnTouchEvent(ui::TouchEvent* event) { - aura::Window* target = static_cast<aura::Window*>(event->target()); - if (widget_ && widget_->IsVisible() && widget_->GetNativeWindow() != target) - Close(); -} + views::View* view = shelf_view_->GetTooltipHandlerForPoint(point); + const bool should_show = shelf_view_->ShouldShowTooltipForView(view); + if (IsVisible() && bubble_->GetAnchorView() != view && should_show) + ShowTooltip(view); -void ShelfTooltipManager::OnGestureEvent(ui::GestureEvent* event) { - if (widget_ && widget_->IsVisible()) { - // Because this mouse event may arrive to |view_|, here we just schedule - // the closing event rather than directly calling Close(). - CloseSoon(); + if (!IsVisible() && event->type() == ui::ET_MOUSE_MOVED) { + timer_.Stop(); + if (should_show) + ShowTooltipWithDelay(view); } } -void ShelfTooltipManager::OnCancelMode(ui::CancelModeEvent* event) { - Close(); -} - void ShelfTooltipManager::WillDeleteShelf() { - shelf_layout_manager_ = NULL; + if (shelf_layout_manager_) + shelf_layout_manager_->RemoveObserver(this); + shelf_layout_manager_ = nullptr; + + views::Widget* widget = shelf_view_ ? shelf_view_->GetWidget() : nullptr; + if (widget && widget->GetNativeWindow()) + widget->GetNativeWindow()->RemovePreTargetHandler(this); + shelf_view_ = nullptr; } void ShelfTooltipManager::WillChangeVisibilityState( ShelfVisibilityState new_state) { - if (new_state == SHELF_HIDDEN) { - StopTimer(); + if (new_state == SHELF_HIDDEN) Close(); - } } void ShelfTooltipManager::OnAutoHideStateChanged(ShelfAutoHideState new_state) { if (new_state == SHELF_AUTO_HIDE_HIDDEN) { - StopTimer(); + timer_.Stop(); // AutoHide state change happens during an event filter, so immediate close // may cause a crash in the HandleMouseEvent() after the filter. So we just // schedule the Close here. - CloseSoon(); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&ShelfTooltipManager::Close, weak_factory_.GetWeakPtr())); } } -void ShelfTooltipManager::CancelHidingAnimation() { - if (!widget_ || !widget_->GetNativeView()) - return; - - gfx::NativeView native_view = widget_->GetNativeView(); - wm::SetWindowVisibilityAnimationTransition( - native_view, wm::ANIMATE_NONE); -} - -void ShelfTooltipManager::CloseSoon() { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&ShelfTooltipManager::Close, weak_factory_.GetWeakPtr())); -} - -void ShelfTooltipManager::ShowInternal() { - if (view_) - view_->GetWidget()->Show(); - - timer_.reset(); -} - -void ShelfTooltipManager::CreateBubble(views::View* anchor, - const base::string16& text) { - DCHECK(!view_); - - anchor_ = anchor; - text_ = text; - Shelf* shelf = shelf_layout_manager_->shelf_widget()->shelf(); - views::BubbleBorder::Arrow arrow = shelf->SelectValueForShelfAlignment( - views::BubbleBorder::BOTTOM_CENTER, views::BubbleBorder::LEFT_CENTER, - views::BubbleBorder::RIGHT_CENTER, views::BubbleBorder::TOP_CENTER); - - view_ = new ShelfTooltipBubble(anchor, arrow, this); - widget_ = view_->GetWidget(); - view_->SetText(text_); - - gfx::NativeView native_view = widget_->GetNativeView(); - wm::SetWindowVisibilityAnimationType( - native_view, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL); - wm::SetWindowVisibilityAnimationTransition( - native_view, wm::ANIMATE_HIDE); -} - -void ShelfTooltipManager::CreateTimer(int delay_in_ms) { - base::OneShotTimer* new_timer = new base::OneShotTimer(); - new_timer->Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(delay_in_ms), - this, - &ShelfTooltipManager::ShowInternal); - timer_.reset(new_timer); -} - } // namespace ash diff --git a/ash/shelf/shelf_tooltip_manager.h b/ash/shelf/shelf_tooltip_manager.h index 17eaee4..6768257 100644 --- a/ash/shelf/shelf_tooltip_manager.h +++ b/ash/shelf/shelf_tooltip_manager.h @@ -7,106 +7,72 @@ #include "ash/ash_export.h" #include "ash/shelf/shelf_layout_manager_observer.h" -#include "ash/shelf/shelf_types.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" +#include "base/timer/timer.h" #include "ui/events/event_handler.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/views/bubble/bubble_border.h" -#include "ui/views/bubble/bubble_delegate.h" - -namespace base { -class Timer; -} namespace views { class BubbleDelegateView; -class Label; +class View; } namespace ash { -class ShelfView; class ShelfLayoutManager; +class ShelfView; namespace test { class ShelfTooltipManagerTest; class ShelfViewTest; } -// ShelfTooltipManager manages the tooltip balloon poping up on shelf items. +// ShelfTooltipManager manages the tooltip bubble that appears for shelf items. class ASH_EXPORT ShelfTooltipManager : public ui::EventHandler, public ShelfLayoutManagerObserver { public: - ShelfTooltipManager(ShelfLayoutManager* shelf_layout_manager, - ShelfView* shelf_view); + explicit ShelfTooltipManager(ShelfView* shelf_view); ~ShelfTooltipManager() override; - ShelfLayoutManager* shelf_layout_manager() { return shelf_layout_manager_; } - - // Called when the bubble is closed. - void OnBubbleClosed(views::BubbleDelegateView* view); - - // Shows the tooltip after a delay. It also has the appearing animation. - void ShowDelayed(views::View* anchor, const base::string16& text); - - // Shows the tooltip immediately. It omits the appearing animation. - void ShowImmediately(views::View* anchor, const base::string16& text); + // Initializes the tooltip manager once the shelf is shown. + void Init(); // Closes the tooltip. void Close(); - // Changes the arrow location of the tooltip in case that the launcher - // arrangement has changed. - void UpdateArrow(); - - // Resets the timer for the delayed showing |view_|. If the timer isn't - // running, it starts a new timer. - void ResetTimer(); - - // Stops the timer for the delayed showing |view_|. - void StopTimer(); - // Returns true if the tooltip is currently visible. - bool IsVisible(); + bool IsVisible() const; + + // Returns the view to which the tooltip bubble is anchored. May be null. + views::View* GetCurrentAnchorView() const; - // Returns the view to which the tooltip bubble is anchored. May be NULL. - views::View* GetCurrentAnchorView() { return anchor_; } + // Show the tooltip bubble for the specified view. + void ShowTooltip(views::View* view); + void ShowTooltipWithDelay(views::View* view); - // Create an instant timer for test purposes. - void CreateZeroDelayTimerForTest(); + // Set the timer delay in ms for testing. + void set_timer_delay_for_test(int timer_delay) { timer_delay_ = timer_delay; } -protected: + protected: // ui::EventHandler overrides: - void OnMouseEvent(ui::MouseEvent* event) override; - void OnTouchEvent(ui::TouchEvent* event) override; - void OnGestureEvent(ui::GestureEvent* event) override; - void OnCancelMode(ui::CancelModeEvent* event) override; + void OnEvent(ui::Event* event) override; // ShelfLayoutManagerObserver overrides: - void WillDeleteShelf() override; - void WillChangeVisibilityState(ShelfVisibilityState new_state) override; - void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; + void WillDeleteShelf() override; + void WillChangeVisibilityState(ShelfVisibilityState new_state) override; + void OnAutoHideStateChanged(ShelfAutoHideState new_state) override; private: class ShelfTooltipBubble; friend class test::ShelfViewTest; friend class test::ShelfTooltipManagerTest; - void CancelHidingAnimation(); - void CloseSoon(); - void ShowInternal(); - void CreateBubble(views::View* anchor, const base::string16& text); - void CreateTimer(int delay_in_ms); + int timer_delay_; + base::OneShotTimer timer_; - ShelfTooltipBubble* view_; - views::Widget* widget_; - views::View* anchor_; - base::string16 text_; - scoped_ptr<base::Timer> timer_; - - ShelfLayoutManager* shelf_layout_manager_; ShelfView* shelf_view_; + ShelfLayoutManager* shelf_layout_manager_; + views::BubbleDelegateView* bubble_; base::WeakPtrFactory<ShelfTooltipManager> weak_factory_; diff --git a/ash/shelf/shelf_tooltip_manager_unittest.cc b/ash/shelf/shelf_tooltip_manager_unittest.cc index 6ebb063..3f2b2e8 100644 --- a/ash/shelf/shelf_tooltip_manager_unittest.cc +++ b/ash/shelf/shelf_tooltip_manager_unittest.cc @@ -4,35 +4,19 @@ #include "ash/shelf/shelf_tooltip_manager.h" -#include "ash/root_window_controller.h" #include "ash/shelf/shelf_layout_manager.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" #include "ash/test/shelf_test_api.h" -#include "ash/wm/window_util.h" -#include "base/strings/string16.h" -#include "base/time/time.h" -#include "ui/aura/window_event_dispatcher.h" -#include "ui/events/event.h" +#include "ash/test/shelf_view_test_api.h" #include "ui/events/event_constants.h" -#include "ui/events/event_handler.h" -#include "ui/events/event_utils.h" #include "ui/events/keycodes/keyboard_codes.h" -#include "ui/events/test/events_test_utils.h" +#include "ui/events/test/event_generator.h" +#include "ui/views/bubble/bubble_delegate.h" #include "ui/views/widget/widget.h" -namespace { - -void SetEventTarget(ui::EventTarget* target, - ui::Event* event) { - ui::Event::DispatcherApi dispatch_helper(event); - dispatch_helper.set_target(target); -} - -} - namespace ash { namespace test { @@ -43,52 +27,38 @@ class ShelfTooltipManagerTest : public AshTestBase { void SetUp() override { AshTestBase::SetUp(); - RootWindowController* controller = Shell::GetPrimaryRootWindowController(); - tooltip_manager_.reset(new ShelfTooltipManager( - controller->GetShelfLayoutManager(), - ShelfTestAPI(controller->shelf()->shelf()).shelf_view())); - } - - void TearDown() override { - tooltip_manager_.reset(); - AshTestBase::TearDown(); + shelf_ = Shelf::ForPrimaryDisplay(); + ShelfView* shelf_view = test::ShelfTestAPI(shelf_).shelf_view(); + tooltip_manager_ = test::ShelfViewTestAPI(shelf_view).tooltip_manager(); } void ShowDelayed() { CreateWidget(); - tooltip_manager_->ShowDelayed(dummy_anchor_.get(), base::string16()); + tooltip_manager_->ShowTooltipWithDelay(dummy_anchor_.get()); } void ShowImmediately() { CreateWidget(); - tooltip_manager_->ShowImmediately(dummy_anchor_.get(), base::string16()); - } - - bool TooltipIsVisible() { - return tooltip_manager_->IsVisible(); + tooltip_manager_->ShowTooltip(dummy_anchor_.get()); } - bool IsTimerRunning() { - return tooltip_manager_->timer_.get() != NULL; - } - - ui::EventHandler* GetEventHandler() { - return tooltip_manager_.get(); - } + bool TooltipIsVisible() { return tooltip_manager_->IsVisible(); } + bool IsTimerRunning() { return tooltip_manager_->timer_.IsRunning(); } - views::Widget* GetTooltipWidget() { - return tooltip_manager_->widget_; + aura::Window* GetTooltipWindow() { + return tooltip_manager_->bubble_->GetWidget()->GetNativeWindow(); } protected: scoped_ptr<views::Widget> widget_; scoped_ptr<views::View> dummy_anchor_; - scoped_ptr<ShelfTooltipManager> tooltip_manager_; + + Shelf* shelf_; + ShelfTooltipManager* tooltip_manager_; private: void CreateWidget() { dummy_anchor_.reset(new views::View); - widget_.reset(new views::Widget); views::Widget::InitParams params( views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); @@ -96,7 +66,6 @@ class ShelfTooltipManagerTest : public AshTestBase { params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.parent = Shell::GetContainer(Shell::GetPrimaryRootWindow(), ash::kShellWindowId_ShelfContainer); - widget_->Init(params); widget_->SetContentsView(dummy_anchor_.get()); } @@ -129,10 +98,7 @@ TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsHidden) { widget->Show(); // Once the shelf is hidden, the tooltip should be invisible. - ASSERT_EQ( - SHELF_HIDDEN, - Shell::GetPrimaryRootWindowController()-> - GetShelfLayoutManager()->visibility_state()); + ASSERT_EQ(SHELF_HIDDEN, shelf_->shelf_layout_manager()->visibility_state()); EXPECT_FALSE(TooltipIsVisible()); // Do not show the view if the shelf is hidden. @@ -156,11 +122,10 @@ TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsAutoHide) { ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); - ShelfLayoutManager* shelf = - Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); - shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); - shelf->UpdateAutoHideState(); - ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); + ShelfLayoutManager* shelf_layout_manager = shelf_->shelf_layout_manager(); + shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + shelf_layout_manager->UpdateAutoHideState(); + ASSERT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state()); // Tooltip visibility change for auto hide may take time. EXPECT_TRUE(TooltipIsVisible()); @@ -176,113 +141,67 @@ TEST_F(ShelfTooltipManagerTest, HideWhenShelfIsAutoHide) { EXPECT_FALSE(IsTimerRunning()); } -TEST_F(ShelfTooltipManagerTest, ShouldHideForEvents) { +TEST_F(ShelfTooltipManagerTest, HideForEvents) { + ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow()); + gfx::Rect shelf_bounds = shelf_->shelf_widget()->GetNativeWindow()->bounds(); + + // Should hide if the mouse exits the shelf area. ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); - - aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); - ui::EventHandler* event_handler = GetEventHandler(); - - // Should not hide for key events. - ui::KeyEvent key_event(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE); - SetEventTarget(root_window, &key_event); - event_handler->OnKeyEvent(&key_event); - EXPECT_FALSE(key_event.handled()); - EXPECT_TRUE(TooltipIsVisible()); - - // Should hide for touch events. - ui::TouchEvent touch_event( - ui::ET_TOUCH_PRESSED, gfx::Point(), 0, base::TimeDelta()); - SetEventTarget(root_window, &touch_event); - event_handler->OnTouchEvent(&touch_event); - EXPECT_FALSE(touch_event.handled()); + generator.MoveMouseTo(shelf_bounds.CenterPoint()); + generator.SendMouseExit(); EXPECT_FALSE(TooltipIsVisible()); - // Shouldn't hide if the touch happens on the tooltip. + // Should hide if the mouse is pressed in the shelf area. ShowImmediately(); - views::Widget* tooltip_widget = GetTooltipWidget(); - SetEventTarget(tooltip_widget->GetNativeWindow(), &touch_event); - event_handler->OnTouchEvent(&touch_event); - EXPECT_FALSE(touch_event.handled()); - EXPECT_TRUE(TooltipIsVisible()); - - // Should hide for gesture events. - ui::GestureEvent gesture_event( - 0, - 0, - ui::EF_NONE, - base::TimeDelta::FromMilliseconds(base::Time::Now().ToDoubleT() * 1000), - ui::GestureEventDetails(ui::ET_GESTURE_BEGIN)); - SetEventTarget(tooltip_widget->GetNativeWindow(), &gesture_event); - event_handler->OnGestureEvent(&gesture_event); - EXPECT_FALSE(gesture_event.handled()); - RunAllPendingInMessageLoop(); + ASSERT_TRUE(TooltipIsVisible()); + generator.MoveMouseTo(shelf_bounds.CenterPoint()); + generator.PressLeftButton(); EXPECT_FALSE(TooltipIsVisible()); -} -TEST_F(ShelfTooltipManagerTest, HideForMouseMoveEvent) { + // Should hide for touch events in the shelf. ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); + generator.set_current_location(shelf_bounds.CenterPoint()); + generator.PressTouch(); + EXPECT_FALSE(TooltipIsVisible()); - aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); - ui::EventHandler* event_handler = GetEventHandler(); - - gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); - ASSERT_FALSE(tooltip_rect.IsEmpty()); - - // Shouldn't hide if the mouse is in the tooltip. - ui::MouseEvent mouse_event(ui::ET_MOUSE_MOVED, tooltip_rect.CenterPoint(), - tooltip_rect.CenterPoint(), ui::EventTimeForNow(), - ui::EF_NONE, ui::EF_NONE); - ui::LocatedEventTestApi test_api(&mouse_event); - - SetEventTarget(root_window, &mouse_event); - event_handler->OnMouseEvent(&mouse_event); - EXPECT_FALSE(mouse_event.handled()); - EXPECT_TRUE(TooltipIsVisible()); - - // Should hide if the mouse is out of the tooltip. - test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1)); - event_handler->OnMouseEvent(&mouse_event); - EXPECT_FALSE(mouse_event.handled()); - RunAllPendingInMessageLoop(); + // Should hide for gesture events in the shelf. + ShowImmediately(); + ASSERT_TRUE(TooltipIsVisible()); + generator.GestureTapDownAndUp(shelf_bounds.CenterPoint()); EXPECT_FALSE(TooltipIsVisible()); } -// Checks that tooltip is hidden when mouse is pressed in anywhere. -TEST_F(ShelfTooltipManagerTest, HideForMouseClickEvent) { +// TODO(msw): Hiding for touch and gesture events outside the shelf is broken. +TEST_F(ShelfTooltipManagerTest, HideForEventsBroken) { + ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow()); + ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); - aura::Window* root_window = Shell::GetInstance()->GetPrimaryRootWindow(); - ui::EventHandler* event_handler = GetEventHandler(); - - gfx::Rect tooltip_rect = GetTooltipWidget()->GetNativeWindow()->bounds(); - ASSERT_FALSE(tooltip_rect.IsEmpty()); + generator.set_current_location(gfx::Point()); + generator.PressTouch(); + EXPECT_TRUE(TooltipIsVisible()); - // Should hide if the mouse is pressed in the tooltip. - ui::MouseEvent mouse_event(ui::ET_MOUSE_PRESSED, tooltip_rect.CenterPoint(), - tooltip_rect.CenterPoint(), ui::EventTimeForNow(), - ui::EF_NONE, ui::EF_NONE); + generator.GestureTapDownAndUp(gfx::Point()); + EXPECT_TRUE(TooltipIsVisible()); +} - SetEventTarget(root_window, &mouse_event); - event_handler->OnMouseEvent(&mouse_event); - EXPECT_FALSE(mouse_event.handled()); - RunAllPendingInMessageLoop(); - EXPECT_FALSE(TooltipIsVisible()); +TEST_F(ShelfTooltipManagerTest, DoNotHideForEvents) { + ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow()); - // Should hide if the mouse is pressed outside of the tooltip. ShowImmediately(); ASSERT_TRUE(TooltipIsVisible()); - ui::LocatedEventTestApi test_api(&mouse_event); - test_api.set_location(tooltip_rect.origin() + gfx::Vector2d(-1, -1)); + // Should not hide for key events. + generator.PressKey(ui::VKEY_A, ui::EF_NONE); + EXPECT_TRUE(TooltipIsVisible()); - SetEventTarget(root_window, &mouse_event); - event_handler->OnMouseEvent(&mouse_event); - EXPECT_FALSE(mouse_event.handled()); - RunAllPendingInMessageLoop(); - EXPECT_FALSE(TooltipIsVisible()); + // Should not hide for touch events on the tooltip. + generator.set_current_location(GetTooltipWindow()->bounds().CenterPoint()); + generator.PressTouch(); + EXPECT_TRUE(TooltipIsVisible()); } } // namespace test diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index b3ddf68..3a19798 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc @@ -23,7 +23,6 @@ #include "ash/shelf/shelf_item_delegate_manager.h" #include "ash/shelf/shelf_menu_model.h" #include "ash/shelf/shelf_model.h" -#include "ash/shelf/shelf_tooltip_manager.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/shell_delegate.h" @@ -224,8 +223,7 @@ bool ShelfMenuModelAdapter::ShouldReserveSpaceForSubmenuIndicator() const { class ShelfFocusSearch : public views::FocusSearch { public: explicit ShelfFocusSearch(views::ViewModel* view_model) - : FocusSearch(NULL, true, true), - view_model_(view_model) {} + : FocusSearch(nullptr, true, true), view_model_(view_model) {} ~ShelfFocusSearch() override {} // views::FocusSearch overrides: @@ -370,25 +368,26 @@ ShelfView::ShelfView(ShelfModel* model, ShelfDelegate* delegate, Shelf* shelf) view_model_(new views::ViewModel), first_visible_index_(0), last_visible_index_(-1), - overflow_button_(NULL), - owner_overflow_bubble_(NULL), + overflow_button_(nullptr), + owner_overflow_bubble_(nullptr), + tooltip_(this), drag_pointer_(NONE), - drag_view_(NULL), + drag_view_(nullptr), start_drag_index_(-1), context_menu_id_(0), leading_inset_(kDefaultLeadingInset), cancelling_drag_model_changed_(false), last_hidden_index_(0), closing_event_time_(base::TimeDelta()), - got_deleted_(NULL), + got_deleted_(nullptr), drag_and_drop_item_pinned_(false), drag_and_drop_shelf_id_(0), drag_replaced_view_(nullptr), dragged_off_shelf_(false), - snap_back_from_rip_off_view_(NULL), + snap_back_from_rip_off_view_(nullptr), item_manager_(Shell::GetInstance()->shelf_item_delegate_manager()), overflow_mode_(false), - main_shelf_(NULL), + main_shelf_(nullptr), dragged_off_from_overflow_to_shelf_(false), is_repost_event_(false), last_pressed_index_(-1) { @@ -397,7 +396,6 @@ ShelfView::ShelfView(ShelfModel* model, ShelfDelegate* delegate, Shelf* shelf) bounds_animator_->AddObserver(this); set_context_menu_controller(this); focus_search_.reset(new ShelfFocusSearch(view_model_.get())); - tooltip_.reset(new ShelfTooltipManager(shelf->shelf_layout_manager(), this)); } ShelfView::~ShelfView() { @@ -434,7 +432,7 @@ void ShelfView::OnShelfAlignmentChanged() { if (i >= first_visible_index_ && i <= last_visible_index_) view_model_->view_at(i)->Layout(); } - tooltip_->Close(); + tooltip_.Close(); if (overflow_bubble_) overflow_bubble_->Hide(); } @@ -517,7 +515,42 @@ views::View* ShelfView::GetAppListButtonView() const { } NOTREACHED() << "Applist button not found"; - return NULL; + return nullptr; +} + +bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) const { + gfx::Rect tooltip_bounds; + for (int i = 0; i < child_count(); ++i) { + const views::View* child = child_at(i); + if (child != overflow_button_ && ShouldShowTooltipForView(child)) + tooltip_bounds.Union(child->GetMirroredBounds()); + } + return !tooltip_bounds.Contains(cursor_location); +} + +bool ShelfView::ShouldShowTooltipForView(const views::View* view) const { + if (view == GetAppListButtonView() && + Shell::GetInstance()->GetAppListWindow()) { + return false; + } + const ShelfItem* item = ShelfItemForView(view); + if (!item) + return false; + return item_manager_->GetShelfItemDelegate(item->id)->ShouldShowTooltip(); +} + +base::string16 ShelfView::GetTitleForView(const views::View* view) const { + const ShelfItem* item = ShelfItemForView(view); + if (!item) + return base::string16(); + return item_manager_->GetShelfItemDelegate(item->id)->GetTitle(); +} + +gfx::Rect ShelfView::GetVisibleItemsBoundsInScreen() { + gfx::Size preferred_size = GetPreferredSize(); + gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0); + ConvertPointToScreen(this, &origin); + return gfx::Rect(origin, preferred_size); } //////////////////////////////////////////////////////////////////////////////// @@ -560,7 +593,7 @@ void ShelfView::CreateDragIconProxy( void ShelfView::UpdateDragIconProxy( const gfx::Point& location_in_screen_coordinates) { - // TODO(jennyz): Investigate why drag_image_ becomes NULL at this point per + // TODO(jennyz): Investigate why drag_image_ becomes null at this point per // crbug.com/34722, while the app list item is still being dragged around. if (drag_image_) { drag_image_->SetScreenPosition( @@ -621,9 +654,7 @@ bool ShelfView::StartDrag(const std::string& app_id, ash::wm::GetRootWindowAt(location_in_screen_coordinates), &point_in_root); ui::MouseEvent event(ui::ET_MOUSE_PRESSED, pt, point_in_root, ui::EventTimeForNow(), 0, 0); - PointerPressedOnButton(drag_and_drop_view, - ShelfButtonHost::DRAG_AND_DROP, - event); + PointerPressedOnButton(drag_and_drop_view, DRAG_AND_DROP, event); // Drag the item where it really belongs. Drag(location_in_screen_coordinates); @@ -644,9 +675,7 @@ bool ShelfView::Drag(const gfx::Point& location_in_screen_coordinates) { ash::wm::GetRootWindowAt(location_in_screen_coordinates), &point_in_root); ui::MouseEvent event(ui::ET_MOUSE_DRAGGED, pt, point_in_root, ui::EventTimeForNow(), 0, 0); - PointerDraggedOnButton(drag_and_drop_view, - ShelfButtonHost::DRAG_AND_DROP, - event); + PointerDraggedOnButton(drag_and_drop_view, DRAG_AND_DROP, event); return true; } @@ -656,8 +685,7 @@ void ShelfView::EndDrag(bool cancel) { views::View* drag_and_drop_view = view_model_->view_at( model_->ItemIndexByID(drag_and_drop_shelf_id_)); - PointerReleasedOnButton( - drag_and_drop_view, ShelfButtonHost::DRAG_AND_DROP, cancel); + PointerReleasedOnButton(drag_and_drop_view, DRAG_AND_DROP, cancel); // Either destroy the temporarily created item - or - make the item visible. if (drag_and_drop_item_pinned_ && cancel) { @@ -676,6 +704,69 @@ void ShelfView::EndDrag(bool cancel) { drag_and_drop_shelf_id_ = 0; } +void ShelfView::PointerPressedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event) { + if (drag_view_) + return; + + int index = view_model_->GetIndexOfView(view); + if (index == -1) + return; + + ShelfItemDelegate* item_delegate = + item_manager_->GetShelfItemDelegate(model_->items()[index].id); + if (view_model_->view_size() <= 1 || !item_delegate->IsDraggable()) + return; // View is being deleted or not draggable, ignore request. + + // Only when the repost event occurs on the same shelf item, we should ignore + // the call in ShelfView::ButtonPressed(...). + is_repost_event_ = IsRepostEvent(event) && (last_pressed_index_ == index); + + CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); + drag_view_ = static_cast<ShelfButton*>(view); + drag_origin_ = gfx::Point(event.x(), event.y()); + UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentUsage", + shelf_->SelectValueForShelfAlignment( + SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM, + SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT, + SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT, -1), + SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT); +} + +void ShelfView::PointerDraggedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event) { + // To prepare all drag types (moving an item in the shelf and dragging off), + // we should check the x-axis and y-axis offset. + if (!dragging() && drag_view_ && + ((std::abs(event.x() - drag_origin_.x()) >= kMinimumDragDistance) || + (std::abs(event.y() - drag_origin_.y()) >= kMinimumDragDistance))) { + PrepareForDrag(pointer, event); + } + if (drag_pointer_ == pointer) + ContinueDrag(event); +} + +void ShelfView::PointerReleasedOnButton(views::View* view, + Pointer pointer, + bool canceled) { + // Reset |is_repost_event| to false. + is_repost_event_ = false; + + if (canceled) { + CancelDrag(-1); + } else if (drag_pointer_ == pointer) { + FinalizeRipOffDrag(false); + drag_pointer_ = NONE; + AnimateToIdealBounds(); + } + // If the drag pointer is NONE, no drag operation is going on and the + // drag_view can be released. + if (drag_pointer_ == NONE) + drag_view_ = nullptr; +} + void ShelfView::LayoutToIdealBounds() { if (bounds_animator_->IsAnimating()) { AnimateToIdealBounds(); @@ -883,7 +974,7 @@ void ShelfView::AnimateToIdealBounds() { } views::View* ShelfView::CreateViewForItem(const ShelfItem& item) { - views::View* view = NULL; + views::View* view = nullptr; switch (item.type) { case TYPE_BROWSER_SHORTCUT: case TYPE_APP_SHORTCUT: @@ -891,7 +982,7 @@ views::View* ShelfView::CreateViewForItem(const ShelfItem& item) { case TYPE_PLATFORM_APP: case TYPE_DIALOG: case TYPE_APP_PANEL: { - ShelfButton* button = ShelfButton::Create(this, this, shelf_); + ShelfButton* button = new ShelfButton(this); button->SetImage(item.image); ReflectItemStatus(item, button); view = button; @@ -899,16 +990,15 @@ views::View* ShelfView::CreateViewForItem(const ShelfItem& item) { } case TYPE_APP_LIST: { - view = new AppListButton(this, this, shelf_->shelf_widget()); + view = new AppListButton(this); break; } - default: - break; + case TYPE_UNDEFINED: + return nullptr; } - view->set_context_menu_controller(this); - DCHECK(view); + view->set_context_menu_controller(this); ConfigureChildView(view); return view; } @@ -1295,30 +1385,6 @@ void ShelfView::UpdateOverflowRange(ShelfView* overflow_view) const { overflow_view->last_visible_index_ = last_overflow_index; } -bool ShelfView::ShouldHideTooltip(const gfx::Point& cursor_location) { - gfx::Rect active_bounds; - - for (int i = 0; i < child_count(); ++i) { - views::View* child = child_at(i); - if (child == overflow_button_) - continue; - if (!ShouldShowTooltipForView(child)) - continue; - - gfx::Rect child_bounds = child->GetMirroredBounds(); - active_bounds.Union(child_bounds); - } - - return !active_bounds.Contains(cursor_location); -} - -gfx::Rect ShelfView::GetVisibleItemsBoundsInScreen() { - gfx::Size preferred_size = GetPreferredSize(); - gfx::Point origin(GetMirroredXWithWidthInView(0, preferred_size.width()), 0); - ConvertPointToScreen(this, &origin); - return gfx::Rect(origin, preferred_size); -} - gfx::Rect ShelfView::GetBoundsForDragInsertInScreen() { gfx::Size preferred_size; if (is_overflow_mode()) { @@ -1366,7 +1432,7 @@ int ShelfView::CancelDrag(int modified_index) { bool was_dragging = dragging(); int drag_view_index = view_model_->GetIndexOfView(drag_view_); drag_pointer_ = NONE; - drag_view_ = NULL; + drag_view_ = nullptr; if (drag_view_index == modified_index) { // The view that was being dragged is being modified. Don't do anything. return modified_index; @@ -1376,9 +1442,9 @@ int ShelfView::CancelDrag(int modified_index) { // Restore previous position, tracking the position of the modified view. bool at_end = modified_index == view_model_->view_size(); - views::View* modified_view = - (modified_index >= 0 && !at_end) ? - view_model_->view_at(modified_index) : NULL; + views::View* modified_view = (modified_index >= 0 && !at_end) + ? view_model_->view_at(modified_index) + : nullptr; model_->Move(drag_view_index, start_drag_index_); // If the modified view will be at the end of the list, return the new end of @@ -1441,6 +1507,12 @@ void ShelfView::GetAccessibleState(ui::AXViewState* state) { state->name = l10n_util::GetStringUTF16(IDS_ASH_SHELF_ACCESSIBLE_NAME); } +void ShelfView::ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) { + if (details.is_add && details.child == this && GetWidget()) + tooltip_.Init(); +} + void ShelfView::OnGestureEvent(ui::GestureEvent* event) { aura::Window* target_window = static_cast<views::View*>(event->target()) ->GetWidget() @@ -1523,10 +1595,8 @@ void ShelfView::ShelfItemRemoved(int model_index, ShelfID id) { AnimateToIdealBounds(); } - // Close the tooltip because it isn't needed any longer and its anchor view - // will be deleted soon. - if (tooltip_->GetCurrentAnchorView() == view) - tooltip_->Close(); + if (view == tooltip_.GetCurrentAnchorView()) + tooltip_.Close(); } void ShelfView::ShelfItemChanged(int model_index, const ShelfItem& old_item) { @@ -1585,104 +1655,6 @@ void ShelfView::ShelfItemMoved(int start_index, int target_index) { AnimateToIdealBounds(); } -void ShelfView::PointerPressedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) { - if (drag_view_) - return; - - int index = view_model_->GetIndexOfView(view); - if (index == -1) - return; - - ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate( - model_->items()[index].id); - if (view_model_->view_size() <= 1 || !item_delegate->IsDraggable()) - return; // View is being deleted or not draggable, ignore request. - - // Only when the repost event occurs on the same shelf item, we should ignore - // the call in ShelfView::ButtonPressed(...). - is_repost_event_ = IsRepostEvent(event) && (last_pressed_index_ == index); - - CHECK_EQ(ShelfButton::kViewClassName, view->GetClassName()); - drag_view_ = static_cast<ShelfButton*>(view); - drag_origin_ = gfx::Point(event.x(), event.y()); - UMA_HISTOGRAM_ENUMERATION("Ash.ShelfAlignmentUsage", - shelf_->SelectValueForShelfAlignment( - SHELF_ALIGNMENT_UMA_ENUM_VALUE_BOTTOM, - SHELF_ALIGNMENT_UMA_ENUM_VALUE_LEFT, - SHELF_ALIGNMENT_UMA_ENUM_VALUE_RIGHT, -1), - SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT); -} - -void ShelfView::PointerDraggedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) { - // To prepare all drag types (moving an item in the shelf and dragging off), - // we should check the x-axis and y-axis offset. - if (!dragging() && drag_view_ && - ((std::abs(event.x() - drag_origin_.x()) >= kMinimumDragDistance) || - (std::abs(event.y() - drag_origin_.y()) >= kMinimumDragDistance))) { - PrepareForDrag(pointer, event); - } - if (drag_pointer_ == pointer) - ContinueDrag(event); -} - -void ShelfView::PointerReleasedOnButton(views::View* view, - Pointer pointer, - bool canceled) { - // Reset |is_repost_event| to false. - is_repost_event_ = false; - - if (canceled) { - CancelDrag(-1); - } else if (drag_pointer_ == pointer) { - FinalizeRipOffDrag(false); - drag_pointer_ = NONE; - AnimateToIdealBounds(); - } - // If the drag pointer is NONE, no drag operation is going on and the - // drag_view can be released. - if (drag_pointer_ == NONE) - drag_view_ = NULL; -} - -void ShelfView::MouseMovedOverButton(views::View* view) { - if (!ShouldShowTooltipForView(view)) - return; - - if (!tooltip_->IsVisible()) - tooltip_->ResetTimer(); -} - -void ShelfView::MouseEnteredButton(views::View* view) { - if (!ShouldShowTooltipForView(view)) - return; - - if (tooltip_->IsVisible()) { - tooltip_->ShowImmediately(view, GetAccessibleName(view)); - } else { - tooltip_->ShowDelayed(view, GetAccessibleName(view)); - } -} - -void ShelfView::MouseExitedButton(views::View* view) { - if (!tooltip_->IsVisible()) - tooltip_->StopTimer(); -} - -base::string16 ShelfView::GetAccessibleName(const views::View* view) { - int view_index = view_model_->GetIndexOfView(view); - // May be -1 while in the process of animating closed. - if (view_index == -1) - return base::string16(); - - ShelfItemDelegate* item_delegate = item_manager_->GetShelfItemDelegate( - model_->items()[view_index].id); - return item_delegate->GetTitle(); -} - void ShelfView::ButtonPressed(views::Button* sender, const ui::Event& event) { // Do not handle mouse release during drag. if (dragging()) @@ -1882,7 +1854,7 @@ void ShelfView::OnBoundsAnimatorDone(views::BoundsAnimator* animator) { break; } } - snap_back_from_rip_off_view_ = NULL; + snap_back_from_rip_off_view_ = nullptr; } } } @@ -1904,18 +1876,6 @@ const ShelfItem* ShelfView::ShelfItemForView(const views::View* view) const { return (view_index < 0) ? nullptr : &(model_->items()[view_index]); } -bool ShelfView::ShouldShowTooltipForView(const views::View* view) const { - if (view == GetAppListButtonView() && - Shell::GetInstance()->GetAppListTargetVisibility()) - return false; - const ShelfItem* item = ShelfItemForView(view); - if (!item) - return true; - ShelfItemDelegate* item_delegate = - item_manager_->GetShelfItemDelegate(item->id); - return item_delegate->ShouldShowTooltip(); -} - int ShelfView::CalculateShelfDistance(const gfx::Point& coordinate) const { const gfx::Rect bounds = GetBoundsInScreen(); int distance = shelf_->SelectValueForShelfAlignment( diff --git a/ash/shelf/shelf_view.h b/ash/shelf/shelf_view.h index 1343283..6971374 100644 --- a/ash/shelf/shelf_view.h +++ b/ash/shelf/shelf_view.h @@ -9,10 +9,10 @@ #include <utility> #include <vector> -#include "ash/shelf/shelf_button_host.h" #include "ash/shelf/shelf_button_pressed_metric_tracker.h" #include "ash/shelf/shelf_item_delegate.h" #include "ash/shelf/shelf_model_observer.h" +#include "ash/shelf/shelf_tooltip_manager.h" #include "ash/wm/gestures/shelf_gesture_handler.h" #include "base/macros.h" #include "base/observer_list.h" @@ -44,7 +44,6 @@ class DragImageView; class OverflowBubble; class OverflowButton; class ShelfButton; -class ShelfTooltipManager; namespace test { class ShelfViewTestAPI; @@ -58,7 +57,6 @@ extern const int SHELF_ALIGNMENT_UMA_ENUM_VALUE_COUNT; class ASH_EXPORT ShelfView : public views::View, public ShelfModelObserver, public views::ButtonListener, - public ShelfButtonHost, public views::ContextMenuController, public views::FocusTraversable, public views::BoundsAnimatorObserver, @@ -67,8 +65,6 @@ class ASH_EXPORT ShelfView : public views::View, ShelfView(ShelfModel* model, ShelfDelegate* delegate, Shelf* shelf); ~ShelfView() override; - ShelfTooltipManager* tooltip_manager() { return tooltip_.get(); } - Shelf* shelf() const { return shelf_; } ShelfModel* model() const { return model_; } @@ -106,7 +102,13 @@ class ASH_EXPORT ShelfView : public views::View, // There are thin gaps between launcher buttons but the tooltip shouldn't hide // in the gaps, but the tooltip should hide if the mouse moved totally outside // of the buttons area. - bool ShouldHideTooltip(const gfx::Point& cursor_location); + bool ShouldHideTooltip(const gfx::Point& cursor_location) const; + + // Returns true if a tooltip should be shown for the shelf item |view|. + bool ShouldShowTooltipForView(const views::View* view) const; + + // Returns the title of the shelf item |view|. + base::string16 GetTitleForView(const views::View* view) const; // Returns rectangle bounding all visible launcher items. Used screen // coordinate system. @@ -131,6 +133,18 @@ class ASH_EXPORT ShelfView : public views::View, bool Drag(const gfx::Point& location_in_screen_coordinates) override; void EndDrag(bool cancel) override; + // The shelf buttons use the Pointer interface to enable item reordering. + enum Pointer { NONE, DRAG_AND_DROP, MOUSE, TOUCH }; + void PointerPressedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event); + void PointerDraggedOnButton(views::View* view, + Pointer pointer, + const ui::LocatedEvent& event); + void PointerReleasedOnButton(views::View* view, + Pointer pointer, + bool canceled); + // Return the view model for test purposes. const views::ViewModel* view_model_for_test() const { return view_model_.get(); @@ -246,6 +260,8 @@ class ASH_EXPORT ShelfView : public views::View, void OnBoundsChanged(const gfx::Rect& previous_bounds) override; FocusTraversable* GetPaneFocusTraversable() override; void GetAccessibleState(ui::AXViewState* state) override; + void ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) override; // Overridden from ui::EventHandler: void OnGestureEvent(ui::GestureEvent* event) override; @@ -256,21 +272,6 @@ class ASH_EXPORT ShelfView : public views::View, void ShelfItemChanged(int model_index, const ShelfItem& old_item) override; void ShelfItemMoved(int start_index, int target_index) override; - // Overridden from ShelfButtonHost: - void PointerPressedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) override; - void PointerDraggedOnButton(views::View* view, - Pointer pointer, - const ui::LocatedEvent& event) override; - void PointerReleasedOnButton(views::View* view, - Pointer pointer, - bool canceled) override; - void MouseMovedOverButton(views::View* view) override; - void MouseEnteredButton(views::View* view) override; - void MouseExitedButton(views::View* view) override; - base::string16 GetAccessibleName(const views::View* view) override; - // Overridden from views::ButtonListener: void ButtonPressed(views::Button* sender, const ui::Event& event) override; @@ -309,9 +310,6 @@ class ASH_EXPORT ShelfView : public views::View, // Convenience accessor to model_->items(). const ShelfItem* ShelfItemForView(const views::View* view) const; - // Returns true if a tooltip should be shown for |view|. - bool ShouldShowTooltipForView(const views::View* view) const; - // Get the distance from the given |coordinate| to the closest point on this // launcher/shelf. int CalculateShelfDistance(const gfx::Point& coordinate) const; @@ -344,7 +342,7 @@ class ASH_EXPORT ShelfView : public views::View, OverflowBubble* owner_overflow_bubble_; - scoped_ptr<ShelfTooltipManager> tooltip_; + ShelfTooltipManager tooltip_; // Pointer device that initiated the current drag operation. If there is no // current dragging operation, this is NONE. diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index 71e5e7f..68ebf31 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc @@ -106,9 +106,7 @@ class ShelfViewIconObserverTest : public AshTestBase { TestShelfIconObserver* observer() { return observer_.get(); } - ShelfViewTestAPI* shelf_view_test() { - return shelf_view_test_.get(); - } + ShelfViewTestAPI* shelf_view_test() { return shelf_view_test_.get(); } Shelf* ShelfForSecondaryDisplay() { return Shelf::ForWindow(Shell::GetAllRootWindows()[1]); @@ -432,52 +430,46 @@ class ShelfViewTest : public AshTestBase { } } - ShelfButton* SimulateButtonPressed(ShelfButtonHost::Pointer pointer, + ShelfButton* SimulateButtonPressed(ShelfView::Pointer pointer, int button_index) { - ShelfButtonHost* button_host = shelf_view_; ShelfButton* button = test_api_->GetButton(button_index); ui::MouseEvent click_event(ui::ET_MOUSE_PRESSED, gfx::Point(), button->GetBoundsInScreen().origin(), ui::EventTimeForNow(), 0, 0); - button_host->PointerPressedOnButton(button, pointer, click_event); + shelf_view_->PointerPressedOnButton(button, pointer, click_event); return button; } // Simulates a single mouse click. void SimulateClick(int button_index) { - ShelfButtonHost* button_host = shelf_view_; - ShelfButton* button = - SimulateButtonPressed(ShelfButtonHost::MOUSE, button_index); + ShelfButton* button = SimulateButtonPressed(ShelfView::MOUSE, button_index); ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, gfx::Point(), button->GetBoundsInScreen().origin(), ui::EventTimeForNow(), 0, 0); test_api_->ButtonPressed(button, release_event); - button_host->PointerReleasedOnButton(button, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(button, ShelfView::MOUSE, false); } // Simulates the second click of a double click. void SimulateDoubleClick(int button_index) { - ShelfButtonHost* button_host = shelf_view_; - ShelfButton* button = - SimulateButtonPressed(ShelfButtonHost::MOUSE, button_index); + ShelfButton* button = SimulateButtonPressed(ShelfView::MOUSE, button_index); ui::MouseEvent release_event(ui::ET_MOUSE_RELEASED, gfx::Point(), button->GetBoundsInScreen().origin(), ui::EventTimeForNow(), ui::EF_IS_DOUBLE_CLICK, 0); test_api_->ButtonPressed(button, release_event); - button_host->PointerReleasedOnButton(button, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(button, ShelfView::MOUSE, false); } void DoDrag(int dist_x, int dist_y, views::View* button, - ShelfButtonHost::Pointer pointer, + ShelfView::Pointer pointer, views::View* to) { ui::MouseEvent drag_event(ui::ET_MOUSE_DRAGGED, gfx::Point(dist_x, dist_y), to->GetBoundsInScreen().origin(), ui::EventTimeForNow(), 0, 0); - static_cast<ShelfButtonHost*>(shelf_view_) - ->PointerDraggedOnButton(button, pointer, drag_event); + shelf_view_->PointerDraggedOnButton(button, pointer, drag_event); } /* @@ -487,7 +479,7 @@ class ShelfViewTest : public AshTestBase { * drag behavior. */ void ContinueDrag(views::View* button, - ShelfButtonHost::Pointer pointer, + ShelfView::Pointer pointer, int from_index, int to_index, bool progressively) { @@ -511,7 +503,7 @@ class ShelfViewTest : public AshTestBase { * series of changes of the posistion of dragged item) like the behavior of * user drags. */ - views::View* SimulateDrag(ShelfButtonHost::Pointer pointer, + views::View* SimulateDrag(ShelfView::Pointer pointer, int button_index, int destination_index, bool progressively) { @@ -534,12 +526,12 @@ class ShelfViewTest : public AshTestBase { void DragAndVerify( int from, int to, - ShelfButtonHost* button_host, + ShelfView* shelf_view, const std::vector<std::pair<int, views::View*>>& expected_id_map) { views::View* dragged_button = - SimulateDrag(ShelfButtonHost::MOUSE, from, to, true); - button_host->PointerReleasedOnButton(dragged_button, ShelfButtonHost::MOUSE, - false); + SimulateDrag(ShelfView::MOUSE, from, to, true); + shelf_view->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, + false); test_api_->RunMessageLoopUntilAnimationsDone(); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(expected_id_map)); } @@ -564,10 +556,6 @@ class ShelfViewTest : public AshTestBase { ASSERT_NO_FATAL_FAILURE(CheckModelIDs(*id_map)); } - views::View* GetTooltipAnchorView() { - return shelf_view_->tooltip_manager()->anchor_; - } - void AddButtonsUntilOverflow() { int items_added = 0; while (!test_api_->IsOverflowButtonVisible()) { @@ -577,10 +565,6 @@ class ShelfViewTest : public AshTestBase { } } - void ShowTooltip() { - shelf_view_->tooltip_manager()->ShowInternal(); - } - void TestDraggingAnItemFromOverflowToShelf(bool cancel) { test_api_->ShowOverflowBubble(); ASSERT_TRUE(test_api_->overflow_bubble() && @@ -1106,107 +1090,97 @@ TEST_F(ShelfViewTest, AddButtonQuickly) { // Check that model changes are handled correctly while a shelf icon is being // dragged. TEST_F(ShelfViewTest, ModelChangesWhileDragging) { - ShelfButtonHost* button_host = shelf_view_; - std::vector<std::pair<ShelfID, views::View*> > id_map; SetupForDragTest(&id_map); // Dragging browser shortcut at index 1. EXPECT_TRUE(model_->items()[1].type == TYPE_BROWSER_SHORTCUT); - views::View* dragged_button = - SimulateDrag(ShelfButtonHost::MOUSE, 1, 3, false); + views::View* dragged_button = SimulateDrag(ShelfView::MOUSE, 1, 3, false); std::rotate(id_map.begin() + 1, id_map.begin() + 2, id_map.begin() + 4); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); - button_host->PointerReleasedOnButton( - dragged_button, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false); EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT); // Dragging changes model order. - dragged_button = SimulateDrag(ShelfButtonHost::MOUSE, 1, 3, false); + dragged_button = SimulateDrag(ShelfView::MOUSE, 1, 3, false); std::rotate(id_map.begin() + 1, id_map.begin() + 2, id_map.begin() + 4); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); // Cancelling the drag operation restores previous order. - button_host->PointerReleasedOnButton( - dragged_button, ShelfButtonHost::MOUSE, true); + shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, true); std::rotate(id_map.begin() + 1, id_map.begin() + 3, id_map.begin() + 4); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); // Deleting an item keeps the remaining intact. - dragged_button = SimulateDrag(ShelfButtonHost::MOUSE, 1, 3, false); + dragged_button = SimulateDrag(ShelfView::MOUSE, 1, 3, false); model_->RemoveItemAt(1); id_map.erase(id_map.begin() + 1); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); - button_host->PointerReleasedOnButton( - dragged_button, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false); // Adding a shelf item cancels the drag and respects the order. - dragged_button = SimulateDrag(ShelfButtonHost::MOUSE, 1, 3, false); + dragged_button = SimulateDrag(ShelfView::MOUSE, 1, 3, false); ShelfID new_id = AddAppShortcut(); id_map.insert(id_map.begin() + 6, std::make_pair(new_id, GetButtonByID(new_id))); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); - button_host->PointerReleasedOnButton( - dragged_button, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false); // Adding a shelf item at the end (i.e. a panel) canels drag and respects // the order. - dragged_button = SimulateDrag(ShelfButtonHost::MOUSE, 1, 3, false); + dragged_button = SimulateDrag(ShelfView::MOUSE, 1, 3, false); new_id = AddPanel(); id_map.insert(id_map.begin() + 7, std::make_pair(new_id, GetButtonByID(new_id))); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); - button_host->PointerReleasedOnButton( - dragged_button, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false); } // Check that 2nd drag from the other pointer would be ignored. TEST_F(ShelfViewTest, SimultaneousDrag) { - ShelfButtonHost* button_host = shelf_view_; - std::vector<std::pair<ShelfID, views::View*> > id_map; SetupForDragTest(&id_map); // Start a mouse drag. views::View* dragged_button_mouse = - SimulateDrag(ShelfButtonHost::MOUSE, 1, 3, false); + SimulateDrag(ShelfView::MOUSE, 1, 3, false); std::rotate(id_map.begin() + 1, id_map.begin() + 2, id_map.begin() + 4); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); // Attempt a touch drag before the mouse drag finishes. views::View* dragged_button_touch = - SimulateDrag(ShelfButtonHost::TOUCH, 4, 2, false); + SimulateDrag(ShelfView::TOUCH, 4, 2, false); // Nothing changes since 2nd drag is ignored. ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); // Finish the mouse drag. - button_host->PointerReleasedOnButton( - dragged_button_mouse, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(dragged_button_mouse, ShelfView::MOUSE, + false); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); // Now start a touch drag. - dragged_button_touch = SimulateDrag(ShelfButtonHost::TOUCH, 4, 2, false); + dragged_button_touch = SimulateDrag(ShelfView::TOUCH, 4, 2, false); std::rotate(id_map.begin() + 3, id_map.begin() + 4, id_map.begin() + 5); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); // And attempt a mouse drag before the touch drag finishes. - dragged_button_mouse = SimulateDrag(ShelfButtonHost::MOUSE, 1, 2, false); + dragged_button_mouse = SimulateDrag(ShelfView::MOUSE, 1, 2, false); // Nothing changes since 2nd drag is ignored. ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); - button_host->PointerReleasedOnButton( - dragged_button_touch, ShelfButtonHost::TOUCH, false); + shelf_view_->PointerReleasedOnButton(dragged_button_touch, ShelfView::TOUCH, + false); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); } @@ -1235,8 +1209,6 @@ TEST_F(ShelfViewTest, DragWithNotDraggableItemInFront) { // Check that clicking first on one item and then dragging another works as // expected. TEST_F(ShelfViewTest, ClickOneDragAnother) { - ShelfButtonHost* button_host = shelf_view_; - std::vector<std::pair<ShelfID, views::View*> > id_map; SetupForDragTest(&id_map); @@ -1245,14 +1217,10 @@ TEST_F(ShelfViewTest, ClickOneDragAnother) { // Dragging browser index at 0 should change the model order correctly. EXPECT_TRUE(model_->items()[1].type == TYPE_BROWSER_SHORTCUT); - views::View* dragged_button = - SimulateDrag(ShelfButtonHost::MOUSE, 1, 3, false); - std::rotate(id_map.begin() + 1, - id_map.begin() + 2, - id_map.begin() + 4); + views::View* dragged_button = SimulateDrag(ShelfView::MOUSE, 1, 3, false); + std::rotate(id_map.begin() + 1, id_map.begin() + 2, id_map.begin() + 4); ASSERT_NO_FATAL_FAILURE(CheckModelIDs(id_map)); - button_host->PointerReleasedOnButton( - dragged_button, ShelfButtonHost::MOUSE, false); + shelf_view_->PointerReleasedOnButton(dragged_button, ShelfView::MOUSE, false); EXPECT_TRUE(model_->items()[3].type == TYPE_BROWSER_SHORTCUT); } @@ -1375,8 +1343,7 @@ TEST_F(ShelfViewTest, ShelfItemBoundsCheck) { } TEST_F(ShelfViewTest, ShelfTooltipTest) { - ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1, - test_api_->GetButtonCount()); + ASSERT_EQ(test_api_->GetLastVisibleIndex() + 1, test_api_->GetButtonCount()); // Prepare some items to the shelf. ShelfID app_button_id = AddAppShortcut(); @@ -1385,53 +1352,53 @@ TEST_F(ShelfViewTest, ShelfTooltipTest) { ShelfButton* app_button = GetButtonByID(app_button_id); ShelfButton* platform_button = GetButtonByID(platform_button_id); - ShelfButtonHost* button_host = shelf_view_; - ShelfTooltipManager* tooltip_manager = shelf_view_->tooltip_manager(); + ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager(); + EXPECT_TRUE(test_api_->shelf_view()->GetWidget()->GetNativeWindow()); + ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow()); - button_host->MouseEnteredButton(app_button); + generator.MoveMouseTo(app_button->GetBoundsInScreen().CenterPoint()); // There's a delay to show the tooltip, so it's not visible yet. EXPECT_FALSE(tooltip_manager->IsVisible()); - EXPECT_EQ(app_button, GetTooltipAnchorView()); + EXPECT_EQ(nullptr, tooltip_manager->GetCurrentAnchorView()); - ShowTooltip(); + tooltip_manager->ShowTooltip(app_button); EXPECT_TRUE(tooltip_manager->IsVisible()); - - // Once it's visible, it keeps visibility and is pointing to the same - // item. - button_host->MouseExitedButton(app_button); + EXPECT_EQ(app_button, tooltip_manager->GetCurrentAnchorView()); + + // The tooltip will continue showing while the cursor moves between buttons. + const gfx::Point midpoint = + gfx::UnionRects(app_button->GetBoundsInScreen(), + platform_button->GetBoundsInScreen()) + .CenterPoint(); + generator.MoveMouseTo(midpoint); EXPECT_TRUE(tooltip_manager->IsVisible()); - EXPECT_EQ(app_button, GetTooltipAnchorView()); + EXPECT_EQ(app_button, tooltip_manager->GetCurrentAnchorView()); - // When entered to another item, it switches to the new item. There is no - // delay for the visibility. - button_host->MouseEnteredButton(platform_button); + // When the cursor moves over another item, its tooltip shows immediately. + generator.MoveMouseTo(platform_button->GetBoundsInScreen().CenterPoint()); EXPECT_TRUE(tooltip_manager->IsVisible()); - EXPECT_EQ(platform_button, GetTooltipAnchorView()); - - button_host->MouseExitedButton(platform_button); + EXPECT_EQ(platform_button, tooltip_manager->GetCurrentAnchorView()); tooltip_manager->Close(); - // Next time: enter app_button -> move immediately to tab_button. - button_host->MouseEnteredButton(app_button); - button_host->MouseExitedButton(app_button); - button_host->MouseEnteredButton(platform_button); + // Now cursor over the app_button and move immediately to the platform_button. + generator.MoveMouseTo(app_button->GetBoundsInScreen().CenterPoint()); + generator.MoveMouseTo(midpoint); + generator.MoveMouseTo(platform_button->GetBoundsInScreen().CenterPoint()); EXPECT_FALSE(tooltip_manager->IsVisible()); - EXPECT_EQ(platform_button, GetTooltipAnchorView()); + EXPECT_EQ(nullptr, tooltip_manager->GetCurrentAnchorView()); } // Verify a fix for crash caused by a tooltip update for a deleted shelf // button, see crbug.com/288838. TEST_F(ShelfViewTest, RemovingItemClosesTooltip) { - ShelfButtonHost* button_host = shelf_view_; - ShelfTooltipManager* tooltip_manager = shelf_view_->tooltip_manager(); + ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager(); // Add an item to the shelf. ShelfID app_button_id = AddAppShortcut(); ShelfButton* app_button = GetButtonByID(app_button_id); // Spawn a tooltip on that item. - button_host->MouseEnteredButton(app_button); - ShowTooltip(); + tooltip_manager->ShowTooltip(app_button); EXPECT_TRUE(tooltip_manager->IsVisible()); // Remove the app shortcut while the tooltip is open. The tooltip should be @@ -1446,16 +1413,14 @@ TEST_F(ShelfViewTest, RemovingItemClosesTooltip) { // Changing the shelf alignment closes any open tooltip. TEST_F(ShelfViewTest, ShelfAlignmentClosesTooltip) { - ShelfButtonHost* button_host = shelf_view_; - ShelfTooltipManager* tooltip_manager = shelf_view_->tooltip_manager(); + ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager(); // Add an item to the shelf. ShelfID app_button_id = AddAppShortcut(); ShelfButton* app_button = GetButtonByID(app_button_id); // Spawn a tooltip on the item. - button_host->MouseEnteredButton(app_button); - ShowTooltip(); + tooltip_manager->ShowTooltip(app_button); EXPECT_TRUE(tooltip_manager->IsVisible()); // Changing shelf alignment hides the tooltip. @@ -1539,8 +1504,8 @@ TEST_F(ShelfViewTest, ShouldHideTooltipWithAppListWindowTest) { // Test that by moving the mouse cursor off the button onto the bubble it closes // the bubble. TEST_F(ShelfViewTest, ShouldHideTooltipWhenHoveringOnTooltip) { - ShelfTooltipManager* tooltip_manager = shelf_view_->tooltip_manager(); - tooltip_manager->CreateZeroDelayTimerForTest(); + ShelfTooltipManager* tooltip_manager = test_api_->tooltip_manager(); + tooltip_manager->set_timer_delay_for_test(0); ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); // Move the mouse off any item and check that no tooltip is shown. diff --git a/ash/test/shelf_test_api.cc b/ash/test/shelf_test_api.cc index d050f73..83bc841 100644 --- a/ash/test/shelf_test_api.cc +++ b/ash/test/shelf_test_api.cc @@ -9,12 +9,9 @@ namespace ash { namespace test { -ShelfTestAPI::ShelfTestAPI(Shelf* shelf) - : shelf_(shelf) { -} +ShelfTestAPI::ShelfTestAPI(Shelf* shelf) : shelf_(shelf) {} -ShelfTestAPI::~ShelfTestAPI() { -} +ShelfTestAPI::~ShelfTestAPI() {} ShelfView* ShelfTestAPI::shelf_view() { return shelf_->shelf_view_; } diff --git a/ash/test/shelf_view_test_api.cc b/ash/test/shelf_view_test_api.cc index 1ab9dcb..780274e 100644 --- a/ash/test/shelf_view_test_api.cc +++ b/ash/test/shelf_view_test_api.cc @@ -101,6 +101,10 @@ OverflowBubble* ShelfViewTestAPI::overflow_bubble() { return shelf_view_->overflow_bubble_.get(); } +ShelfTooltipManager* ShelfViewTestAPI::tooltip_manager() { + return &shelf_view_->tooltip_; +} + gfx::Size ShelfViewTestAPI::GetPreferredSize() { return shelf_view_->GetPreferredSize(); } diff --git a/ash/test/shelf_view_test_api.h b/ash/test/shelf_view_test_api.h index 9d5f594..9b03588 100644 --- a/ash/test/shelf_view_test_api.h +++ b/ash/test/shelf_view_test_api.h @@ -27,6 +27,7 @@ class OverflowBubble; class ShelfButton; class ShelfButtonPressedMetricTracker; class ShelfDelegate; +class ShelfTooltipManager; class ShelfView; namespace test { @@ -68,6 +69,9 @@ class ShelfViewTestAPI { // An accessor for |shelf_view|. ShelfView* shelf_view() { return shelf_view_; } + // An accessor for the shelf tooltip manager. + ShelfTooltipManager* tooltip_manager(); + // An accessor for overflow bubble. OverflowBubble* overflow_bubble(); |