- add sources.
[platform/framework/web/crosswalk.git] / src / ash / wm / workspace / magnetism_matcher.h
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_MAGNETISM_MATCHER_H_
6 #define ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_
7
8 #include <utility>
9 #include <vector>
10
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"
16
17 namespace ash {
18 namespace internal {
19
20 enum MagnetismEdge {
21   MAGNETISM_EDGE_TOP    = 1 << 0,
22   MAGNETISM_EDGE_LEFT   = 1 << 1,
23   MAGNETISM_EDGE_BOTTOM = 1 << 2,
24   MAGNETISM_EDGE_RIGHT  = 1 << 3,
25 };
26
27 const uint32 kAllMagnetismEdges =
28     MAGNETISM_EDGE_TOP | MAGNETISM_EDGE_LEFT | MAGNETISM_EDGE_BOTTOM |
29     MAGNETISM_EDGE_RIGHT;
30
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
33 // care of all edges.
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 {
37  public:
38   MagnetismEdgeMatcher(const gfx::Rect& bounds, MagnetismEdge edge);
39   ~MagnetismEdgeMatcher();
40
41   MagnetismEdge edge() const { return edge_; }
42   const gfx::Rect& bounds() const { return bounds_; }
43
44   // Returns true if the edge is completely obscured. If true ShouldAttach()
45   // will return false.
46   bool is_edge_obscured() const { return ranges_.empty(); }
47
48   // Returns true if should attach to the specified bounds.
49   bool ShouldAttach(const gfx::Rect& bounds);
50
51  private:
52   typedef std::pair<int,int> Range;
53   typedef std::vector<Range> Ranges;
54
55   // Removes |range| from |ranges_|.
56   void UpdateRanges(const Range& range);
57
58   static int GetPrimaryCoordinate(const gfx::Rect& bounds, MagnetismEdge edge) {
59     switch (edge) {
60       case MAGNETISM_EDGE_TOP:
61         return bounds.y();
62       case MAGNETISM_EDGE_LEFT:
63         return bounds.x();
64       case MAGNETISM_EDGE_BOTTOM:
65         return bounds.bottom();
66       case MAGNETISM_EDGE_RIGHT:
67         return bounds.right();
68     }
69     NOTREACHED();
70     return 0;
71   }
72
73   static MagnetismEdge FlipEdge(MagnetismEdge edge) {
74     switch (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;
83     }
84     NOTREACHED();
85     return MAGNETISM_EDGE_LEFT;
86   }
87
88   Range GetPrimaryRange(const gfx::Rect& bounds) const {
89     switch (edge_) {
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());
96     }
97     NOTREACHED();
98     return Range();
99   }
100
101   Range GetSecondaryRange(const gfx::Rect& bounds) const {
102     switch (edge_) {
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());
109     }
110     NOTREACHED();
111     return Range();
112   }
113
114   static bool RangesIntersect(const Range& r1, const Range& r2) {
115     return r2.first < r1.second && r2.second > r1.first;
116   }
117
118   // The bounds of window.
119   const gfx::Rect bounds_;
120
121   // The edge this matcher checks.
122   const MagnetismEdge edge_;
123
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.
127   Ranges ranges_;
128
129   DISALLOW_COPY_AND_ASSIGN(MagnetismEdgeMatcher);
130 };
131
132 enum SecondaryMagnetismEdge {
133   SECONDARY_MAGNETISM_EDGE_LEADING,
134   SECONDARY_MAGNETISM_EDGE_TRAILING,
135   SECONDARY_MAGNETISM_EDGE_NONE,
136 };
137
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.
146 struct MatchedEdge {
147   MagnetismEdge primary_edge;
148   SecondaryMagnetismEdge secondary_edge;
149 };
150
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 {
159  public:
160   static const int kMagneticDistance;
161
162   // |edges| is a bitmask of MagnetismEdges to match against.
163   MagnetismMatcher(const gfx::Rect& bounds, uint32 edges);
164   ~MagnetismMatcher();
165
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);
170
171   // Returns true if no other matches are possible.
172   bool AreEdgesObscured() const;
173
174  private:
175   // Sets |secondary_edge| based on whether the secondary edges should snap.
176   void AttachToSecondaryEdge(const gfx::Rect& bounds,
177                              MagnetismEdge edge,
178                              SecondaryMagnetismEdge* secondary_edge) const;
179
180   // The edges to match against.
181   const int32 edges_;
182
183   ScopedVector<MagnetismEdgeMatcher> matchers_;
184
185   DISALLOW_COPY_AND_ASSIGN(MagnetismMatcher);
186 };
187
188 }  // namespace internal
189 }  // namespace ash
190
191 #endif  // ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_