| 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 |