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.
5 #ifndef ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_
6 #define ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_
11 #include "ash/ash_export.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_vector.h"
15 #include "ui/gfx/rect.h"
21 MAGNETISM_EDGE_TOP
= 1 << 0,
22 MAGNETISM_EDGE_LEFT
= 1 << 1,
23 MAGNETISM_EDGE_BOTTOM
= 1 << 2,
24 MAGNETISM_EDGE_RIGHT
= 1 << 3,
27 const uint32 kAllMagnetismEdges
=
28 MAGNETISM_EDGE_TOP
| MAGNETISM_EDGE_LEFT
| MAGNETISM_EDGE_BOTTOM
|
31 // MagnetismEdgeMatcher is used for matching a particular edge of a window. You
32 // shouldn't need to use this directly, instead use MagnetismMatcher which takes
34 // MagnetismEdgeMatcher maintains a range of the visible portions of the
35 // edge. As ShouldAttach() is invoked the visible range is updated.
36 class MagnetismEdgeMatcher
{
38 MagnetismEdgeMatcher(const gfx::Rect
& bounds
, MagnetismEdge edge
);
39 ~MagnetismEdgeMatcher();
41 MagnetismEdge
edge() const { return edge_
; }
42 const gfx::Rect
& bounds() const { return bounds_
; }
44 // Returns true if the edge is completely obscured. If true ShouldAttach()
46 bool is_edge_obscured() const { return ranges_
.empty(); }
48 // Returns true if should attach to the specified bounds.
49 bool ShouldAttach(const gfx::Rect
& bounds
);
52 typedef std::pair
<int,int> Range
;
53 typedef std::vector
<Range
> Ranges
;
55 // Removes |range| from |ranges_|.
56 void UpdateRanges(const Range
& range
);
58 static int GetPrimaryCoordinate(const gfx::Rect
& bounds
, MagnetismEdge edge
) {
60 case MAGNETISM_EDGE_TOP
:
62 case MAGNETISM_EDGE_LEFT
:
64 case MAGNETISM_EDGE_BOTTOM
:
65 return bounds
.bottom();
66 case MAGNETISM_EDGE_RIGHT
:
67 return bounds
.right();
73 static MagnetismEdge
FlipEdge(MagnetismEdge edge
) {
75 case MAGNETISM_EDGE_TOP
:
76 return MAGNETISM_EDGE_BOTTOM
;
77 case MAGNETISM_EDGE_BOTTOM
:
78 return MAGNETISM_EDGE_TOP
;
79 case MAGNETISM_EDGE_LEFT
:
80 return MAGNETISM_EDGE_RIGHT
;
81 case MAGNETISM_EDGE_RIGHT
:
82 return MAGNETISM_EDGE_LEFT
;
85 return MAGNETISM_EDGE_LEFT
;
88 Range
GetPrimaryRange(const gfx::Rect
& bounds
) const {
90 case MAGNETISM_EDGE_TOP
:
91 case MAGNETISM_EDGE_BOTTOM
:
92 return Range(bounds
.y(), bounds
.bottom());
93 case MAGNETISM_EDGE_LEFT
:
94 case MAGNETISM_EDGE_RIGHT
:
95 return Range(bounds
.x(), bounds
.right());
101 Range
GetSecondaryRange(const gfx::Rect
& bounds
) const {
103 case MAGNETISM_EDGE_TOP
:
104 case MAGNETISM_EDGE_BOTTOM
:
105 return Range(bounds
.x(), bounds
.right());
106 case MAGNETISM_EDGE_LEFT
:
107 case MAGNETISM_EDGE_RIGHT
:
108 return Range(bounds
.y(), bounds
.bottom());
114 static bool RangesIntersect(const Range
& r1
, const Range
& r2
) {
115 return r2
.first
< r1
.second
&& r2
.second
> r1
.first
;
118 // The bounds of window.
119 const gfx::Rect bounds_
;
121 // The edge this matcher checks.
122 const MagnetismEdge edge_
;
124 // Visible ranges of the edge. Initialized with GetSecondaryRange() and
125 // updated as ShouldAttach() is invoked. When empty the edge is completely
126 // obscured by other bounds.
129 DISALLOW_COPY_AND_ASSIGN(MagnetismEdgeMatcher
);
132 enum SecondaryMagnetismEdge
{
133 SECONDARY_MAGNETISM_EDGE_LEADING
,
134 SECONDARY_MAGNETISM_EDGE_TRAILING
,
135 SECONDARY_MAGNETISM_EDGE_NONE
,
138 // Used to identify a matched edge. |primary_edge| is relative to the source and
139 // indicates the edge the two are to share. For example, if |primary_edge| is
140 // MAGNETISM_EDGE_RIGHT then the right edge of the source should snap to to the
141 // left edge of the target. |secondary_edge| indicates one of the edges along
142 // the opposite axis should should also be aligned. For example, if
143 // |primary_edge| is MAGNETISM_EDGE_RIGHT and |secondary_edge| is
144 // SECONDARY_MAGNETISM_EDGE_LEADING then the source should snap to the left top
145 // corner of the target.
147 MagnetismEdge primary_edge
;
148 SecondaryMagnetismEdge secondary_edge
;
151 // MagnetismMatcher is used to test if a window should snap to another window.
152 // To use MagnetismMatcher do the following:
153 // . Create it with the bounds of the window being dragged.
154 // . Iterate over the child windows checking if the window being dragged should
155 // attach to it using ShouldAttach().
156 // . Use AreEdgesObscured() to test if no other windows can match (because all
157 // edges are completely obscured).
158 class ASH_EXPORT MagnetismMatcher
{
160 static const int kMagneticDistance
;
162 // |edges| is a bitmask of MagnetismEdges to match against.
163 MagnetismMatcher(const gfx::Rect
& bounds
, uint32 edges
);
166 // Returns true if |bounds| is close enough to the initial bounds that the two
167 // should be attached. If true is returned |edge| is set to indicates how the
168 // two should snap together. See description of MatchedEdge for details.
169 bool ShouldAttach(const gfx::Rect
& bounds
, MatchedEdge
* edge
);
171 // Returns true if no other matches are possible.
172 bool AreEdgesObscured() const;
175 // Sets |secondary_edge| based on whether the secondary edges should snap.
176 void AttachToSecondaryEdge(const gfx::Rect
& bounds
,
178 SecondaryMagnetismEdge
* secondary_edge
) const;
180 // The edges to match against.
183 ScopedVector
<MagnetismEdgeMatcher
> matchers_
;
185 DISALLOW_COPY_AND_ASSIGN(MagnetismMatcher
);
188 } // namespace internal
191 #endif // ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_