OLD | NEW |
| (Empty) |
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_COMMON_WM_WORKSPACE_MAGNETISM_MATCHER_H_ | |
6 #define ASH_COMMON_WM_WORKSPACE_MAGNETISM_MATCHER_H_ | |
7 | |
8 #include <stdint.h> | |
9 | |
10 #include <memory> | |
11 #include <utility> | |
12 #include <vector> | |
13 | |
14 #include "ash/ash_export.h" | |
15 #include "base/compiler_specific.h" | |
16 #include "base/logging.h" | |
17 #include "base/macros.h" | |
18 #include "ui/gfx/geometry/rect.h" | |
19 | |
20 namespace ash { | |
21 | |
22 enum MagnetismEdge { | |
23 MAGNETISM_EDGE_TOP = 1 << 0, | |
24 MAGNETISM_EDGE_LEFT = 1 << 1, | |
25 MAGNETISM_EDGE_BOTTOM = 1 << 2, | |
26 MAGNETISM_EDGE_RIGHT = 1 << 3, | |
27 }; | |
28 | |
29 const uint32_t kAllMagnetismEdges = MAGNETISM_EDGE_TOP | MAGNETISM_EDGE_LEFT | | |
30 MAGNETISM_EDGE_BOTTOM | | |
31 MAGNETISM_EDGE_RIGHT; | |
32 | |
33 // MagnetismEdgeMatcher is used for matching a particular edge of a window. You | |
34 // shouldn't need to use this directly, instead use MagnetismMatcher which takes | |
35 // care of all edges. | |
36 // MagnetismEdgeMatcher maintains a range of the visible portions of the | |
37 // edge. As ShouldAttach() is invoked the visible range is updated. | |
38 class MagnetismEdgeMatcher { | |
39 public: | |
40 MagnetismEdgeMatcher(const gfx::Rect& bounds, MagnetismEdge edge); | |
41 ~MagnetismEdgeMatcher(); | |
42 | |
43 MagnetismEdge edge() const { return edge_; } | |
44 const gfx::Rect& bounds() const { return bounds_; } | |
45 | |
46 // Returns true if the edge is completely obscured. If true ShouldAttach() | |
47 // will return false. | |
48 bool is_edge_obscured() const { return ranges_.empty(); } | |
49 | |
50 // Returns true if should attach to the specified bounds. | |
51 bool ShouldAttach(const gfx::Rect& bounds); | |
52 | |
53 private: | |
54 typedef std::pair<int, int> Range; | |
55 typedef std::vector<Range> Ranges; | |
56 | |
57 // Removes |range| from |ranges_|. | |
58 void UpdateRanges(const Range& range); | |
59 | |
60 static int GetPrimaryCoordinate(const gfx::Rect& bounds, MagnetismEdge edge) { | |
61 switch (edge) { | |
62 case MAGNETISM_EDGE_TOP: | |
63 return bounds.y(); | |
64 case MAGNETISM_EDGE_LEFT: | |
65 return bounds.x(); | |
66 case MAGNETISM_EDGE_BOTTOM: | |
67 return bounds.bottom(); | |
68 case MAGNETISM_EDGE_RIGHT: | |
69 return bounds.right(); | |
70 } | |
71 NOTREACHED(); | |
72 return 0; | |
73 } | |
74 | |
75 static MagnetismEdge FlipEdge(MagnetismEdge edge) { | |
76 switch (edge) { | |
77 case MAGNETISM_EDGE_TOP: | |
78 return MAGNETISM_EDGE_BOTTOM; | |
79 case MAGNETISM_EDGE_BOTTOM: | |
80 return MAGNETISM_EDGE_TOP; | |
81 case MAGNETISM_EDGE_LEFT: | |
82 return MAGNETISM_EDGE_RIGHT; | |
83 case MAGNETISM_EDGE_RIGHT: | |
84 return MAGNETISM_EDGE_LEFT; | |
85 } | |
86 NOTREACHED(); | |
87 return MAGNETISM_EDGE_LEFT; | |
88 } | |
89 | |
90 Range GetPrimaryRange(const gfx::Rect& bounds) const { | |
91 switch (edge_) { | |
92 case MAGNETISM_EDGE_TOP: | |
93 case MAGNETISM_EDGE_BOTTOM: | |
94 return Range(bounds.y(), bounds.bottom()); | |
95 case MAGNETISM_EDGE_LEFT: | |
96 case MAGNETISM_EDGE_RIGHT: | |
97 return Range(bounds.x(), bounds.right()); | |
98 } | |
99 NOTREACHED(); | |
100 return Range(); | |
101 } | |
102 | |
103 Range GetSecondaryRange(const gfx::Rect& bounds) const { | |
104 switch (edge_) { | |
105 case MAGNETISM_EDGE_TOP: | |
106 case MAGNETISM_EDGE_BOTTOM: | |
107 return Range(bounds.x(), bounds.right()); | |
108 case MAGNETISM_EDGE_LEFT: | |
109 case MAGNETISM_EDGE_RIGHT: | |
110 return Range(bounds.y(), bounds.bottom()); | |
111 } | |
112 NOTREACHED(); | |
113 return Range(); | |
114 } | |
115 | |
116 static bool RangesIntersect(const Range& r1, const Range& r2) { | |
117 return r2.first < r1.second && r2.second > r1.first; | |
118 } | |
119 | |
120 // The bounds of window. | |
121 const gfx::Rect bounds_; | |
122 | |
123 // The edge this matcher checks. | |
124 const MagnetismEdge edge_; | |
125 | |
126 // Visible ranges of the edge. Initialized with GetSecondaryRange() and | |
127 // updated as ShouldAttach() is invoked. When empty the edge is completely | |
128 // obscured by other bounds. | |
129 Ranges ranges_; | |
130 | |
131 DISALLOW_COPY_AND_ASSIGN(MagnetismEdgeMatcher); | |
132 }; | |
133 | |
134 enum SecondaryMagnetismEdge { | |
135 SECONDARY_MAGNETISM_EDGE_LEADING, | |
136 SECONDARY_MAGNETISM_EDGE_TRAILING, | |
137 SECONDARY_MAGNETISM_EDGE_NONE, | |
138 }; | |
139 | |
140 // Used to identify a matched edge. |primary_edge| is relative to the source and | |
141 // indicates the edge the two are to share. For example, if |primary_edge| is | |
142 // MAGNETISM_EDGE_RIGHT then the right edge of the source should snap to to the | |
143 // left edge of the target. |secondary_edge| indicates one of the edges along | |
144 // the opposite axis should should also be aligned. For example, if | |
145 // |primary_edge| is MAGNETISM_EDGE_RIGHT and |secondary_edge| is | |
146 // SECONDARY_MAGNETISM_EDGE_LEADING then the source should snap to the left top | |
147 // corner of the target. | |
148 struct MatchedEdge { | |
149 MagnetismEdge primary_edge; | |
150 SecondaryMagnetismEdge secondary_edge; | |
151 }; | |
152 | |
153 // MagnetismMatcher is used to test if a window should snap to another window. | |
154 // To use MagnetismMatcher do the following: | |
155 // . Create it with the bounds of the window being dragged. | |
156 // . Iterate over the child windows checking if the window being dragged should | |
157 // attach to it using ShouldAttach(). | |
158 // . Use AreEdgesObscured() to test if no other windows can match (because all | |
159 // edges are completely obscured). | |
160 class ASH_EXPORT MagnetismMatcher { | |
161 public: | |
162 static const int kMagneticDistance; | |
163 | |
164 // |edges| is a bitmask of MagnetismEdges to match against. | |
165 MagnetismMatcher(const gfx::Rect& bounds, uint32_t edges); | |
166 ~MagnetismMatcher(); | |
167 | |
168 // Returns true if |bounds| is close enough to the initial bounds that the two | |
169 // should be attached. If true is returned |edge| is set to indicates how the | |
170 // two should snap together. See description of MatchedEdge for details. | |
171 bool ShouldAttach(const gfx::Rect& bounds, MatchedEdge* edge); | |
172 | |
173 // Returns true if no other matches are possible. | |
174 bool AreEdgesObscured() const; | |
175 | |
176 private: | |
177 // Sets |secondary_edge| based on whether the secondary edges should snap. | |
178 void AttachToSecondaryEdge(const gfx::Rect& bounds, | |
179 MagnetismEdge edge, | |
180 SecondaryMagnetismEdge* secondary_edge) const; | |
181 | |
182 // The edges to match against. | |
183 const int32_t edges_; | |
184 | |
185 std::vector<std::unique_ptr<MagnetismEdgeMatcher>> matchers_; | |
186 | |
187 DISALLOW_COPY_AND_ASSIGN(MagnetismMatcher); | |
188 }; | |
189 | |
190 } // namespace ash | |
191 | |
192 #endif // ASH_COMMON_WM_WORKSPACE_MAGNETISM_MATCHER_H_ | |
OLD | NEW |