app_list_item_view.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef ASH_APP_LIST_VIEWS_APP_LIST_ITEM_VIEW_H_
  5. #define ASH_APP_LIST_VIEWS_APP_LIST_ITEM_VIEW_H_
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "ash/app_list/grid_index.h"
  10. #include "ash/app_list/model/app_icon_load_helper.h"
  11. #include "ash/app_list/model/app_list_item_observer.h"
  12. #include "ash/ash_export.h"
  13. #include "base/memory/ref_counted.h"
  14. #include "base/timer/timer.h"
  15. #include "third_party/abseil-cpp/absl/types/optional.h"
  16. #include "ui/compositor/layer_animation_observer.h"
  17. #include "ui/views/context_menu_controller.h"
  18. #include "ui/views/controls/button/button.h"
  19. namespace gfx {
  20. class Point;
  21. class Rect;
  22. } // namespace gfx
  23. namespace ui {
  24. class LocatedEvent;
  25. class SimpleMenuModel;
  26. } // namespace ui
  27. namespace views {
  28. class Label;
  29. } // namespace views
  30. namespace ash {
  31. class AppsGridContextMenu;
  32. class AppListConfig;
  33. class AppListItem;
  34. class AppListMenuModelAdapter;
  35. class AppListViewDelegate;
  36. class DotIndicator;
  37. namespace test {
  38. class AppsGridViewTest;
  39. class AppListMainViewTest;
  40. } // namespace test
  41. // An application icon and title. Commonly part of the AppsGridView, but may be
  42. // used in other contexts. Supports dragging and keyboard selection via the
  43. // GridDelegate interface.
  44. class ASH_EXPORT AppListItemView : public views::Button,
  45. public views::ContextMenuController,
  46. public AppListItemObserver,
  47. public ui::ImplicitAnimationObserver {
  48. public:
  49. METADATA_HEADER(AppListItemView);
  50. // The types of context where the app list item view is shown.
  51. enum class Context {
  52. // The item is shown in an AppsGridView.
  53. kAppsGridView,
  54. // The item is shown in the RecentAppsView.
  55. kRecentAppsView
  56. };
  57. // The parent apps grid (AppsGridView) or a stub. Not named "Delegate" to
  58. // differentiate it from AppListViewDelegate.
  59. class GridDelegate {
  60. public:
  61. virtual ~GridDelegate() = default;
  62. // Whether the parent apps grid (if any) is a folder.
  63. virtual bool IsInFolder() const = 0;
  64. // Methods for keyboard selection.
  65. virtual void SetSelectedView(AppListItemView* view) = 0;
  66. virtual void ClearSelectedView() = 0;
  67. virtual bool IsSelectedView(const AppListItemView* view) const = 0;
  68. // Registers `view` as a dragged item with the apps grid. Called when the
  69. // user presses the mouse, or starts touch interaction with the view (both
  70. // of which may transition into a drag operation).
  71. // `location` - The pointer location in the view's bounds.
  72. // `root_location` - The pointer location in the root window coordinates.
  73. // `drag_start_callback` - Callback that gets called when the mouse/touch
  74. // interaction transitions into a drag (i.e. when the "drag" item starts
  75. // moving.
  76. // `drag_end_callback` - Callback that gets called when drag interaction
  77. // ends.
  78. // Returns whether `view` has been registered as a dragged view. Callbacks
  79. // should be ignored if the method returns false. If the method returns
  80. // true, it's expected to eventually run `drag_end_callback`.
  81. virtual bool InitiateDrag(AppListItemView* view,
  82. const gfx::Point& location,
  83. const gfx::Point& root_location,
  84. base::OnceClosure drag_start_callback,
  85. base::OnceClosure drag_end_callback) = 0;
  86. virtual void StartDragAndDropHostDragAfterLongPress() = 0;
  87. // Called from AppListItemView when it receives a drag event. Returns true
  88. // if the drag is still happening.
  89. virtual bool UpdateDragFromItem(bool is_touch,
  90. const ui::LocatedEvent& event) = 0;
  91. virtual void EndDrag(bool cancel) = 0;
  92. // Provided as a callback for AppListItemView to notify of activation via
  93. // press/click/return key.
  94. virtual void OnAppListItemViewActivated(AppListItemView* pressed_item_view,
  95. const ui::Event& event) = 0;
  96. };
  97. AppListItemView(const AppListConfig* app_list_config,
  98. GridDelegate* grid_delegate,
  99. AppListItem* item,
  100. AppListViewDelegate* view_delegate,
  101. Context context);
  102. AppListItemView(const AppListItemView&) = delete;
  103. AppListItemView& operator=(const AppListItemView&) = delete;
  104. ~AppListItemView() override;
  105. // Initializes icon loader. Should be called after the view has been added to
  106. // the apps grid view model - otherwise, if icon gets updated synchronously,
  107. // it may update the item metadata before the view gets added to the view
  108. // model. If the metadata update causes a position change, attempts to move
  109. // the item in the view model could crash.
  110. void InitializeIconLoader();
  111. // Sets the app list config that should be used to size the app list icon, and
  112. // margins within the app list item view. The owner should ensure the
  113. // `AppListItemView` does not outlive the object referenced by
  114. // `app_list_config_`.
  115. void UpdateAppListConfig(const AppListConfig* app_list_config);
  116. // Sets the icon of this image.
  117. void SetIcon(const gfx::ImageSkia& icon);
  118. void SetItemName(const std::u16string& display_name,
  119. const std::u16string& full_name);
  120. void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
  121. void CancelContextMenu();
  122. gfx::Point GetDragImageOffset();
  123. void SetAsAttemptedFolderTarget(bool is_target_folder);
  124. // Sets focus without a11y announcements or focus ring.
  125. void SilentlyRequestFocus();
  126. // Ensures that the item view is selected by `grid_delegate_`.
  127. void EnsureSelected();
  128. AppListItem* item() const { return item_weak_; }
  129. views::Label* title() { return title_; }
  130. // In a synchronous drag the item view isn't informed directly of the drag
  131. // ending, so the runner of the drag should call this.
  132. void OnSyncDragEnd();
  133. // Returns the icon bounds relative to AppListItemView.
  134. gfx::Rect GetIconBounds() const;
  135. // Returns the icon bounds in screen.
  136. gfx::Rect GetIconBoundsInScreen() const;
  137. // Returns the image of icon.
  138. gfx::ImageSkia GetIconImage() const;
  139. // Sets the icon's visibility.
  140. void SetIconVisible(bool visible);
  141. // Handles the icon's scaling and animation for a cardified grid.
  142. void EnterCardifyState();
  143. void ExitCardifyState();
  144. // Returns the icon bounds for with |target_bounds| as the bounds of this view
  145. // and given |icon_size| and the |icon_scale| if the icon was scaled from the
  146. // original display size.
  147. static gfx::Rect GetIconBoundsForTargetViewBounds(
  148. const AppListConfig* config,
  149. const gfx::Rect& target_bounds,
  150. const gfx::Size& icon_size,
  151. float icon_scale);
  152. // Returns the title bounds for with |target_bounds| as the bounds of this
  153. // view and given |title_size| and the |icon_scale| if the icon was scaled
  154. // from the original display size.
  155. static gfx::Rect GetTitleBoundsForTargetViewBounds(
  156. const AppListConfig* config,
  157. const gfx::Rect& target_bounds,
  158. const gfx::Size& title_size,
  159. float icon_scale);
  160. // views::Button overrides:
  161. void OnGestureEvent(ui::GestureEvent* event) override;
  162. void OnThemeChanged() override;
  163. // views::View overrides:
  164. std::u16string GetTooltipText(const gfx::Point& p) const override;
  165. // When a dragged view enters this view, a preview circle is shown for
  166. // non-folder item while the icon is enlarged for folder item. When a
  167. // dragged view exits this view, the reverse animation will be performed.
  168. void OnDraggedViewEnter();
  169. void OnDraggedViewExit();
  170. // Enables background blur for folder icon if |enabled| is true.
  171. void SetBackgroundBlurEnabled(bool enabled);
  172. // Ensures this item view has its own layer.
  173. void EnsureLayer();
  174. bool HasNotificationBadge();
  175. void FireMouseDragTimerForTest();
  176. bool FireTouchDragTimerForTest();
  177. // Whether the context menu on a non-folder app item view is showing.
  178. bool IsShowingAppMenu() const;
  179. bool is_folder() const { return is_folder_; }
  180. bool IsNotificationIndicatorShownForTest() const;
  181. GridDelegate* grid_delegate_for_test() { return grid_delegate_; }
  182. const gfx::ImageSkia& icon_image_for_test() const { return icon_image_; }
  183. AppListMenuModelAdapter* item_menu_model_adapter() const {
  184. return item_menu_model_adapter_.get();
  185. }
  186. AppsGridContextMenu* context_menu_for_folder() const {
  187. return context_menu_for_folder_.get();
  188. }
  189. // Sets the callback which will run after the context menu is shown.
  190. void SetContextMenuShownCallbackForTest(base::RepeatingClosure closure);
  191. // Returns the bounds that would be used for the title if there was no blue
  192. // dot for new install.
  193. gfx::Rect GetDefaultTitleBoundsForTest();
  194. // Sets the most recent grid index for this item view. Also sets
  195. // `has_pending_row_change_` based on whether the grid index change is
  196. // considered a row change for the purposes of animating item views between
  197. // rows.
  198. void SetMostRecentGridIndex(GridIndex new_grid_index, int columns);
  199. bool has_pending_row_change() { return has_pending_row_change_; }
  200. void reset_has_pending_row_change() { has_pending_row_change_ = false; }
  201. private:
  202. friend class AppListItemViewTest;
  203. friend class AppListMainViewTest;
  204. friend class test::AppsGridViewTest;
  205. class IconImageView;
  206. enum UIState {
  207. UI_STATE_NORMAL, // Normal UI (icon + label)
  208. UI_STATE_DRAGGING, // Dragging UI (scaled icon only)
  209. UI_STATE_DROPPING_IN_FOLDER, // Folder dropping preview UI
  210. };
  211. // Describes the app list item view drag state.
  212. enum class DragState {
  213. // Item is not being dragged.
  214. kNone,
  215. // Drag is initialized for the item (the owning apps grid considers the view
  216. // to be the dragged view), but the item is still not being dragged.
  217. // Depending on mouse/touch drag timers, UI may be in either normal, or
  218. // dragging state.
  219. kInitialized,
  220. // The item drag is in progress. While in this state, the owning apps grid
  221. // view will generally hide the item view, and replace it with a drag icon
  222. // widget. The UI should be in dragging state (scaled up and with title
  223. // hidden).
  224. kStarted,
  225. };
  226. // gfx::AnimationDelegate:
  227. void AnimationProgressed(const gfx::Animation* animation) override;
  228. // Callback used when a menu is closed.
  229. void OnMenuClosed();
  230. // Get icon from |item_| and schedule background processing.
  231. void UpdateIcon();
  232. // Update the tooltip text from |item_|.
  233. void UpdateTooltip();
  234. void SetUIState(UIState state);
  235. // Scales up app icon if |scale_up| is true; otherwise, scale it back to
  236. // normal size.
  237. void ScaleAppIcon(bool scale_up);
  238. // Scale app icon to |scale_factor| without animation.
  239. void ScaleIconImmediatly(float scale_factor);
  240. // Sets |touch_dragging_| flag and updates UI.
  241. void SetTouchDragging(bool touch_dragging);
  242. // Sets |mouse_dragging_| flag and updates UI. Only to be called on
  243. // |mouse_drag_timer_|.
  244. void SetMouseDragging(bool mouse_dragging);
  245. // Invoked when |mouse_drag_timer_| fires to show dragging UI.
  246. void OnMouseDragTimer();
  247. // Invoked when |touch_drag_timer_| fires to show dragging UI.
  248. void OnTouchDragTimer(const gfx::Point& tap_down_location,
  249. const gfx::Point& tap_down_root_location);
  250. // Registers this view as a dragged view with the grid delegate.
  251. bool InitiateDrag(const gfx::Point& location,
  252. const gfx::Point& root_location);
  253. // Called when the drag registered for this view starts moving.
  254. // `drag_start_callback` passed to `GridDelegate::InitiateDrag()`.
  255. void OnDragStarted();
  256. // Called when the drag registered for this view ends.
  257. // `drag_end_callback` passed to `GridDelegate::InitiateDrag()`.
  258. void OnDragEnded();
  259. // Callback invoked when a context menu is received after calling
  260. // |AppListViewDelegate::GetContextMenuModel|.
  261. void OnContextMenuModelReceived(
  262. const gfx::Point& point,
  263. ui::MenuSourceType source_type,
  264. std::unique_ptr<ui::SimpleMenuModel> menu_model);
  265. // views::ContextMenuController overrides:
  266. void ShowContextMenuForViewImpl(views::View* source,
  267. const gfx::Point& point,
  268. ui::MenuSourceType source_type) override;
  269. // views::Button overrides:
  270. bool ShouldEnterPushedState(const ui::Event& event) override;
  271. void PaintButtonContents(gfx::Canvas* canvas) override;
  272. // views::View overrides:
  273. void Layout() override;
  274. gfx::Size CalculatePreferredSize() const override;
  275. bool OnKeyPressed(const ui::KeyEvent& event) override;
  276. bool OnMousePressed(const ui::MouseEvent& event) override;
  277. void OnMouseReleased(const ui::MouseEvent& event) override;
  278. void OnMouseCaptureLost() override;
  279. bool OnMouseDragged(const ui::MouseEvent& event) override;
  280. bool SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) override;
  281. void OnFocus() override;
  282. void OnBlur() override;
  283. // AppListItemObserver overrides:
  284. void ItemIconChanged(AppListConfigType config_type) override;
  285. void ItemNameChanged() override;
  286. void ItemBadgeVisibilityChanged() override;
  287. void ItemBadgeColorChanged() override;
  288. void ItemIsNewInstallChanged() override;
  289. void ItemBeingDestroyed() override;
  290. // ui::ImplicitAnimationObserver:
  291. void OnImplicitAnimationsCompleted() override;
  292. // Returns the radius of preview circle.
  293. int GetPreviewCircleRadius() const;
  294. // Creates dragged view hover animation if it does not exist.
  295. void CreateDraggedViewHoverAnimation();
  296. // Modifies AppListItemView bounds to match the selected highlight bounds.
  297. void AdaptBoundsForSelectionHighlight(gfx::Rect* rect);
  298. // Calculates the transform between the icon scaled by |icon_scale| and the
  299. // normal size icon.
  300. gfx::Transform GetScaleTransform(float icon_scale);
  301. // The app list config used to layout this view. The initial values is set
  302. // during view construction, but can be changed by calling
  303. // `UpdateAppListConfig()`.
  304. const AppListConfig* app_list_config_;
  305. const bool is_folder_;
  306. // Whether context menu options have been requested. Prevents multiple
  307. // requests.
  308. bool waiting_for_context_menu_options_ = false;
  309. AppListItem* item_weak_; // Owned by AppListModel. Can be nullptr.
  310. // Handles dragging and item selection. Might be a stub for items that are not
  311. // part of an apps grid.
  312. GridDelegate* const grid_delegate_;
  313. // AppListControllerImpl by another name.
  314. AppListViewDelegate* const view_delegate_;
  315. IconImageView* icon_ = nullptr; // Strongly typed child view.
  316. views::Label* title_ = nullptr; // Strongly typed child view.
  317. // Draws a dot next to the title for newly installed apps. Only exists when
  318. // ProductivityLauncher is enabled.
  319. views::View* new_install_dot_ = nullptr;
  320. // The context menu model adapter used for app item view.
  321. std::unique_ptr<AppListMenuModelAdapter> item_menu_model_adapter_;
  322. // The context menu controller used for folder item view.
  323. std::unique_ptr<AppsGridContextMenu> context_menu_for_folder_;
  324. UIState ui_state_ = UI_STATE_NORMAL;
  325. // True if scroll gestures should contribute to dragging.
  326. bool touch_dragging_ = false;
  327. // True if the app is enabled for drag/drop operation by mouse.
  328. bool mouse_dragging_ = false;
  329. // Whether AppsGridView should not be notified of a focus event, triggering
  330. // A11y alerts and a focus ring.
  331. bool focus_silently_ = false;
  332. // Whether AppsGridView is in cardified state.
  333. bool in_cardified_grid_ = false;
  334. // The animation that runs when dragged view enters or exits this view.
  335. std::unique_ptr<gfx::SlideAnimation> dragged_view_hover_animation_;
  336. // The radius of preview circle for non-folder item.
  337. int preview_circle_radius_ = 0;
  338. // Whether `item_menu_model_adapter_` was cancelled as the result of a
  339. // continuous drag gesture.
  340. bool menu_close_initiated_from_drag_ = false;
  341. // Whether `item_menu_model_adapter_` was shown via key event.
  342. bool menu_show_initiated_from_key_ = false;
  343. std::u16string tooltip_text_;
  344. // A timer to defer showing drag UI when mouse is pressed.
  345. base::OneShotTimer mouse_drag_timer_;
  346. // A timer to defer showing drag UI when the app item is touch pressed.
  347. base::OneShotTimer touch_drag_timer_;
  348. // The bitmap image for this app list item.
  349. gfx::ImageSkia icon_image_;
  350. // The current item's drag state.
  351. DragState drag_state_ = DragState::kNone;
  352. // The scaling factor for displaying the app icon.
  353. float icon_scale_ = 1.0f;
  354. // Draws an indicator in the top right corner of the image to represent an
  355. // active notification.
  356. DotIndicator* notification_indicator_ = nullptr;
  357. // Indicates the context in which this view is shown.
  358. const Context context_;
  359. // Helper to trigger icon load.
  360. absl::optional<AppIconLoadHelper> icon_load_helper_;
  361. // Called when the context menu is shown.
  362. base::RepeatingClosure context_menu_shown_callback_;
  363. // The most recent location of this item within the app grid.
  364. GridIndex most_recent_grid_index_;
  365. // Whether the last grid index update was a change in position between rows.
  366. // Used to determine whether the animation between rows should be used.
  367. bool has_pending_row_change_ = false;
  368. // Whether the context menu removed focus on a view when opening. Used to
  369. // determine if the focus should be restored on context menu close.
  370. bool focus_removed_by_context_menu_ = false;
  371. base::WeakPtrFactory<AppListItemView> weak_ptr_factory_{this};
  372. };
  373. } // namespace ash
  374. #endif // ASH_APP_LIST_VIEWS_APP_LIST_ITEM_VIEW_H_