| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_ |
| #define ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_ |
| |
| #include <memory> |
| |
| #include "ash/ash_export.h" |
| #include "ash/wm/overview/overview_controller.h" |
| #include "ash/wm/splitview/split_view_types.h" |
| #include "base/containers/flat_map.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/timer/timer.h" |
| #include "ui/gfx/geometry/point_f.h" |
| #include "ui/gfx/geometry/rect_f.h" |
| #include "ui/gfx/geometry/size_f.h" |
| |
| namespace aura { |
| class Window; |
| } // namespace aura |
| |
| namespace ui { |
| class PresentationTimeRecorder; |
| } // namespace ui |
| |
| namespace ash { |
| |
| class OverviewGrid; |
| class OverviewItemBase; |
| class OverviewSession; |
| class SplitViewController; |
| |
| // These values are persisted to logs. Entries should not be renumbered and |
| // numeric values should never be reused. |
| // Workflows of dragging windows from overview (not from the top or shelf). |
| enum class OverviewDragAction { |
| kToGridSameDisplayClamshellMouse = 0, |
| kToGridSameDisplayClamshellTouch = 1, |
| kToDeskSameDisplayClamshellMouse = 2, |
| kToDeskSameDisplayClamshellTouch = 3, |
| kToSnapSameDisplayClamshellMouse = 4, |
| kToSnapSameDisplayClamshellTouch = 5, |
| kSwipeToCloseSuccessfulClamshellTouch = 6, |
| kSwipeToCloseCanceledClamshellTouch = 7, |
| kFlingToCloseClamshellTouch = 8, |
| kToGridOtherDisplayClamshellMouse = 9, |
| kToDeskOtherDisplayClamshellMouse = 10, |
| kToSnapOtherDisplayClamshellMouse = 11, |
| kToGridSameDisplayTabletTouch = 12, |
| kToDeskSameDisplayTabletTouch = 13, |
| kToSnapSameDisplayTabletTouch = 14, |
| kSwipeToCloseSuccessfulTabletTouch = 15, |
| kSwipeToCloseCanceledTabletTouch = 16, |
| kFlingToCloseTabletTouch = 17, |
| kMaxValue = kFlingToCloseTabletTouch, |
| }; |
| |
| // The drag controller for an overview window item in overview mode. It updates |
| // the position of the corresponding window item using transform while dragging. |
| // It also updates the split view drag indicators, which handles showing |
| // indicators where to drag, and preview areas showing the bounds of the |
| // window about to be snapped. |
| class ASH_EXPORT OverviewWindowDragController { |
| public: |
| enum class DragBehavior { |
| // No drag has started. |
| kNoDrag, |
| // Drag has started, but it is undecided whether we want to drag to snap or |
| // drag to close yet. |
| kUndefined, |
| // On drag complete, the window will be snapped, if it meets requirements, |
| // or moved to another desk if dropped on one of the desks' mini_views. This |
| // mode is triggered if the the window is initially dragged horizontally |
| // more than vertically (more in X than Y), or if the window item in the |
| // overview grid was gesture long pressed. |
| kNormalDrag, |
| // On drag complete, the window will be closed, if it meets requirements. |
| // This mode is triggered when the window is initially dragged vertically |
| // more than horizontally (more in Y than in X). |
| kDragToClose, |
| }; |
| |
| enum class DragResult { |
| // The drag ended without ever being disambiguated between a normal drag and |
| // drag-to-close. |
| kNeverDisambiguated, |
| // The drag was considered as a normal drag, and then the window was dropped |
| // back into overview, in the same grid or another one. |
| kDropIntoOverview, |
| // The drag resulted in snapping the window. |
| kSnap, |
| // The drag resulted in moving the window to another desk. |
| kDragToDesk, |
| // The drag resulted in closing the window. |
| kSuccessfulDragToClose, |
| // The drag was considered as drag-to-close, but did not result in closing |
| // the window. |
| kCanceledDragToClose, |
| }; |
| |
| OverviewWindowDragController(OverviewSession* overview_session, |
| OverviewItemBase* item, |
| bool is_touch_dragging, |
| OverviewItemBase* event_source_item); |
| |
| OverviewWindowDragController(const OverviewWindowDragController&) = delete; |
| OverviewWindowDragController& operator=(const OverviewWindowDragController&) = |
| delete; |
| |
| ~OverviewWindowDragController(); |
| |
| static base::AutoReset<bool> SkipNewDeskButtonScaleUpDurationForTesting(); |
| |
| OverviewItemBase* item() { return item_; } |
| |
| bool is_touch_dragging() const { return is_touch_dragging_; } |
| |
| void InitiateDrag(const gfx::PointF& location_in_screen); |
| void Drag(const gfx::PointF& location_in_screen); |
| DragResult CompleteDrag(const gfx::PointF& location_in_screen); |
| void StartNormalDragMode(const gfx::PointF& location_in_screen); |
| DragResult Fling(const gfx::PointF& location_in_screen, |
| float velocity_x, |
| float velocity_y); |
| void ActivateDraggedWindow(); |
| |
| // Called when a gesture event is reset or when the dragged window is being |
| // destroyed. |
| void ResetGesture(); |
| |
| // Resets |overview_session_| to nullptr. It's needed since we defer the |
| // deletion of OverviewWindowDragController in Overview destructor and |
| // we need to reset |overview_session_| to nullptr to avoid null pointer |
| // dereference. |
| void ResetOverviewSession(); |
| |
| DragBehavior current_drag_behavior_for_testing() const { |
| return current_drag_behavior_; |
| } |
| |
| base::OneShotTimer* new_desk_button_scale_up_timer_for_test() { |
| return &new_desk_button_scale_up_timer_; |
| } |
| |
| private: |
| enum NormalDragAction { |
| kToGrid = 0, |
| kToDesk = 1, |
| kToSnap = 2, |
| kNormalDragActionEnumSize = 3, |
| }; |
| enum DragToCloseAction { |
| kSwipeToCloseSuccessful = 0, |
| kSwipeToCloseCanceled = 1, |
| kFlingToClose = 2, |
| kDragToCloseActionEnumSize = 3, |
| }; |
| |
| void StartDragToCloseMode(); |
| |
| // Methods to continue and complete the drag when the drag mode is |
| // kDragToClose. |
| void ContinueDragToClose(const gfx::PointF& location_in_screen); |
| DragResult CompleteDragToClose(const gfx::PointF& location_in_screen); |
| |
| // Methods to continue and complete the drag when the drag mode is |
| // kNormalDrag. |
| void ContinueNormalDrag(const gfx::PointF& location_in_screen); |
| DragResult CompleteNormalDrag(const gfx::PointF& location_in_screen); |
| |
| // Updates visuals for the user while dragging items around. |
| void UpdateDragIndicatorsAndOverviewGrid( |
| const gfx::PointF& location_in_screen); |
| |
| aura::Window* GetRootWindowBeingDraggedIn() const; |
| |
| SnapPosition GetSnapPosition(const gfx::PointF& location_in_screen) const; |
| |
| // Snaps and activates the window. Uses the divider spawn animation (see |
| // |SplitViewController::SnapWindow|). Sets |item_| to null because the |
| // overview item is destroyed. |
| void SnapWindow(SplitViewController* split_view_controller, |
| SnapPosition snap_position); |
| |
| // Returns the item's overview grid, or the grid in which the item is being |
| // dragged if the multi display overview and split view feature is enabled. |
| OverviewGrid* GetCurrentGrid() const; |
| |
| // Records the histogram Ash.Overview.WindowDrag.Workflow. |
| void RecordNormalDrag(NormalDragAction action, |
| bool is_dragged_to_other_display) const; |
| void RecordDragToClose(DragToCloseAction action) const; |
| |
| // Creates `float_drag_helper_` if needed. The helper will temporarily stack |
| // the float container under the active desk container, so that dragging |
| // regular windows appear above overview items of floated windows. |
| void MaybeCreateFloatDragHelper(); |
| |
| // Scale up the new desk button on the desks bar from expanded state to active |
| // state to make the new desk button a drop target for the window being |
| // dragged. It's triggered by `new_desk_button_scale_up_timer_`. Refer to |
| // `new_desk_button_scale_up_timer_` for more information. |
| void MaybeScaleUpNewDeskButton(); |
| |
| raw_ptr<OverviewSession> overview_session_; |
| |
| // The drag target item in the overview mode. |
| raw_ptr<OverviewItemBase, DanglingUntriaged> item_ = nullptr; |
| |
| // The source item of the drag event. |
| raw_ptr<OverviewItemBase, DanglingUntriaged> event_source_item_ = nullptr; |
| |
| DragBehavior current_drag_behavior_ = DragBehavior::kNoDrag; |
| |
| // The location of the initial mouse/touch/gesture event in screen. |
| gfx::PointF initial_event_location_; |
| |
| // Stores the bounds of |item_| when a drag is started. Used to calculate the |
| // new bounds on a drag event. |
| gfx::PointF initial_centerpoint_; |
| |
| // The original size of the dragged item after we scale it up when we start |
| // dragging it. The item is restored to this size once it no longer intersects |
| // with the OverviewDeskBarView. |
| gfx::SizeF original_scaled_size_; |
| |
| // Track the per-overview-grid desks bar data used to perform the window |
| // sizing operations when it is moved towards or on the desks bar. |
| struct GridDesksBarData { |
| // The scaled-down size of the dragged item once the drag location is on the |
| // OverviewDeskBarView of the corresponding grid. We size the item down so |
| // that it fits inside the desks' preview view. |
| gfx::SizeF on_desks_bar_item_size; |
| |
| // Cached values related to dragging items while the desks bar is shown. |
| // |desks_bar_bounds| is the bounds of the desks bar in screen coordinates. |
| // |shrink_bounds| is a rectangle around the desks bar which the items |
| // starts shrinking when the event location is contained. The item will |
| // shrink until it is contained in |desks_bar_bounds|, at which it has |
| // reached its minimum size and will no longer shrink. |
| // |shrink_region_distance| is a vector contained the distance from the |
| // origin of |desks_bar_bounds| to the origin of |shrink_bounds|. It's |
| // used to determine the size of the dragged item when it's within |
| // |shrink_bounds|. |
| gfx::RectF desks_bar_bounds; |
| gfx::RectF shrink_bounds; |
| gfx::Vector2dF shrink_region_distance; |
| }; |
| base::flat_map<OverviewGrid*, GridDesksBarData> per_grid_desks_bar_data_; |
| |
| const size_t display_count_; |
| |
| // Indicates touch dragging, as opposed to mouse dragging. The drag-to-close |
| // mode is only allowed when |is_touch_dragging_| is true. |
| const bool is_touch_dragging_; |
| |
| // True if the `item_` can be snapped by dragging. |
| const bool is_eligible_for_drag_to_snap_; |
| |
| // True if the Virtual Desks bar is created and dragging to desks is enabled. |
| const bool virtual_desks_bar_enabled_; |
| |
| // The opacity of |item_| changes if we are in drag to close mode. Store the |
| // original opacity of |item_| and restore it to the item when we leave drag |
| // to close mode. |
| float original_opacity_ = 1.f; |
| |
| // Set to true once the bounds of |item_| change. |
| bool did_move_ = false; |
| |
| // Records the presentation time of window drag operation in overview mode. |
| std::unique_ptr<ui::PresentationTimeRecorder> presentation_time_recorder_; |
| |
| SnapPosition snap_position_ = SnapPosition::kNone; |
| |
| std::optional<OverviewController::ScopedOcclusionPauser> occlusion_pauser_; |
| |
| // A timer used to scale up the new desk button to make it a drop target for |
| // the window being dragged if the window is hovered on the button over a |
| // period of time. |
| base::OneShotTimer new_desk_button_scale_up_timer_; |
| }; |
| |
| } // namespace ash |
| |
| #endif // ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_ |