tabs now also project trenches; unregistering trenches on group/tab close; allow proportional resizing while snapping; preferLeft and preferTop flags for which edges to preferentially snap to

This commit is contained in:
Michael Yoshitaka Erlewine 2010-06-15 19:08:21 -04:00
parent bc4b8a9b47
commit ea88675f6d
4 changed files with 108 additions and 54 deletions

View File

@ -477,38 +477,6 @@ window.Group.prototype = iQ.extend(new Item(), new Subscribable(), {
this.save();
},
setTrenches: function(rect) {
var container = this.container;
if (!this.borderTrenches) {
var bT = this.borderTrenches = {};
bT.left = Trenches.register(container,"x","border","left");
bT.right = Trenches.register(container,"x","border","right");
bT.top = Trenches.register(container,"y","border","top");
bT.bottom = Trenches.register(container,"y","border","bottom");
}
var bT = this.borderTrenches;
bT.left.setWithRect(rect);
bT.right.setWithRect(rect);
bT.top.setWithRect(rect);
bT.bottom.setWithRect(rect);
if (!this.guideTrenches) {
var gT = this.guideTrenches = {};
gT.left = Trenches.register(container,"x","guide","left");
gT.right = Trenches.register(container,"x","guide","right");
gT.top = Trenches.register(container,"y","guide","top");
gT.bottom = Trenches.register(container,"y","guide","bottom");
}
var gT = this.guideTrenches;
gT.left.setWithRect(rect);
gT.right.setWithRect(rect);
gT.top.setWithRect(rect);
gT.bottom.setWithRect(rect);
},
// ----------
setZ: function(value) {
@ -538,6 +506,7 @@ window.Group.prototype = iQ.extend(new Item(), new Subscribable(), {
this.removeAll();
this._sendOnClose();
Groups.unregister(this);
Trenches.unregister(this.container);
iQ(this.container).fadeOut(function() {
iQ(this).remove();
Items.unsquish();
@ -580,10 +549,12 @@ window.Group.prototype = iQ.extend(new Item(), new Subscribable(), {
} else {
$el = iQ(a);
item = Items.item($el);
}
}
Utils.assert('shouldn\'t already be in another group', !item.parent || item.parent == this);
Trenches.unregister(a.container);
if(!dropPos)
dropPos = {top:window.innerWidth, left:window.innerHeight};

View File

@ -203,6 +203,7 @@ window.Item.prototype = {
//
setParent: function(parent) {
this.parent = parent;
Trenches.unregister(this.container);
this.save();
},
@ -401,7 +402,39 @@ window.Item.prototype = {
height: this.bounds.height
});
}
}
},
setTrenches: function(rect) {
var container = this.container;
if (!this.borderTrenches) {
var bT = this.borderTrenches = {};
bT.left = Trenches.register(container,"x","border","left");
bT.right = Trenches.register(container,"x","border","right");
bT.top = Trenches.register(container,"y","border","top");
bT.bottom = Trenches.register(container,"y","border","bottom");
}
var bT = this.borderTrenches;
bT.left.setWithRect(rect);
bT.right.setWithRect(rect);
bT.top.setWithRect(rect);
bT.bottom.setWithRect(rect);
if (!this.guideTrenches) {
var gT = this.guideTrenches = {};
gT.left = Trenches.register(container,"x","guide","left");
gT.right = Trenches.register(container,"x","guide","right");
gT.top = Trenches.register(container,"y","guide","top");
gT.bottom = Trenches.register(container,"y","guide","bottom");
}
var gT = this.guideTrenches;
gT.left.setWithRect(rect);
gT.right.setWithRect(rect);
gT.top.setWithRect(rect);
gT.bottom.setWithRect(rect);
},
};
// ##########

View File

@ -121,6 +121,7 @@ window.TabItem = function(container, tab) {
var self = this;
this.tab.mirror.addOnClose(this, function(who, info) {
TabItems.unregister(self);
Trenches.unregister(self.container);
});
this.tab.mirror.addSubscriber(this, 'urlChanged', function(who, info) {
@ -178,15 +179,15 @@ window.TabItem.prototype = iQ.extend(new Item(), {
reloadBounds: function() {
var newBounds = Utils.getBounds(this.container);
/*
if(!this.bounds || newBounds.width != this.bounds.width || newBounds.height != this.bounds.height) {
/* if(!this.bounds || newBounds.width != this.bounds.width || newBounds.height != this.bounds.height) {
// if resizing, or first time, do the whole deal
if(!this.bounds)
this.bounds = new Rect(0, 0, 0, 0);
this.setBounds(newBounds, true);
} else {
*/
} else { */
// if we're just moving, this is more efficient
this.bounds = newBounds;
this._updateDebugBounds();
@ -204,7 +205,7 @@ window.TabItem.prototype = iQ.extend(new Item(), {
if(!options)
options = {};
if(this._zoomPrep)
this.bounds.copy(rect);
else {
@ -285,6 +286,9 @@ window.TabItem.prototype = iQ.extend(new Item(), {
if(!isRect(this.bounds))
Utils.trace('TabItem.setBounds: this.bounds is not a real rectangle!', this.bounds);
if (this.parent === null)
this.setTrenches(rect);
this.save();
},
@ -345,7 +349,7 @@ window.TabItem.prototype = iQ.extend(new Item(), {
self.reloadBounds();
var bounds = self.getBounds();
// OH SNAP!
var newRect = Trenches.snap(bounds,false);
var newRect = Trenches.snap(bounds,false,true);
if (newRect) // might be false if no changes were made
self.setBounds(bounds,true);
},

View File

@ -66,8 +66,7 @@ Trench.prototype = {
},
show: function Trench_show() { // DEBUG
if (!iQ('#showTrenches:checked').length) {
if (this.visibleTrench)
this.visibleTrench.remove();
this.hide();
return;
}
@ -88,7 +87,11 @@ Trench.prototype = {
visibleTrench.css(this.rect);
iQ("body").append(visibleTrench);
},
rectOverlaps: function Trench_rectOverlaps(rect, assumeConstantSize) {
hide: function Trench_hide() {
if (this.visibleTrench)
this.visibleTrench.remove();
},
rectOverlaps: function Trench_rectOverlaps(rect, assumeConstantSize, keepProportional) {
var xRange = {min: rect.left, max: rect.left + rect.width};
var yRange = {min: rect.top, max: rect.top + rect.height};
@ -106,6 +109,8 @@ Trench.prototype = {
edgeToCheck = this.edge;
}
rect.adjustedEdge = edgeToCheck;
switch (edgeToCheck) {
case "left":
if (this.ruleOverlaps(rect.left, yRange)) {
@ -115,10 +120,14 @@ Trench.prototype = {
break;
case "right":
if (this.ruleOverlaps(rect.left + rect.width, yRange)) {
if (assumeConstantSize)
if (assumeConstantSize) {
rect.left = this.position - rect.width;
else
rect.width = this.position - rect.left;
} else {
var newWidth = this.position - rect.left;
if (keepProportional)
rect.height = rect.height * newWidth / rect.width;
rect.width = newWidth;
}
return rect;
}
break;
@ -130,10 +139,14 @@ Trench.prototype = {
break;
case "bottom":
if (this.ruleOverlaps(rect.top + rect.height, xRange)) {
if (assumeConstantSize)
if (assumeConstantSize) {
rect.top = this.position - rect.height;
else
rect.height = this.position - rect.top;
} else {
var newHeight = this.position - rect.top;
if (keepProportional)
rect.width = rect.width * newHeight / rect.height;
rect.height = newHeight;
}
return rect;
}
}
@ -149,12 +162,22 @@ Trench.prototype = {
// global Trenches
// used to track "trenches" in which the edges will snap.
var Trenches = {
preferTop: true,
preferLeft: true,
trenches: [],
register: function Trenches_register(element, xory, type, edge) {
var trench = new Trench(element, xory, type, edge);
this.trenches.push(trench);
return trench;
},
unregister: function Trenches_unregister(element) {
for (let i in this.trenches) {
if (this.trenches[i].el === element) {
this.trenches[i].hide();
delete this.trenches[i];
}
}
},
activateOthersTrenches: function Trenches_activateOthersTrenches(element) {
this.trenches.forEach(function(t) {
if (t.el === element)
@ -169,18 +192,41 @@ var Trenches = {
t.show();
});
},
snap: function Trenches_snap(rect,assumeConstantSize) {
snap: function Trenches_snap(rect,assumeConstantSize,keepProportional) {
var updated = false;
this.trenches.forEach(function(t){
var updatedX = false;
var updatedY = false;
for (let i in this.trenches) {
var t = this.trenches[i];
if (!t.active)
return;
continue;
// newRect will be a new rect, or false
var newRect = t.rectOverlaps(rect,assumeConstantSize);
var newRect = t.rectOverlaps(rect,assumeConstantSize,keepProportional);
if (newRect) {
if (updatedX && updatedY)
break;
if (updatedX && (newRect.adjustedEdge == "left"||newRect.adjustedEdge == "right"))
continue;
if (updatedY && (newRect.adjustedEdge == "top"||newRect.adjustedEdge == "bottom"))
continue;
rect = newRect;
updated = true;
// if updatedX, we don't need to update x any more.
if (newRect.adjustedEdge == "left" && this.preferLeft)
updatedX = true;
if (newRect.adjustedEdge == "right" && !this.preferLeft)
updatedX = true;
// if updatedY, we don't need to update x any more.
if (newRect.adjustedEdge == "top" && this.preferTop)
updatedY = true;
if (newRect.adjustedEdge == "bottom" && !this.preferTop)
updatedY = true;
}
});
}
if (updated)
return rect;
else