15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility> 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ash/ash_export.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_vector.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/rect.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace ash { 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum MagnetismEdge { 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGNETISM_EDGE_TOP = 1 << 0, 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGNETISM_EDGE_LEFT = 1 << 1, 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGNETISM_EDGE_BOTTOM = 1 << 2, 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGNETISM_EDGE_RIGHT = 1 << 3, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const uint32 kAllMagnetismEdges = 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGNETISM_EDGE_TOP | MAGNETISM_EDGE_LEFT | MAGNETISM_EDGE_BOTTOM | 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MAGNETISM_EDGE_RIGHT; 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MagnetismEdgeMatcher is used for matching a particular edge of a window. You 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shouldn't need to use this directly, instead use MagnetismMatcher which takes 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// care of all edges. 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MagnetismEdgeMatcher maintains a range of the visible portions of the 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// edge. As ShouldAttach() is invoked the visible range is updated. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MagnetismEdgeMatcher { 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MagnetismEdgeMatcher(const gfx::Rect& bounds, MagnetismEdge edge); 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MagnetismEdgeMatcher(); 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MagnetismEdge edge() const { return edge_; } 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect& bounds() const { return bounds_; } 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if the edge is completely obscured. If true ShouldAttach() 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // will return false. 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_edge_obscured() const { return ranges_.empty(); } 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if should attach to the specified bounds. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ShouldAttach(const gfx::Rect& bounds); 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::pair<int,int> Range; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef std::vector<Range> Ranges; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Removes |range| from |ranges_|. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void UpdateRanges(const Range& range); 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static int GetPrimaryCoordinate(const gfx::Rect& bounds, MagnetismEdge edge) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (edge) { 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_TOP: 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bounds.y(); 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_LEFT: 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bounds.x(); 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_BOTTOM: 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bounds.bottom(); 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_RIGHT: 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return bounds.right(); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static MagnetismEdge FlipEdge(MagnetismEdge edge) { 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (edge) { 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_TOP: 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MAGNETISM_EDGE_BOTTOM; 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_BOTTOM: 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MAGNETISM_EDGE_TOP; 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_LEFT: 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MAGNETISM_EDGE_RIGHT; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_RIGHT: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MAGNETISM_EDGE_LEFT; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MAGNETISM_EDGE_LEFT; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Range GetPrimaryRange(const gfx::Rect& bounds) const { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (edge_) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_TOP: 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_BOTTOM: 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Range(bounds.y(), bounds.bottom()); 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_LEFT: 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_RIGHT: 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Range(bounds.x(), bounds.right()); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Range(); 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Range GetSecondaryRange(const gfx::Rect& bounds) const { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (edge_) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_TOP: 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_BOTTOM: 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Range(bounds.x(), bounds.right()); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_LEFT: 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAGNETISM_EDGE_RIGHT: 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Range(bounds.y(), bounds.bottom()); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Range(); 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool RangesIntersect(const Range& r1, const Range& r2) { 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return r2.first < r1.second && r2.second > r1.first; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The bounds of window. 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const gfx::Rect bounds_; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The edge this matcher checks. 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const MagnetismEdge edge_; 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Visible ranges of the edge. Initialized with GetSecondaryRange() and 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // updated as ShouldAttach() is invoked. When empty the edge is completely 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // obscured by other bounds. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Ranges ranges_; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MagnetismEdgeMatcher); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)enum SecondaryMagnetismEdge { 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECONDARY_MAGNETISM_EDGE_LEADING, 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECONDARY_MAGNETISM_EDGE_TRAILING, 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SECONDARY_MAGNETISM_EDGE_NONE, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used to identify a matched edge. |primary_edge| is relative to the source and 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// indicates the edge the two are to share. For example, if |primary_edge| is 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MAGNETISM_EDGE_RIGHT then the right edge of the source should snap to to the 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// left edge of the target. |secondary_edge| indicates one of the edges along 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the opposite axis should should also be aligned. For example, if 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// |primary_edge| is MAGNETISM_EDGE_RIGHT and |secondary_edge| is 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SECONDARY_MAGNETISM_EDGE_LEADING then the source should snap to the left top 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// corner of the target. 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct MatchedEdge { 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MagnetismEdge primary_edge; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SecondaryMagnetismEdge secondary_edge; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// MagnetismMatcher is used to test if a window should snap to another window. 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// To use MagnetismMatcher do the following: 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// . Create it with the bounds of the window being dragged. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// . Iterate over the child windows checking if the window being dragged should 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// attach to it using ShouldAttach(). 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// . Use AreEdgesObscured() to test if no other windows can match (because all 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// edges are completely obscured). 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ASH_EXPORT MagnetismMatcher { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const int kMagneticDistance; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |edges| is a bitmask of MagnetismEdges to match against. 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MagnetismMatcher(const gfx::Rect& bounds, uint32 edges); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~MagnetismMatcher(); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if |bounds| is close enough to the initial bounds that the two 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should be attached. If true is returned |edge| is set to indicates how the 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // two should snap together. See description of MatchedEdge for details. 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ShouldAttach(const gfx::Rect& bounds, MatchedEdge* edge); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Returns true if no other matches are possible. 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool AreEdgesObscured() const; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Sets |secondary_edge| based on whether the secondary edges should snap. 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void AttachToSecondaryEdge(const gfx::Rect& bounds, 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MagnetismEdge edge, 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SecondaryMagnetismEdge* secondary_edge) const; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The edges to match against. 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int32 edges_; 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ScopedVector<MagnetismEdgeMatcher> matchers_; 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(MagnetismMatcher); 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace ash 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // ASH_WM_WORKSPACE_MAGNETISM_MATCHER_H_ 190