1 /* ************************************************************************
3 qooxdoo - the new era of web development
8 2004-2006 by 1&1 Internet AG, Germany, http://www.1and1.org
11 LGPL 2.1: http://www.gnu.org/licenses/lgpl.html
14 * Volker Pauli (vpauli)
15 * Sebastian Werner (wpbasti)
16 * Carsten Lergenmueller (carstenL)
18 ************************************************************************ */
20 /* ************************************************************************
24 ************************************************************************ */
28 * Creates a new instance of a SplitPane. It allows the user to dynamically resize
29 * the areas dropping the border between.
31 * new qx.ui.splitpane.SplitPane(orientation)
32 * new qx.ui.splitpane.SplitPane(orientation, firstSize, secondSize)
34 * @param orientation {string} The orientation of the splitpane control. Allowed values are "horizontal" (default) and "vertical". This is the same type as used in {@link qx.ui.layout.BoxLayout#orientation}.
35 * @param firstSize {string} The size of the left (top) pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit.
36 * @param secondSize {string} The size of the right (bottom) pane. Allowed values are any by {@link qx.ui.core.Widget} supported unit.
38 qx.OO.defineClass("qx.ui.splitpane.SplitPane", qx.ui.layout.CanvasLayout,
39 function(orientation, firstSize, secondSize)
41 qx.ui.layout.CanvasLayout.call(this);
43 // CREATE INNER BOX LAYOUT
44 var box = this._box = new qx.ui.layout.BoxLayout;
50 the splitpane itself is a boxlayout resides on top of a canvas for easier computing of positional values
52 ---------------------------------------------------------------------------------------
54 | ----------------------------------------------------------------------------------- |
56 | | --------------------------- --- ----------------------------------------------- | |
58 | | | firstArea | |s| | secondArea | | |
67 | | --------------------------- --- ----------------------------------------------- | |
68 | ----------------------------------------------------------------------------------- |
70 ---------------------------------------------------------------------------------------
75 this._slider = new qx.ui.layout.CanvasLayout;
76 this._slider.setAppearance("splitpane-slider");
77 this._slider.setStyleProperty("fontSize", "0px");
78 this._slider.setStyleProperty("lineHeight", "0px");
80 this._slider._pane = this;
81 this.add(this._slider);
84 this._splitter = new qx.ui.layout.CanvasLayout;
85 this._splitter.setStyleProperty("fontSize", "0px");
86 this._splitter.setStyleProperty("lineHeight", "0px");
87 this._splitter.setAppearance("splitpane-splitter");
88 this._splitter._pane = this;
91 this._slider._applyRuntimeLeft = this._splitter._applyRuntimeLeft = this._applyRuntimeLeftWrapper;
92 this._slider._applyRuntimeTop = this._splitter._applyRuntimeTop = this._applyRuntimeTopWrapper;
95 this._knob = new qx.ui.basic.Image;
96 this._knob.setAppearance("splitpane-knob");
97 this._knob.setVisibility(false);
101 this._firstArea = new qx.ui.layout.CanvasLayout;
102 this._secondArea = new qx.ui.layout.CanvasLayout;
105 box.add(this._firstArea, this._splitter, this._secondArea);
108 this.setFirstSize(firstSize || "1*");
109 this.setSecondSize(secondSize || "1*");
112 this.setOrientation(orientation || "horizontal");
125 ---------------------------------------------------------------------------
127 ---------------------------------------------------------------------------
133 qx.OO.changeProperty({ name : "appearance", defaultValue : "splitpane" });
138 qx.OO.addProperty({ name : "showKnob", type : "boolean", allowNull : false, defaultValue : false });
141 * The layout method for the splitpane. If true, the content will updated immediatly.
143 qx.OO.addProperty({ name : "liveResize", type : "boolean", allowNull : false, defaultValue : false, getAlias : "isLiveResize"});
146 * The orientation of the splitpane control. Allowed values are "horizontal" (default) and "vertical".
148 qx.OO.addProperty({ name : "orientation", type : "string", possibleValues : [ "horizontal", "vertical" ] });
151 * The size of the first (left/top) area.
153 qx.OO.addProperty({ name : "firstSize" });
156 * The size of the second (right/bottom) area.
158 qx.OO.addProperty({ name : "secondSize" });
161 * Size of the splitter
163 qx.OO.addProperty({ name : "splitterSize", defaultValue : 4 });
172 ---------------------------------------------------------------------------
174 ---------------------------------------------------------------------------
179 * adds one or more widget(s) to the left pane
181 *@param widget (qx.ui.core.Parent)
183 qx.Proto.addLeft = function() {
184 var c = this.getFirstArea();
185 return c.add.apply(c, arguments);
189 * adds one or more widget(s) to the top pane
191 *@param widget (qx.ui.core.Parent)
193 qx.Proto.addTop = function() {
194 var c = this.getFirstArea();
195 return c.add.apply(c, arguments);
199 * adds one or more widget(s) to the right pane
201 *@param widget (qx.ui.core.Parent)
203 qx.Proto.addRight = function() {
204 var c = this.getSecondArea();
205 return c.add.apply(c, arguments);
209 * adds one or more widget(s) to the bottom pane
211 *@param widget (qx.ui.core.Parent)
213 qx.Proto.addBottom = function() {
214 var c = this.getSecondArea();
215 return c.add.apply(c, arguments);
219 * Returns the splitter.
221 * @return {qx.ui.core.Widget} The splitter.
223 qx.Proto.getSplitter = function() {
224 return this._splitter;
230 * @return {qx.ui.core.Widget} The knob.
232 qx.Proto.getKnob = function() {
242 * Returns the left area (CanvasLayout)
244 * @return {qx.ui.layout.CanvasLayout}
246 qx.Proto.getLeftArea = function() {
247 return this.getFirstArea();
251 * Returns the top area (CanvasLayout)
253 * @return {qx.ui.layout.CanvasLayout}
255 qx.Proto.getTopArea = function() {
256 return this.getFirstArea();
260 * Returns the right area (CanvasLayout)
262 * @return {qx.ui.layout.CanvasLayout}
264 qx.Proto.getRightArea = function() {
265 return this.getSecondArea();
269 * Returns the bottom area (CanvasLayout)
271 * @return {qx.ui.layout.CanvasLayout}
273 qx.Proto.getBottomArea = function() {
274 return this.getSecondArea();
278 * Returns the first area (CanvasLayout)
280 * @return {qx.ui.layout.CanvasLayout}
282 qx.Proto.getFirstArea = function() {
283 return this._firstArea;
287 * Returns the second area (CanvasLayout)
289 * @return {qx.ui.layout.CanvasLayout}
291 qx.Proto.getSecondArea = function() {
292 return this._secondArea;
304 ---------------------------------------------------------------------------
306 ---------------------------------------------------------------------------
309 qx.Proto._modifyShowKnob = function(propValue, propOldValue, propData)
311 this._knob.setVisibility(propValue);
315 qx.Proto._modifyOrientation = function(propValue, propOldValue, propData)
317 // sync orientation to layout
318 this._box.setOrientation(propValue);
323 // remove old listeners
324 this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownX, this);
325 this._splitter.removeEventListener("mousemove", this._onSplitterMouseMoveX, this);
326 this._splitter.removeEventListener("mouseup", this._onSplitterMouseUpX, this);
327 this._knob.removeEventListener("mousedown", this._onSplitterMouseDownX, this);
328 this._knob.removeEventListener("mousemove", this._onSplitterMouseMoveX, this);
329 this._knob.removeEventListener("mouseup", this._onSplitterMouseUpX, this);
331 // reconfigure states
332 this._splitter.removeState("horizontal");
333 this._knob.removeState("horizontal");
335 // reset old dimensions
336 this._firstArea.setWidth(null);
337 this._secondArea.setWidth(null);
338 this._splitter.setWidth(null);
343 // remove old listeners
344 this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownY, this);
345 this._splitter.removeEventListener("mousemove", this._onSplitterMouseMoveY, this);
346 this._splitter.removeEventListener("mouseup", this._onSplitterMouseUpY, this);
347 this._knob.removeEventListener("mousedown", this._onSplitterMouseDownY, this);
348 this._knob.removeEventListener("mousemove", this._onSplitterMouseMoveY, this);
349 this._knob.removeEventListener("mouseup", this._onSplitterMouseUpY, this);
351 // reconfigure states
352 this._splitter.removeState("vertical");
353 this._knob.removeState("vertical");
355 // reset old dimensions
356 this._firstArea.setHeight(null);
357 this._secondArea.setHeight(null);
358 this._splitter.setHeight(null);
367 this._splitter.addEventListener("mousemove", this._onSplitterMouseMoveX, this);
368 this._splitter.addEventListener("mousedown", this._onSplitterMouseDownX, this);
369 this._splitter.addEventListener("mouseup", this._onSplitterMouseUpX, this);
370 this._knob.addEventListener("mousemove", this._onSplitterMouseMoveX, this);
371 this._knob.addEventListener("mousedown", this._onSplitterMouseDownX, this);
372 this._knob.addEventListener("mouseup", this._onSplitterMouseUpX, this);
374 // reconfigure states
375 this._splitter.addState("horizontal");
376 this._knob.addState("horizontal");
379 this._knob.setSource("widget/splitpane/knob-horizontal.png");
385 this._splitter.addEventListener("mousedown", this._onSplitterMouseDownY, this);
386 this._splitter.addEventListener("mousemove", this._onSplitterMouseMoveY, this);
387 this._splitter.addEventListener("mouseup", this._onSplitterMouseUpY, this);
388 this._knob.addEventListener("mousedown", this._onSplitterMouseDownY, this);
389 this._knob.addEventListener("mousemove", this._onSplitterMouseMoveY, this);
390 this._knob.addEventListener("mouseup", this._onSplitterMouseUpY, this);
392 // reconfigure states
393 this._splitter.addState("vertical");
394 this._knob.addState("vertical");
397 this._knob.setSource("widget/splitpane/knob-vertical.png");
402 // apply new dimensions
403 this._syncFirstSize();
404 this._syncSecondSize();
405 this._syncSplitterSize();
410 qx.Proto._modifyFirstSize = function(propValue, propOldValue, propData)
412 this._syncFirstSize();
416 qx.Proto._modifySecondSize = function(propValue, propOldValue, propData)
418 this._syncSecondSize();
422 qx.Proto._modifySplitterSize = function(propValue, propOldValue, propData)
424 this._syncSplitterSize();
428 qx.Proto._syncFirstSize = function()
430 switch(this.getOrientation())
433 this._firstArea.setWidth(this.getFirstSize());
437 this._firstArea.setHeight(this.getFirstSize());
442 qx.Proto._syncSecondSize = function()
444 switch(this.getOrientation())
447 this._secondArea.setWidth(this.getSecondSize());
451 this._secondArea.setHeight(this.getSecondSize());
456 qx.Proto._syncSplitterSize = function()
458 switch(this.getOrientation())
461 this._splitter.setWidth(this.getSplitterSize());
465 this._splitter.setHeight(this.getSplitterSize());
477 ---------------------------------------------------------------------------
479 ---------------------------------------------------------------------------
483 * Initializes drag session in case of a mousedown event on splitter in a horizontal splitpane.
485 * @param e {qx.event.MouseEvent} The event itself.
487 qx.Proto._onSplitterMouseDownX = function(e)
489 if (!e.isLeftButtonPressed()) {
493 this._commonMouseDown();
495 // activate global cursor
496 this.getTopLevelWidget().setGlobalCursor("col-resize");
497 this._slider.addState("dragging");
498 this._knob.addState("dragging");
500 // initialize the drag session
501 this._dragMin = qx.dom.Location.getPageInnerLeft(this._box.getElement());
502 this._dragMax = this._dragMin + this._box.getInnerWidth() - this._splitter.getBoxWidth();
503 this._dragOffset = e.getPageX() - qx.dom.Location.getPageBoxLeft(this._splitter.getElement());
507 * Initializes drag session in case of a mousedown event on splitter in a vertical splitpane.
509 * @param e {qx.event.MouseEvent} The event itself.
511 qx.Proto._onSplitterMouseDownY = function(e)
513 if (!e.isLeftButtonPressed()) {
517 this._commonMouseDown();
519 // activate global cursor
520 this.getTopLevelWidget().setGlobalCursor("row-resize");
521 this._slider.addState("dragging");
522 this._knob.addState("dragging");
524 // initialize the drag session
525 // dragStart = position of layout + mouse offset on splitter
526 this._dragMin = qx.dom.Location.getPageInnerTop(this._box.getElement());
527 this._dragMax = this._dragMin + this._box.getInnerHeight() - this._splitter.getBoxHeight();
528 this._dragOffset = e.getPageY() - qx.dom.Location.getPageBoxTop(this._splitter.getElement());
531 qx.Proto._commonMouseDown = function()
534 this._splitter.setCapture(true);
536 // initialize the slider
537 if(!this.isLiveResize())
539 this._slider.setLeft(this._splitter.getOffsetLeft());
540 this._slider.setTop(this._splitter.getOffsetTop());
541 this._slider.setWidth(this._splitter.getBoxWidth());
542 this._slider.setHeight(this._splitter.getBoxHeight());
556 * Move the splitter in case of a mousemove event on splitter in a horizontal splitpane.
558 * @param e {qx.event.MouseEvent} The event itself.
560 qx.Proto._onSplitterMouseMoveX = function(e)
562 if (!this._splitter.getCapture()) {
566 this.isLiveResize() ? this._syncX(e) : this._slider._applyRuntimeLeft(this._normalizeX(e));
571 * Move the splitter in case of a mousemove event on splitter in a vertical splitpane.
573 * @param e {qx.event.MouseEvent} The event itself.
575 qx.Proto._onSplitterMouseMoveY = function(e)
577 if (!this._splitter.getCapture()) {
581 this.isLiveResize() ? this._syncY(e) : this._slider._applyRuntimeTop(this._normalizeY(e));
592 * Ends the drag session and computes the new dimensions of panes in case of a mouseup event on splitter in a horizontal splitpane.
594 * @param e {qx.event.MouseEvent} The event itself.
596 qx.Proto._onSplitterMouseUpX = function(e)
598 if (!this._splitter.getCapture()) {
602 if(!this.isLiveResize()) {
606 this._commonMouseUp();
610 * Ends the drag session and computes the new dimensions of panes in case of a mouseup event on splitter in a vertical splitpane.
612 * @param e {qx.event.MouseEvent} The event itself.
614 qx.Proto._onSplitterMouseUpY = function(e)
616 if (!this._splitter.getCapture()) {
620 if(!this.isLiveResize()) {
624 this._commonMouseUp();
627 qx.Proto._commonMouseUp = function()
633 this._splitter.setCapture(false);
635 // reset the global cursor
636 this.getTopLevelWidget().setGlobalCursor(null);
638 // cleanup dragsession
639 this._slider.removeState("dragging");
640 this._knob.removeState("dragging");
643 qx.Proto._syncX = function(e)
645 var first = this._normalizeX(e);
646 var second = this._box.getInnerWidth() - this._splitter.getBoxWidth() - first;
648 this._syncCommon(first, second);
651 qx.Proto._syncY = function(e)
653 var first = this._normalizeY(e);
654 var second = this._box.getInnerHeight() - this._splitter.getBoxHeight() - first;
656 this._syncCommon(first, second);
659 qx.Proto._syncCommon = function(first, second)
661 this.setFirstSize(first + "*");
662 this.setSecondSize(second + "*");
665 qx.Proto._normalizeX = function(e) {
666 return qx.lang.Number.limit(e.getPageX() - this._dragOffset, this._dragMin, this._dragMax) - this._dragMin;
669 qx.Proto._normalizeY = function(e) {
670 return qx.lang.Number.limit(e.getPageY() - this._dragOffset, this._dragMin, this._dragMax) - this._dragMin;
673 qx.Proto._applyRuntimeLeftWrapper = function(v)
675 if (this._pane.getOrientation() == "horizontal") {
676 this._pane._knob._applyRuntimeLeft(v);
679 return this.constructor.prototype._applyRuntimeLeft.call(this, v);
682 qx.Proto._applyRuntimeTopWrapper = function(v)
684 if (this._pane.getOrientation() == "vertical") {
685 this._pane._knob._applyRuntimeTop(v);
688 return this.constructor.prototype._applyRuntimeTop.call(this, v);
696 ------------------------------------------------------------------------------------
698 ------------------------------------------------------------------------------------
704 qx.Proto.dispose = function()
706 if (this.getDisposed()) {
712 this._firstArea.dispose();
713 this._firstArea = null;
718 this._secondArea.dispose();
719 this._secondArea = null;
724 this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownX, this);
725 this._splitter.removeEventListener("mouseup", this._onSplitterMouseMoveX, this);
726 this._splitter.removeEventListener("mousemove", this._onSplitterMouseUpX, this);
728 this._splitter.removeEventListener("mousedown", this._onSplitterMouseDownY, this);
729 this._splitter.removeEventListener("mouseup", this._onSplitterMouseMoveY, this);
730 this._splitter.removeEventListener("mousemove", this._onSplitterMouseUpY, this);
732 this._splitter.dispose();
733 this._splitter._pane = null;
734 this._splitter = null;
739 this._slider.dispose();
740 this._slider._pane = null;
746 this._knob.removeEventListener("mousedown", this._onSplitterMouseDownX, this);
747 this._knob.removeEventListener("mouseup", this._onSplitterMouseMoveX, this);
748 this._knob.removeEventListener("mousemove", this._onSplitterMouseUpX, this);
750 this._knob.removeEventListener("mousedown", this._onSplitterMouseDownY, this);
751 this._knob.removeEventListener("mouseup", this._onSplitterMouseMoveY, this);
752 this._knob.removeEventListener("mousemove", this._onSplitterMouseUpY, this);
754 this._knob.dispose();
758 return qx.ui.layout.BoxLayout.prototype.dispose.call(this);