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
5#ifndef ASH_WM_WORKSPACE_WINDOW_RESIZER_H_
6#define ASH_WM_WORKSPACE_WINDOW_RESIZER_H_
7
8#include <vector>
9
10#include "ash/wm/window_resizer.h"
11#include "ash/wm/workspace/magnetism_matcher.h"
12#include "base/compiler_specific.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/scoped_ptr.h"
15#include "base/memory/weak_ptr.h"
16#include "ui/aura/window_tracker.h"
17
18namespace ash {
19class DockedWindowLayoutManager;
20class PhantomWindowController;
21class TwoStepEdgeCycler;
22class WindowSize;
23
24namespace wm {
25class WindowState;
26}
27
28// WindowResizer implementation for workspaces. This enforces that windows are
29// not allowed to vertically move or resize outside of the work area. As windows
30// are moved outside the work area they are shrunk. We remember the height of
31// the window before it was moved so that if the window is again moved up we
32// attempt to restore the old height.
33class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer {
34 public:
35  // When dragging an attached window this is the min size we'll make sure is
36  // visible. In the vertical direction we take the max of this and that from
37  // the delegate.
38  static const int kMinOnscreenSize;
39
40  // Min height we'll force on screen when dragging the caption.
41  // TODO: this should come from a property on the window.
42  static const int kMinOnscreenHeight;
43
44  // Snap region when dragging close to the edges. That is, as the window gets
45  // this close to an edge of the screen it snaps to the edge.
46  static const int kScreenEdgeInset;
47
48  // Distance in pixels that the cursor must move past an edge for a window
49  // to move or resize beyond that edge.
50  static const int kStickyDistancePixels;
51
52  virtual ~WorkspaceWindowResizer();
53
54  static WorkspaceWindowResizer* Create(
55      wm::WindowState* window_state,
56      const std::vector<aura::Window*>& attached_windows);
57
58  // WindowResizer:
59  virtual void Drag(const gfx::Point& location_in_parent,
60                    int event_flags) OVERRIDE;
61  virtual void CompleteDrag() OVERRIDE;
62  virtual void RevertDrag() OVERRIDE;
63
64 private:
65  WorkspaceWindowResizer(wm::WindowState* window_state,
66                         const std::vector<aura::Window*>& attached_windows);
67
68 private:
69  friend class WorkspaceWindowResizerTest;
70
71  // The edge to which the window should be snapped at the end of the drag.
72  enum SnapType {
73    SNAP_LEFT,
74    SNAP_RIGHT,
75    SNAP_NONE
76  };
77
78  // Lays out the attached windows. |bounds| is the bounds of the main window.
79  void LayoutAttachedWindows(gfx::Rect* bounds);
80
81  // Calculates the new sizes of the attached windows, given that the main
82  // window has been resized (along the primary axis) by |delta|.
83  // |available_size| is the maximum length of the space that the attached
84  // windows are allowed to occupy (ie: the distance between the right/bottom
85  // edge of the primary window and the right/bottom of the desktop area).
86  // Populates |sizes| with the desired sizes of the attached windows, and
87  // returns the number of pixels that couldn't be allocated to the attached
88  // windows (due to min/max size constraints).
89  // Note the return value can be positive or negative, a negative value
90  // indicating that that many pixels couldn't be removed from the attached
91  // windows.
92  int CalculateAttachedSizes(
93      int delta,
94      int available_size,
95      std::vector<int>* sizes) const;
96
97  // Divides |amount| evenly between |sizes|. If |amount| is negative it
98  // indicates how many pixels |sizes| should be shrunk by.
99  // Returns how many pixels failed to be allocated/removed from |sizes|.
100  int GrowFairly(int amount, std::vector<WindowSize>& sizes) const;
101
102  // Calculate the ratio of pixels that each WindowSize in |sizes| should
103  // receive when growing or shrinking.
104  void CalculateGrowthRatios(const std::vector<WindowSize*>& sizes,
105                             std::vector<float>* out_ratios) const;
106
107  // Adds a WindowSize to |sizes| for each attached window.
108  void CreateBucketsForAttached(std::vector<WindowSize>* sizes) const;
109
110  // If possible snaps the window to a neary window. Updates |bounds| if there
111  // was a close enough window.
112  void MagneticallySnapToOtherWindows(gfx::Rect* bounds);
113
114  // If possible snaps the resize to a neary window. Updates |bounds| if there
115  // was a close enough window.
116  void MagneticallySnapResizeToOtherWindows(gfx::Rect* bounds);
117
118  // Finds the neareset window to magentically snap to. Updates
119  // |magnetism_window_| and |magnetism_edge_| appropriately. |edges| is a
120  // bitmask of the MagnetismEdges to match again. Returns true if a match is
121  // found.
122  bool UpdateMagnetismWindow(const gfx::Rect& bounds, uint32 edges);
123
124  // Adjusts the bounds of the window: magnetically snapping, ensuring the
125  // window has enough on screen... |snap_size| is the distance from an edge of
126  // the work area before the window is snapped. A value of 0 results in no
127  // snapping.
128  void AdjustBoundsForMainWindow(int snap_size, gfx::Rect* bounds);
129
130  // Stick the window bounds to the work area during a move.
131  bool StickToWorkAreaOnMove(const gfx::Rect& work_area,
132                             int sticky_size,
133                             gfx::Rect* bounds) const;
134
135  // Stick the window bounds to the work area during a resize.
136  void StickToWorkAreaOnResize(const gfx::Rect& work_area,
137                               int sticky_size,
138                               gfx::Rect* bounds) const;
139
140  // Returns a coordinate along the primary axis. Used to share code for
141  // left/right multi window resize and top/bottom resize.
142  int PrimaryAxisSize(const gfx::Size& size) const;
143  int PrimaryAxisCoordinate(int x, int y) const;
144
145  // Updates the bounds of the phantom window for window snapping.
146  void UpdateSnapPhantomWindow(const gfx::Point& location,
147                               const gfx::Rect& bounds);
148
149  // Restacks the windows z-order position so that one of the windows is at the
150  // top of the z-order, and the rest directly underneath it.
151  void RestackWindows();
152
153  // Returns the edge to which the window should be snapped to if the user does
154  // no more dragging. SNAP_NONE is returned if the window should not be
155  // snapped.
156  SnapType GetSnapType(const gfx::Point& location) const;
157
158  // Returns true if |bounds_in_parent| are valid bounds for snapped state type
159  // |snapped_type|.
160  bool AreBoundsValidSnappedBounds(wm::WindowStateType snapped_type,
161                                   const gfx::Rect& bounds_in_parent) const;
162
163  // Docks or undocks the dragged window.
164  void SetDraggedWindowDocked(bool should_dock);
165
166  wm::WindowState* window_state() { return window_state_; }
167
168  const std::vector<aura::Window*> attached_windows_;
169
170  // Returns the currently used instance for test.
171  static WorkspaceWindowResizer* GetInstanceForTest();
172
173  bool did_lock_cursor_;
174
175  // Set to true once Drag() is invoked and the bounds of the window change.
176  bool did_move_or_resize_;
177
178  // True if the window initially had |bounds_changed_by_user_| set in state.
179  bool initial_bounds_changed_by_user_;
180
181  // The initial size of each of the windows in |attached_windows_| along the
182  // primary axis.
183  std::vector<int> initial_size_;
184
185  // Sum of the minimum sizes of the attached windows.
186  int total_min_;
187
188  // Sum of the sizes in |initial_size_|.
189  int total_initial_size_;
190
191  // Gives a previews of where the the window will end up. Only used if there
192  // is a grid and the caption is being dragged.
193  scoped_ptr<PhantomWindowController> snap_phantom_window_controller_;
194
195  // Used to determine whether the window should be snapped or docked when
196  // the user drags a window to the edge of the screen.
197  scoped_ptr<TwoStepEdgeCycler> edge_cycler_;
198
199  // The edge to which the window should be snapped to at the end of the drag.
200  SnapType snap_type_;
201
202  // Number of mouse moves since the last bounds change. Only used for phantom
203  // placement to track when the mouse is moved while pushed against the edge of
204  // the screen.
205  int num_mouse_moves_since_bounds_change_;
206
207  // The mouse location passed to Drag().
208  gfx::Point last_mouse_location_;
209
210  // Window the drag has magnetically attached to.
211  aura::Window* magnetism_window_;
212
213  // Used to verify |magnetism_window_| is still valid.
214  aura::WindowTracker window_tracker_;
215
216  // If |magnetism_window_| is non-NULL this indicates how the two windows
217  // should attach.
218  MatchedEdge magnetism_edge_;
219
220  // Dock container window layout manager.
221  DockedWindowLayoutManager* dock_layout_;
222
223  // Used to determine if this has been deleted during a drag such as when a tab
224  // gets dragged into another browser window.
225  base::WeakPtrFactory<WorkspaceWindowResizer> weak_ptr_factory_;
226
227  DISALLOW_COPY_AND_ASSIGN(WorkspaceWindowResizer);
228};
229
230}  // namespace ash
231
232#endif  // ASH_WM_WORKSPACE_WINDOW_RESIZER_H_
233