X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTSplitPane.java;h=b308e9b79162a57aea99d55bad2a77f22e951eb3;hb=HEAD;hp=0a3443b85eeda57511fd486db0539dc663e08f6a;hpb=5ffeabccc177e9fdadb62002c6d3bf1f6ae650fa;p=fanfix.git diff --git a/src/jexer/TSplitPane.java b/src/jexer/TSplitPane.java index 0a3443b..b308e9b 100644 --- a/src/jexer/TSplitPane.java +++ b/src/jexer/TSplitPane.java @@ -30,10 +30,8 @@ package jexer; import jexer.bits.CellAttributes; import jexer.bits.GraphicsChars; -import jexer.event.TMenuEvent; import jexer.event.TMouseEvent; import jexer.event.TResizeEvent; -import jexer.menu.TMenu; /** * TSplitPane contains two widgets with a draggable horizontal or vertical @@ -81,6 +79,11 @@ public class TSplitPane extends TWidget { */ private boolean inSplitMove = false; + /** + * The last seen mouse position. + */ + private TMouseEvent mouse; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -136,14 +139,15 @@ public class TSplitPane extends TWidget { */ @Override public void onMouseDown(final TMouseEvent mouse) { + this.mouse = mouse; inSplitMove = false; if (mouse.isMouse1()) { if (vertical) { - inSplitMove = (mouse.getX() == split); + inSplitMove = (mouse.getAbsoluteX() - getAbsoluteX() == split); } else { - inSplitMove = (mouse.getY() == split); + inSplitMove = (mouse.getAbsoluteY() - getAbsoluteY() == split); } if (inSplitMove) { return; @@ -161,6 +165,7 @@ public class TSplitPane extends TWidget { */ @Override public void onMouseUp(final TMouseEvent mouse) { + this.mouse = mouse; if (inSplitMove && mouse.isMouse1()) { // Stop moving split @@ -179,13 +184,23 @@ public class TSplitPane extends TWidget { */ @Override public void onMouseMotion(final TMouseEvent mouse) { + this.mouse = mouse; + + if ((mouse.getAbsoluteX() - getAbsoluteX() < 0) + || (mouse.getAbsoluteX() - getAbsoluteX() >= getWidth()) + || (mouse.getAbsoluteY() - getAbsoluteY() < 0) + || (mouse.getAbsoluteY() - getAbsoluteY() >= getHeight()) + ) { + // Mouse has travelled out of my window. + inSplitMove = false; + } if (inSplitMove) { if (vertical) { - split = mouse.getX(); + split = mouse.getAbsoluteX() - getAbsoluteX(); split = Math.min(Math.max(1, split), getWidth() - 2); } else { - split = mouse.getY(); + split = mouse.getAbsoluteY() - getAbsoluteY(); split = Math.min(Math.max(1, split), getHeight() - 2); } layoutChildren(); @@ -208,11 +223,95 @@ public class TSplitPane extends TWidget { CellAttributes attr = getTheme().getColor("tsplitpane"); if (vertical) { vLineXY(split, 0, getHeight(), GraphicsChars.WINDOW_SIDE, attr); - // TODO: draw intersections of children + + // Draw intersections of children + if ((left instanceof TSplitPane) + && (((TSplitPane) left).vertical == false) + && (right instanceof TSplitPane) + && (((TSplitPane) right).vertical == false) + && (((TSplitPane) left).split == ((TSplitPane) right).split) + ) { + putCharXY(split, ((TSplitPane) left).split, '\u253C', attr); + } else { + if ((left instanceof TSplitPane) + && (((TSplitPane) left).vertical == false) + ) { + putCharXY(split, ((TSplitPane) left).split, '\u2524', attr); + } + if ((right instanceof TSplitPane) + && (((TSplitPane) right).vertical == false) + ) { + putCharXY(split, ((TSplitPane) right).split, '\u251C', + attr); + } + } + + if ((mouse != null) + && (mouse.getAbsoluteX() == getAbsoluteX() + split) + && (mouse.getAbsoluteY() >= getAbsoluteY()) && + (mouse.getAbsoluteY() < getAbsoluteY() + getHeight()) + ) { + putCharXY(split, mouse.getAbsoluteY() - getAbsoluteY(), + '\u2194', attr); + } } else { hLineXY(0, split, getWidth(), GraphicsChars.SINGLE_BAR, attr); - // TODO: draw intersections of children + + // Draw intersections of children + if ((top instanceof TSplitPane) + && (((TSplitPane) top).vertical == true) + && (bottom instanceof TSplitPane) + && (((TSplitPane) bottom).vertical == true) + && (((TSplitPane) top).split == ((TSplitPane) bottom).split) + ) { + putCharXY(((TSplitPane) top).split, split, '\u253C', attr); + } else { + if ((top instanceof TSplitPane) + && (((TSplitPane) top).vertical == true) + ) { + putCharXY(((TSplitPane) top).split, split, '\u2534', attr); + } + if ((bottom instanceof TSplitPane) + && (((TSplitPane) bottom).vertical == true) + ) { + putCharXY(((TSplitPane) bottom).split, split, '\u252C', + attr); + } + } + + if ((mouse != null) + && (mouse.getAbsoluteY() == getAbsoluteY() + split) + && (mouse.getAbsoluteX() >= getAbsoluteX()) && + (mouse.getAbsoluteX() < getAbsoluteX() + getWidth()) + ) { + putCharXY(mouse.getAbsoluteX() - getAbsoluteX(), split, + '\u2195', attr); + } } + + } + + /** + * Generate a human-readable string for this widget. + * + * @return a human-readable string + */ + @Override + public String toString() { + return String.format("%s(%8x) %s position (%d, %d) geometry %dx%d " + + "split %d left %s(%8x) right %s(%8x) top %s(%8x) bottom %s(%8x) " + + "active %s enabled %s visible %s", getClass().getName(), + hashCode(), (vertical ? "VERTICAL" : "HORIZONTAL"), + getX(), getY(), getWidth(), getHeight(), split, + (left == null ? "null" : left.getClass().getName()), + (left == null ? 0 : left.hashCode()), + (right == null ? "null" : right.getClass().getName()), + (right == null ? 0 : right.hashCode()), + (top == null ? "null" : top.getClass().getName()), + (top == null ? 0 : top.hashCode()), + (bottom == null ? "null" : bottom.getClass().getName()), + (bottom == null ? 0 : bottom.hashCode()), + isActive(), isEnabled(), isVisible()); } // ------------------------------------------------------------------------ @@ -239,7 +338,9 @@ public class TSplitPane extends TWidget { "horizontal split pane"); } if (left == null) { - remove(this.left); + if (this.left != null) { + remove(this.left); + } this.left = null; return; } @@ -269,7 +370,9 @@ public class TSplitPane extends TWidget { "horizontal split pane"); } if (right == null) { - remove(this.right); + if (this.right != null) { + remove(this.right); + } this.right = null; return; } @@ -299,7 +402,9 @@ public class TSplitPane extends TWidget { "split pane"); } if (top == null) { - remove(this.top); + if (this.top != null) { + remove(this.top); + } this.top = null; return; } @@ -329,7 +434,9 @@ public class TSplitPane extends TWidget { "vertical split pane"); } if (bottom == null) { - remove(this.bottom); + if (this.bottom != null) { + remove(this.bottom); + } this.bottom = null; return; } @@ -339,6 +446,92 @@ public class TSplitPane extends TWidget { getHeight())); } + /** + * Remove a widget, regardless of what pane it is on. + * + * @param widget the widget to remove + */ + public void removeWidget(final TWidget widget) { + if (widget == null) { + throw new IllegalArgumentException("cannot remove null widget"); + } + if (left == widget) { + left = null; + assert(right != widget); + assert(top != widget); + assert(bottom != widget); + return; + } + if (right == widget) { + right = null; + assert(left != widget); + assert(top != widget); + assert(bottom != widget); + return; + } + if (top == widget) { + top = null; + assert(left != widget); + assert(right != widget); + assert(bottom != widget); + return; + } + if (bottom == widget) { + bottom = null; + assert(left != widget); + assert(right != widget); + assert(top != widget); + return; + } + throw new IllegalArgumentException("widget " + widget + + " not in this split"); + } + + /** + * Replace a widget, regardless of what pane it is on, with another + * widget. + * + * @param oldWidget the widget to remove + * @param newWidget the widget to replace it with + */ + public void replaceWidget(final TWidget oldWidget, + final TWidget newWidget) { + + if (oldWidget == null) { + throw new IllegalArgumentException("cannot remove null oldWidget"); + } + if (left == oldWidget) { + setLeft(newWidget); + assert(right != newWidget); + assert(top != newWidget); + assert(bottom != newWidget); + return; + } + if (right == oldWidget) { + setRight(newWidget); + assert(left != newWidget); + assert(top != newWidget); + assert(bottom != newWidget); + return; + } + if (top == oldWidget) { + setTop(newWidget); + assert(left != newWidget); + assert(right != newWidget); + assert(bottom != newWidget); + return; + } + if (bottom == oldWidget) { + setBottom(newWidget); + assert(left != newWidget); + assert(right != newWidget); + assert(top != newWidget); + return; + } + throw new IllegalArgumentException("oldWidget " + oldWidget + + " not in this split"); + } + /** * Layout the two child widgets. */ @@ -382,4 +575,68 @@ public class TSplitPane extends TWidget { layoutChildren(); } + /** + * Remove this split, removing the widget specified. + * + * @param widgetToRemove the widget to remove + * @param doClose if true, call the close() method before removing the + * child + * @return the pane that remains, or null if nothing is retained + */ + public TWidget removeSplit(final TWidget widgetToRemove, + final boolean doClose) { + + TWidget keep = null; + if (vertical) { + if ((widgetToRemove != left) && (widgetToRemove != right)) { + throw new IllegalArgumentException("widget to remove is not " + + "either of the panes in this splitpane"); + } + if (widgetToRemove == left) { + keep = right; + } else { + keep = left; + } + + } else { + if ((widgetToRemove != top) && (widgetToRemove != bottom)) { + throw new IllegalArgumentException("widget to remove is not " + + "either of the panes in this splitpane"); + } + if (widgetToRemove == top) { + keep = bottom; + } else { + keep = top; + } + } + + // Remove me from my parent widget. + TWidget myParent = getParent(); + remove(false); + + if (keep == null) { + if (myParent instanceof TSplitPane) { + // TSplitPane has a left/right/top/bottom link to me + // somewhere, remove it. + ((TSplitPane) myParent).removeWidget(this); + } + + // Nothing is left of either pane. Remove me and bail out. + return null; + } + + if (myParent instanceof TSplitPane) { + // TSplitPane has a left/right/top/bottom link to me + // somewhere, replace me with keep. + ((TSplitPane) myParent).replaceWidget(this, keep); + } else { + keep.setParent(myParent, false); + keep.setDimensions(getX(), getY(), getWidth(), getHeight()); + keep.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET, getWidth(), + getHeight())); + } + + return keep; + } + }