magnetism_matcher.h 6.2 KB

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