/* Copyright (c) 2011, Geert Bergman (geert@scrivo.nl)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of "Scrivo" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* $Id: BorderLayout.js 616 2013-04-22 23:48:38Z geert $
*/
"use strict";
SUI.BorderLayout = SUI.defineClass(
/** @lends SUI.BorderLayout.prototype */{
/** @ignore */ baseClass: SUI.SplitLayout,
/**
* @class
* The border layOut is a container type that lets you split an area into
* a center box and (optional) north, south, west and east boxes, just at
* as the split layOut from which it is inherited. The difference between
* the border layOut and the split layOut is that the border layOut has
* sizable borders. When sizing the total border layOut component the same
* rules are followed as for the split layOut.
*
* @augments SUI.SplitLayout
*
* @description
* Construct a split border object. You can tell the split layOut which
* areas (north/south/west/east) to set and the dimensions to use.
* It's also possible to set the child boxes directly.
*
* @constructs
* @param see base class
*/
initializer: function(arg) {
SUI.BorderLayout.initializeBase(this, arg);
this.addClass("sui-borderlayout");
this.anchor = {left:true,right:true,top:true,bottom:true};
this.center = new SUI.Box({parent: this});
if (arg.center && arg.center.box) {
this.add(arg.center.box, "center");
}
// add north, south, west and east if given in arguments
if (arg.north) {
this.north = new SUI.Box({parent: this});
this.north.height(arg.north.height);
this._createBorder(this.north);
if (arg.north.box) {
this.add(arg.north.box, "north");
}
}
if (arg.south) {
this.south = new SUI.Box({parent: this});
this.south.height(arg.south.height);
this._createBorder(this.south);
if (arg.south.box) {
this.add(arg.south.box, "south");
}
}
if (arg.west) {
this.west = new SUI.Box({parent: this});
this.west.width(arg.west.width);
this._createBorder(this.west);
if (arg.west.box) {
this.add(arg.west.box, "west");
}
}
if (arg.east) {
this.east = new SUI.Box({parent: this});
this.east.width(arg.east.width);
this._createBorder(this.east);
if (arg.east.box) {
this.add(arg.east.box, "east");
}
}
},
/**
* Width of the border between the panels.
*/
BORDER_WIDTH: 6,
/**
* Size of the gripper image on the panel.
*/
HANDLE_LENGTH: 48,
/**
* Set the CSS width and height of she SplitLayout, its locations and
* all the child boxes.
*/
display: function() {
// set the CSS dimensions of the container box ...
this.setDim();
// ... and the of the location boxes ...
if (this.north) {
this.north.setDim();
this.north.paneBorder.setDim();
this.north.handle.setDim();
}
if (this.south) {
this.south.setDim();
this.south.paneBorder.setDim();
this.south.handle.setDim();
}
if (this.west) {
this.west.setDim();
this.west.paneBorder.setDim();
this.west.handle.setDim();
}
if (this.east) {
this.east.setDim();
this.east.paneBorder.setDim();
this.east.handle.setDim();
}
this.center.setDim();
// ... and of all the children
SUI.SplitLayout.parentMethod(this, "display");
},
/**
* Recalculate size of the frames in the border layOut
*/
layOut: function() {
// get the minimum widths and heights
var tmp = this._prepareLayout();
var w = tmp.w; // corrected widths
var h = tmp.h; // corrected heights
var ct = 0; // center top
var cl = 0; // center left
var cw = w.w; // center width
var ch = h.h; // center height
var hl = 0; // handle length
// set the dimensions of the container box
this.setRect(this.top(), this.left(), w.w, h.h);
// handle length for horizontal border
hl = this.HANDLE_LENGTH > w.w ? w.w : this.HANDLE_LENGTH;
// if there is a north panel ...
if (this.north) {
// ... set the dimensions ...
this.north.setRect(0, 0, w.w, h.nh);
// ... and adjust the top and height of the center
ct += h.nh + this.BORDER_WIDTH;
ch -= ct;
// set the dimensions of the north border and handle
this.north.paneBorder.setRect(h.nh, 0, w.w, this.BORDER_WIDTH);
this.north.handle.setRect(
0, Math.floor((w.w-hl)/2), hl, this.BORDER_WIDTH);
}
// if there is a south panel ...
if (this.south) {
// ... set the dimensions ...
this.south.setRect(h.h-h.sh, 0, w.w, h.sh);
// ... and adjust the height of the center
ch -= h.sh + this.BORDER_WIDTH;
// set the dimensions of the south border and handle
this.south.paneBorder.setRect(h.h-h.sh-this.BORDER_WIDTH, 0, w.w,
this.BORDER_WIDTH);
this.south.handle.setRect(0, Math.floor((w.w-hl)/2), hl,
this.BORDER_WIDTH);
}
// handle length for vertical border
hl = this.HANDLE_LENGTH > ch ? ch : this.HANDLE_LENGTH;
// if there is a west panel ...
if (this.west) {
// ... set the dimensions ...
this.west.setRect(ct, 0, w.ew, ch);
// ... and adjust the left and width of the center
cl += w.ew + this.BORDER_WIDTH;
cw -= cl;
// set the dimensions of the west border and handle
this.west.paneBorder.setRect(ct, w.ew, this.BORDER_WIDTH, ch);
this.west.handle.setRect(
Math.floor((ch-hl)/2), 0,this.BORDER_WIDTH, hl);
}
// if there is an east panel ...
if (this.east) {
// ... set the dimensions ...
this.east.setRect(ct, w.w-w.ww, w.ww, ch);
// ... and adjust the width of the center
cw -= w.ww + this.BORDER_WIDTH;
// set the dimensions of the east border and handle
this.east.paneBorder.setRect(
ct, w.w-w.ww-this.BORDER_WIDTH, this.BORDER_WIDTH, ch);
this.east.handle.setRect(
Math.floor((ch-hl)/2), 0,this.BORDER_WIDTH, hl);
}
// now we know the position of the center
this.center.setRect(ct, cl, cw, ch);
// layOut the child boxes
SUI.SplitLayout.parentMethod(this, "layOut"); return;
},
/* Create border and handle box for a pane
*/
_createBorder: function(pane) {
// create the border
pane.paneBorder = new SUI.Box({parent: this});
pane.paneBorder.addClass("sui-borderlayout-border");
// and set the cursor type for the border
pane.paneBorder.el().style.cursor =
(pane === this.east || pane === this.west)
? "col-resize" : "row-resize";
// create the handle
pane.handle = new SUI.Box({parent: pane.paneBorder});
pane.handle.addClass("sui-borderlayout-handle");
pane.handle.el().style.cursor = pane.paneBorder.el().style.cursor;
pane.handle.el().style.backgroundImage = "url(" + SUI.imgDir + "/"
+ SUI.resource.blHandle + ")";
// add the onmousedown handler to the border
var that = this;
SUI.browser.addEventListener(pane.paneBorder.el(), "mousedown",
function(e) {
if (!that._doMouseDown(new SUI.Event(this, e), pane)) {
SUI.browser.noPropagation(e);
}
}
);
},
/* Start the dragging motion: create and initialize the dragger.
*/
_doMouseDown: function(event, pane) {
// Create dragger ...
var dragger = new SUI.Dragger({parent: this});
// ... width the same dimensions as the border
dragger.setRect(pane.paneBorder);
dragger.addClass("sui-borderlayout-dragger");
// if we're resizing the west pane ...
if (this.west === pane) {
// ... set minimum x ...
dragger.xMin(this.west.minWidth());
// ... and maximum x ...
dragger.xMax(this.center.left() + this.center.width()
- this.center.minWidth() - this.BORDER_WIDTH);
// ... and horizontal dragging direction
dragger.direction(dragger.HORIZONTAL);
}
// if we're resizing the east pane ...
if (this.east === pane) {
// ... set minimum x ...
dragger.xMin(this.center.left() + this.center.minWidth());
// ... and maximum x ...
dragger.xMax(this.east.left() + this.east.width()
- this.east.minWidth() - this.BORDER_WIDTH);
// ... and horizontal dragging direction
dragger.direction(dragger.HORIZONTAL);
}
// if we're resizing the north pane ...
if (this.north === pane) {
// ... set minimum y ...
dragger.yMin(this.north.minHeight());
// ... and maximum y ...
dragger.yMax(this.center.top() + this.center.height()
- this.center.minHeight() - this.BORDER_WIDTH);
// ... and vertical dragging direction
dragger.direction(dragger.VERTICAL);
}
// if we're resizing the south pane ...
if (this.south === pane) {
// ... set minimum y ...
dragger.yMin(this.center.top() + this.center.minHeight());
// ... and maximum y ...
dragger.yMax(this.south.top() + this.south.height()
- this.south.minHeight() - this.BORDER_WIDTH);
// ... and vertical dragging direction
dragger.direction(dragger.VERTICAL);
}
// make a box that covers the entire border layOut. This prevents
// HTML objects such as an iframe to steal the onmousemove event. You
// can use this to keep the cursor if you move off the border also.
var draggerbg = new SUI.Box({parent: this});
draggerbg.setRect(0, 0, this.width(), this.height());
draggerbg.el().style.cursor = pane.paneBorder.el().style.cursor;
draggerbg.setDim();
// copy the cursor of the border to the dragger
dragger.el().style.cursor = pane.paneBorder.el().style.cursor;
// and set the CSS dimension of the dragger
dragger.setDim();
var that = this;
// 'that', 'pane', 'dragger', 'draggerbg' are closure variables
dragger.addListener("onEndDrag",
function() {
that._endDrag(pane, dragger, draggerbg);
}
);
// and start dragging
dragger.start(event, this);
},
/* End dragging of the border: set the new pane and border dimensions
*/
_endDrag: function(pane, dragger, draggerbg) {
// remove the dragger and dragger background from the DOM tree
dragger.removeBox();
draggerbg.removeBox();
// set the new pane and border dimensions
if (this.north === pane) {
var d = this.north.paneBorder.top() - dragger.top();
this.north.height(this.north.height() - d);
}
if (this.south === pane) {
var d = this.south.paneBorder.top() - dragger.top();
this.south.height(this.south.height() + d);
}
if (this.west === pane) {
var d = this.west.paneBorder.left() - dragger.left();
this.west.width(this.west.width() - d);
}
if (this.east === pane) {
var d = this.east.paneBorder.left() - dragger.left();
this.east.width(this.east.width() + d);
}
// redraw the border layOut
this.draw();
}
});