1 // Copyright 2017 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 5 #ifndef ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_ 6 #define ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_ 7 8 #include <memory> 9 10 #include "ash/ash_export.h" 11 #include "ash/wm/splitview/split_view_controller.h" 12 #include "base/containers/flat_map.h" 13 #include "base/macros.h" 14 #include "ui/gfx/geometry/point_f.h" 15 16 namespace ash { 17 18 class OverviewGrid; 19 class OverviewItem; 20 class OverviewSession; 21 class PresentationTimeRecorder; 22 23 // These values are persisted to logs. Entries should not be renumbered and 24 // numeric values should never be reused. 25 // Workflows of dragging windows from overview (not from the top or shelf). 26 enum class OverviewDragAction { 27 kToGridSameDisplayClamshellMouse = 0, 28 kToGridSameDisplayClamshellTouch = 1, 29 kToDeskSameDisplayClamshellMouse = 2, 30 kToDeskSameDisplayClamshellTouch = 3, 31 kToSnapSameDisplayClamshellMouse = 4, 32 kToSnapSameDisplayClamshellTouch = 5, 33 kSwipeToCloseSuccessfulClamshellTouch = 6, 34 kSwipeToCloseCanceledClamshellTouch = 7, 35 kFlingToCloseClamshellTouch = 8, 36 kToGridOtherDisplayClamshellMouse = 9, 37 kToDeskOtherDisplayClamshellMouse = 10, 38 kToSnapOtherDisplayClamshellMouse = 11, 39 kToGridSameDisplayTabletTouch = 12, 40 kToDeskSameDisplayTabletTouch = 13, 41 kToSnapSameDisplayTabletTouch = 14, 42 kSwipeToCloseSuccessfulTabletTouch = 15, 43 kSwipeToCloseCanceledTabletTouch = 16, 44 kFlingToCloseTabletTouch = 17, 45 kMaxValue = kFlingToCloseTabletTouch, 46 }; 47 48 // The drag controller for an overview window item in overview mode. It updates 49 // the position of the corresponding window item using transform while dragging. 50 // It also updates the split view drag indicators, which handles showing 51 // indicators where to drag, and preview areas showing the bounds of the 52 // window about to be snapped. 53 class ASH_EXPORT OverviewWindowDragController { 54 public: 55 enum class DragBehavior { 56 // No drag has started. 57 kNoDrag, 58 // Drag has started, but it is undecided whether we want to drag to snap or 59 // drag to close yet. 60 kUndefined, 61 // On drag complete, the window will be snapped, if it meets requirements, 62 // or moved to another desk if dropped on one of the desks' mini_views. This 63 // mode is triggered if the the window is initially dragged horizontally 64 // more than vertically (more in X than Y), or if the window item in the 65 // overview grid was gesture long pressed. 66 kNormalDrag, 67 // On drag complete, the window will be closed, if it meets requirements. 68 // This mode is triggered when the window is initially dragged vertically 69 // more than horizontally (more in Y than in X). 70 kDragToClose, 71 }; 72 73 enum class DragResult { 74 // The drag ended without ever being disambiguated between a normal drag and 75 // drag-to-close. 76 kNeverDisambiguated, 77 // The drag was considered as a normal drag, and then the window was dropped 78 // back into overview, in the same grid or another one. 79 kDropIntoOverview, 80 // The drag resulted in snapping the window. 81 kSnap, 82 // The drag resulted in moving the window to another desk. 83 kDragToDesk, 84 // The drag resulted in closing the window. 85 kSuccessfulDragToClose, 86 // The drag was considered as drag-to-close, but did not result in closing 87 // the window. 88 kCanceledDragToClose, 89 }; 90 91 OverviewWindowDragController(OverviewSession* overview_session, 92 OverviewItem* item, 93 bool is_touch_dragging); 94 ~OverviewWindowDragController(); 95 96 void InitiateDrag(const gfx::PointF& location_in_screen); 97 void Drag(const gfx::PointF& location_in_screen); 98 DragResult CompleteDrag(const gfx::PointF& location_in_screen); 99 void StartNormalDragMode(const gfx::PointF& location_in_screen); 100 DragResult Fling(const gfx::PointF& location_in_screen, 101 float velocity_x, 102 float velocity_y); 103 void ActivateDraggedWindow(); 104 void ResetGesture(); 105 106 // Resets |overview_session_| to nullptr. It's needed since we defer the 107 // deletion of OverviewWindowDragController in Overview destructor and 108 // we need to reset |overview_session_| to nullptr to avoid null pointer 109 // dereference. 110 void ResetOverviewSession(); 111 item()112 OverviewItem* item() { return item_; } 113 current_drag_behavior()114 DragBehavior current_drag_behavior() { return current_drag_behavior_; } 115 is_touch_dragging()116 bool is_touch_dragging() const { return is_touch_dragging_; } 117 118 private: 119 enum NormalDragAction { 120 kToGrid = 0, 121 kToDesk = 1, 122 kToSnap = 2, 123 kNormalDragActionEnumSize = 3, 124 }; 125 enum DragToCloseAction { 126 kSwipeToCloseSuccessful = 0, 127 kSwipeToCloseCanceled = 1, 128 kFlingToClose = 2, 129 kDragToCloseActionEnumSize = 3, 130 }; 131 132 void StartDragToCloseMode(); 133 134 // Methods to continue and complete the drag when the drag mode is 135 // kDragToClose. 136 void ContinueDragToClose(const gfx::PointF& location_in_screen); 137 DragResult CompleteDragToClose(const gfx::PointF& location_in_screen); 138 139 // Methods to continue and complete the drag when the drag mode is 140 // kNormalDrag. 141 void ContinueNormalDrag(const gfx::PointF& location_in_screen); 142 DragResult CompleteNormalDrag(const gfx::PointF& location_in_screen); 143 144 // Updates visuals for the user while dragging items around. 145 void UpdateDragIndicatorsAndOverviewGrid( 146 const gfx::PointF& location_in_screen); 147 148 aura::Window* GetRootWindowBeingDraggedIn() const; 149 150 SplitViewController::SnapPosition GetSnapPosition( 151 const gfx::PointF& location_in_screen) const; 152 153 // Snaps and activates the window. Uses the divider spawn animation (see 154 // |SplitViewController::SnapWindow|). Sets |item_| to null because the 155 // overview item is destroyed. 156 void SnapWindow(SplitViewController* split_view_controller, 157 SplitViewController::SnapPosition snap_position); 158 159 // Returns the item's overview grid, or the grid in which the item is being 160 // dragged if the multi display overview and split view feature is enabled. 161 OverviewGrid* GetCurrentGrid() const; 162 163 // Records the histogram Ash.Overview.WindowDrag.Workflow. 164 void RecordNormalDrag(NormalDragAction action, 165 bool is_dragged_to_other_display) const; 166 void RecordDragToClose(DragToCloseAction action) const; 167 168 OverviewSession* overview_session_; 169 170 // The drag target window in the overview mode. 171 OverviewItem* item_ = nullptr; 172 173 DragBehavior current_drag_behavior_ = DragBehavior::kNoDrag; 174 175 // The location of the initial mouse/touch/gesture event in screen. 176 gfx::PointF initial_event_location_; 177 178 // Stores the bounds of |item_| when a drag is started. Used to calculate the 179 // new bounds on a drag event. 180 gfx::PointF initial_centerpoint_; 181 182 // The original size of the dragged item after we scale it up when we start 183 // dragging it. The item is restored to this size once it no longer intersects 184 // with the DesksBarView. 185 gfx::SizeF original_scaled_size_; 186 187 // Track the per-overview-grid desks bar data used to perform the window 188 // sizing operations when it is moved towards or on the desks bar. 189 struct GridDesksBarData { 190 // The scaled-down size of the dragged item once the drag location is on the 191 // DesksBarView of the corresponding grid. We size the item down so that it 192 // fits inside the desks' preview view. 193 gfx::SizeF on_desks_bar_item_size; 194 195 // Cached values related to dragging items while the desks bar is shown. 196 // |desks_bar_bounds| is the bounds of the desks bar in screen coordinates. 197 // |shrink_bounds| is a rectangle around the desks bar which the items 198 // starts shrinking when the event location is contained. The item will 199 // shrink until it is contained in |desks_bar_bounds|, at which it has 200 // reached its minimum size and will no longer shrink. 201 // |shrink_region_distance| is a vector contained the distance from the 202 // origin of |desks_bar_bounds| to the origin of |shrink_bounds|. It's 203 // used to determine the size of the dragged item when it's within 204 // |shrink_bounds|. 205 gfx::RectF desks_bar_bounds; 206 gfx::RectF shrink_bounds; 207 gfx::Vector2dF shrink_region_distance; 208 }; 209 base::flat_map<OverviewGrid*, GridDesksBarData> per_grid_desks_bar_data_; 210 211 const size_t display_count_; 212 213 // Indicates touch dragging, as opposed to mouse dragging. The drag-to-close 214 // mode is only allowed when |is_touch_dragging_| is true. 215 const bool is_touch_dragging_; 216 217 // True if SplitView is enabled. 218 const bool should_allow_split_view_; 219 220 // True if the Virtual Desks bar is created and dragging to desks is enabled. 221 const bool virtual_desks_bar_enabled_; 222 223 const bool are_multi_display_overview_and_splitview_enabled_; 224 225 // The opacity of |item_| changes if we are in drag to close mode. Store the 226 // original opacity of |item_| and restore it to the item when we leave drag 227 // to close mode. 228 float original_opacity_ = 1.f; 229 230 // Set to true once the bounds of |item_| change. 231 bool did_move_ = false; 232 233 // Records the presentation time of window drag operation in overview mode. 234 std::unique_ptr<PresentationTimeRecorder> presentation_time_recorder_; 235 236 SplitViewController::SnapPosition snap_position_ = SplitViewController::NONE; 237 238 DISALLOW_COPY_AND_ASSIGN(OverviewWindowDragController); 239 }; 240 241 } // namespace ash 242 243 #endif // ASH_WM_OVERVIEW_OVERVIEW_WINDOW_DRAG_CONTROLLER_H_ 244