From e21f6105d8dab899f123717d462e177727aab978 Mon Sep 17 00:00:00 2001 From: Aza Raskin Date: Sun, 16 May 2010 11:30:45 -0700 Subject: [PATCH] + First pass at a snap-to functionality for groups - The jQuery UI's draggable snap-to just wasn't specific enough for our use case + TODO: Need to add the snap ability to resizing groups --- browser/base/content/tabcandy/app/groups.js | 106 +++++++++++++++++++- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/browser/base/content/tabcandy/app/groups.js b/browser/base/content/tabcandy/app/groups.js index a1b786760baa..f14e81f0f5ab 100644 --- a/browser/base/content/tabcandy/app/groups.js +++ b/browser/base/content/tabcandy/app/groups.js @@ -1006,14 +1006,60 @@ var DragInfo = function(element, event) { DragInfo.prototype = { // ---------- snap: function(event, ui){ - //window.console.log( event, ui); - // Step 1: Find the closest group by edge + var me = this.item; + function closeTo(a,b){ return Math.abs(a-b) <= 12 } + + // Snap inline to the tops of other groups. + var closestTop = null; + var minDist = Infinity; + for each(var group in Groups.groups){ + // Exlcude the current group + if( group == me ) continue; + var dist = Math.abs(group.bounds.top - me.bounds.top); + if( dist < minDist ){ + minDist = dist; + closestTop = group.bounds.top; + } + } - // Step 2: Match to the to + if( closeTo(ui.position.top, closestTop) ){ + ui.position.top = closestTop; + } + + // Snap to the right of other groups by topish left corner + var topLeft = new Point( me.bounds.left, ui.position.top + 25 ); + var other = Groups.findGroupClosestToPoint(topLeft, {exclude:me}); + var closestRight = other.bounds.right + 20; + if( closeTo(ui.position.left, closestRight) ){ + ui.position.left = closestRight; + } + + // Snap to the bottom of other groups by top leftish corner + var topLeft = new Point( me.bounds.left+25, ui.position.top); + var other = Groups.findGroupClosestToPoint(topLeft, {exclude:me}); + var closestBottom = other.bounds.bottom + 20; + if( closeTo(ui.position.top, closestBottom) ){ + ui.position.top = closestBottom; + } - // Step 3: Profit! + // Snap inline to the right of other groups by top right corner + var topRight = new Point( me.bounds.right, ui.position.top); + var other = Groups.findGroupClosestToPoint(topRight, {exclude:me}); + var closestRight = other.bounds.right; + if( closeTo(ui.position.left + me.bounds.width, closestRight) ){ + ui.position.left = closestRight - me.bounds.width; + } + + // Snap inline to the left of other groups by top left corner + var topLeft = new Point( me.bounds.left, ui.position.top); + var other = Groups.findGroupClosestToPoint(topLeft, {exclude:me}); + var closestLeft = other.bounds.left; + if( closeTo(ui.position.left, closestLeft) ){ + ui.position.left = closestLeft; + } - // TODO: Refactor these comments. Also, does this routine belong in DragInfo? + // Step 4: Profit? + return ui; }, @@ -1022,6 +1068,7 @@ DragInfo.prototype = { // Called in response to a jQuery-UI draggable "drag" event. drag: function(event, ui) { if(this.item.isAGroup) { + ui = this.snap(event,ui); var bb = this.item.getBounds(); bb.left = ui.position.left; bb.top = ui.position.top; @@ -1374,6 +1421,55 @@ window.Groups = { return tab.parent == null; }) return tabs + }, + + // --------- + // Function: findGroupClosestToPoint + // Given a returns an object which contains + // the group and it's closest side: {group:, side:"top|left|right|bottom"} + // + // Paramters + // - + // - options + // + exclude: will exclude a group for being matched against + findGroupClosestToPoint: function(point, options){ + minDist = Infinity; + closestGroup = null; + var onSide = null; + for each(var group in this.groups){ + // Step 0: Exlcude any exluded groups + if( options && options.exclude && options.exclude == group ) continue; + + // Step 1: Find the closest side + var sideDists = []; + sideDists.push( [Math.abs(group.bounds.top - point.y), "top"] ); + sideDists.push( [Math.abs(group.bounds.bottom - point.y), "bottom"] ); + sideDists.push( [Math.abs(group.bounds.left - point.x), "left"] ); + sideDists.push( [Math.abs(group.bounds.right - point.x), "right"] ); + sideDists.sort(function(a,b){return a[0]-b[0]}); + var closestSide = sideDists[0][1]; + + // Step 2: Find where one that side is closest to the point. + if( closestSide == "top" || closestSide == "bottom" ){ + var closestPoint = new Point(0, group.bounds[closestSide]); + closestPoint.x = Math.max(Math.min(point.x, group.bounds.right), group.bounds.left); + } else { + var closestPoint = new Point(group.bounds[closestSide], 0); + closestPoint.y = Math.max(Math.min(point.y, group.bounds.bottom), group.bounds.top); + } + + // Step 3: Calculate the distance from the closest point on the rect + // to the given point + var dist = closestPoint.distance(point); + if( dist < minDist ){ + closestGroup = group; + onSide = closestSide; + minDist = dist; + } + + } + + return closestGroup; } };