#51 wip
authorKevin Lamonte <kevin.lamonte@gmail.com>
Wed, 21 Aug 2019 18:29:56 +0000 (13:29 -0500)
committerKevin Lamonte <kevin.lamonte@gmail.com>
Wed, 21 Aug 2019 18:29:56 +0000 (13:29 -0500)
examples/JexerTilingWindowManager2.java
src/jexer/TSplitPane.java
src/jexer/TWidget.java
src/jexer/TWindow.java

index cb7f0d0263659a4be295d7c0397f3836ce0d3098..accbf739317bf0212c1c7aa07c6fb2e934b84b11 100644 (file)
@@ -88,12 +88,13 @@ public class JexerTilingWindowManager2 extends TApplication {
     protected boolean onMenu(TMenuEvent event) {
         if (event.getId() == MENU_SPLIT_VERTICAL) {
             if (root == null) {
+                assert (getDesktop().getActiveChild() == null);
                 createRootTerminal();
                 return true;
             }
-            TWidget active = root.getActiveChild();
+            TWidget active = getDesktop().getActiveChild();
             TSplitPane split = active.splitVertical(false,
-                new TTerminalWidget(getDesktop(), active.getX(),
+                new TTerminalWidget(active, active.getX(),
                     active.getY(), active.getWidth(), active.getHeight(),
                     new TAction() {
                         public void DO() {
@@ -106,20 +107,22 @@ public class JexerTilingWindowManager2 extends TApplication {
                             }
                         }
                     }));
-
             if (active == root) {
                 root = split;
             }
+            System.err.println("\nAfter vertical split:");
+            System.err.println(getDesktop().toPrettyString());
             return true;
         }
         if (event.getId() == MENU_SPLIT_HORIZONTAL) {
             if (root == null) {
+                assert (getDesktop().getActiveChild() == null);
                 createRootTerminal();
                 return true;
             }
-            TWidget active = root.getActiveChild();
+            TWidget active = getDesktop().getActiveChild();
             TSplitPane split = active.splitHorizontal(false,
-                new TTerminalWidget(getDesktop(), active.getX(),
+                new TTerminalWidget(active, active.getX(),
                     active.getY(), active.getWidth(), active.getHeight(),
                     new TAction() {
                         public void DO() {
@@ -132,6 +135,11 @@ public class JexerTilingWindowManager2 extends TApplication {
                             }
                         }
                     }));
+            if (active == root) {
+                root = split;
+            }
+            System.err.println("\nAfter horizontal split:");
+            System.err.println(getDesktop().toPrettyString());
             return true;
         }
 
index b63ea1fbd06fd8805b3c7e3e27d654f59a3dfaf3..5a65736add6ae1296860c7306295cc45bbfb8d09 100644 (file)
@@ -124,6 +124,8 @@ public class TSplitPane extends TWidget {
             // Resize me
             super.onResize(event);
 
+            // System.err.println("onResize(): " + toString());
+
             if (vertical && (split >= getWidth() - 2)) {
                 center();
             } else if (!vertical && (split >= getHeight() - 2)) {
@@ -147,9 +149,9 @@ public class TSplitPane extends TWidget {
 
         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;
@@ -170,6 +172,9 @@ public class TSplitPane extends TWidget {
         this.mouse = mouse;
 
         if (inSplitMove && mouse.isMouse1()) {
+            // DEBUG
+            // System.err.println(toPrettyString());
+
             // Stop moving split
             inSplitMove = false;
             return;
@@ -199,10 +204,10 @@ public class TSplitPane extends TWidget {
 
         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();
@@ -251,6 +256,29 @@ public class TSplitPane extends TWidget {
 
     }
 
+    /**
+     * 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());
+    }
+
     // ------------------------------------------------------------------------
     // TSplitPane -------------------------------------------------------------
     // ------------------------------------------------------------------------
@@ -383,33 +411,126 @@ 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.
      */
     private void layoutChildren() {
+
+        // System.err.println("layoutChildren(): " + toString());
+
         if (vertical) {
             if (left != null) {
                 left.setDimensions(0, 0, split, getHeight());
                 left.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
                         left.getWidth(), left.getHeight()));
+                // System.err.println("   move/size left: " + left.toString());
             }
             if (right != null) {
                 right.setDimensions(split + 1, 0, getWidth() - split - 1,
                     getHeight());
                 right.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
                         right.getWidth(), right.getHeight()));
+                // System.err.println("   move/size right: " + right.toString());
             }
         } else {
             if (top != null) {
                 top.setDimensions(0, 0, getWidth(), split);
                 top.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
                         top.getWidth(), top.getHeight()));
+                // System.err.println("   move/size top: " + top.toString());
             }
             if (bottom != null) {
                 bottom.setDimensions(0, split + 1, getWidth(),
                     getHeight() - split - 1);
                 bottom.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
                         bottom.getWidth(), bottom.getHeight()));
+                // System.err.println("   move/size bottom: " + bottom.toString());
             }
         }
     }
@@ -462,7 +583,7 @@ public class TSplitPane extends TWidget {
         }
 
         // Remove me from my parent widget.
-        TWidget newParent = getParent();
+        TWidget myParent = getParent();
         remove(false);
 
         if (keep == null) {
@@ -470,7 +591,7 @@ public class TSplitPane extends TWidget {
             return null;
         }
 
-        keep.setParent(newParent, false);
+        keep.setParent(myParent, false);
         keep.setDimensions(getX(), getY(), getWidth(), getHeight());
         keep.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET, getWidth(),
                 getHeight()));
index 6994e6fd3d0f61ae618df0f4730ceb836bbcd4c7..5d2612b3092e961d82ad8b6beea94ce93a20d15d 100644 (file)
@@ -933,10 +933,10 @@ public abstract class TWidget implements Comparable<TWidget> {
     public final void setDimensions(final int x, final int y, final int width,
         final int height) {
 
-        setX(x);
-        setY(y);
-        setWidth(width);
-        setHeight(height);
+        this.x = x;
+        this.y = y;
+        this.width = width;
+        this.height = height;
         if (layout != null) {
             layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET,
                     width, height));
@@ -1560,16 +1560,20 @@ public abstract class TWidget implements Comparable<TWidget> {
         final TWidget newWidget) {
 
         TSplitPane splitPane = new TSplitPane(null, x, y, width, height, true);
-        List<TWidget> widgets = new ArrayList<TWidget>(children);
         TWidget myParent = parent;
         remove(false);
+        if (myParent instanceof TSplitPane) {
+            // TSplitPane has a left/right/top/bottom link to me somewhere,
+            // replace it with a link to splitPane.
+            ((TSplitPane) myParent).replaceWidget(this, splitPane);
+        }
         splitPane.setParent(myParent, false);
         if (newWidgetOnLeft) {
             splitPane.setLeft(newWidget);
             splitPane.setRight(this);
         } else {
-            splitPane.setRight(newWidget);
             splitPane.setLeft(this);
+            splitPane.setRight(newWidget);
         }
         splitPane.activate();
         if (newWidget != null) {
@@ -1577,15 +1581,20 @@ public abstract class TWidget implements Comparable<TWidget> {
         } else {
             activate();
         }
+
         assert (parent != null);
         assert (window != null);
-        for (TWidget w: widgets) {
-            assert (w.window != null);
-            assert (w.parent != null);
-        }
         assert (splitPane.getWindow() != null);
         assert (splitPane.getParent() != null);
         assert (splitPane.isActive() == true);
+        assert (parent == splitPane);
+        if (newWidget != null) {
+            assert (newWidget.parent == parent);
+            assert (newWidget.active == true);
+            assert (active == false);
+        } else {
+            assert (active == true);
+        }
         return splitPane;
     }
 
@@ -1603,16 +1612,20 @@ public abstract class TWidget implements Comparable<TWidget> {
         final TWidget newWidget) {
 
         TSplitPane splitPane = new TSplitPane(null, x, y, width, height, false);
-        List<TWidget> widgets = new ArrayList<TWidget>(children);
         TWidget myParent = parent;
         remove(false);
+        if (myParent instanceof TSplitPane) {
+            // TSplitPane has a left/right/top/bottom link to me somewhere,
+            // replace it with a link to splitPane.
+            ((TSplitPane) myParent).replaceWidget(this, splitPane);
+        }
         splitPane.setParent(myParent, false);
         if (newWidgetOnTop) {
             splitPane.setTop(newWidget);
             splitPane.setBottom(this);
         } else {
-            splitPane.setBottom(newWidget);
             splitPane.setTop(this);
+            splitPane.setBottom(newWidget);
         }
         splitPane.activate();
         if (newWidget != null) {
@@ -1620,18 +1633,69 @@ public abstract class TWidget implements Comparable<TWidget> {
         } else {
             activate();
         }
+
         assert (parent != null);
         assert (window != null);
-        for (TWidget w: widgets) {
-            assert (w.window != null);
-            assert (w.parent != null);
-        }
         assert (splitPane.getWindow() != null);
         assert (splitPane.getParent() != null);
         assert (splitPane.isActive() == true);
+        assert (parent == splitPane);
+        if (newWidget != null) {
+            assert (newWidget.parent == parent);
+            assert (newWidget.active == true);
+            assert (active == false);
+        } else {
+            assert (active == true);
+        }
         return splitPane;
     }
 
+    /**
+     * Generate a human-readable string for this widget.
+     *
+     * @return a human-readable string
+     */
+    @Override
+    public String toString() {
+        return String.format("%s(%8x) position (%d, %d) geometry %dx%d " +
+            "active %s enabled %s visible %s", getClass().getName(),
+            hashCode(), x, y, width, height, active, enabled, visible);
+    }
+
+    /**
+     * Generate a string for this widget's hierarchy.
+     *
+     * @param prefix a prefix to use for this widget's place in the hierarchy
+     * @return a pretty-printable string of this hierarchy
+     */
+    protected String toPrettyString(final String prefix) {
+        StringBuilder sb = new StringBuilder(prefix);
+        sb.append(toString());
+        String newPrefix = "";
+        for (int i = 0; i < prefix.length(); i++) {
+            newPrefix += " ";
+        }
+        for (int i = 0; i < children.size(); i++) {
+            TWidget child= children.get(i);
+            sb.append("\n");
+            if (i == children.size() - 1) {
+                sb.append(child.toPrettyString(newPrefix + " \u2514\u2500"));
+            } else {
+                sb.append(child.toPrettyString(newPrefix + " \u251c\u2500"));
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Generate a string for this widget's hierarchy.
+     *
+     * @return a pretty-printable string of this hierarchy
+     */
+    public String toPrettyString() {
+        return toPrettyString("");
+    }
+
     // ------------------------------------------------------------------------
     // Passthru for Screen functions ------------------------------------------
     // ------------------------------------------------------------------------
index 6763df3063640e5e2504dfa34d2e6f5bf6997b43..e0a20734341f3f19405810df7ad3595ff3058a25 100644 (file)
@@ -1431,4 +1431,16 @@ public class TWindow extends TWidget {
         this.hideMouse = hideMouse;
     }
 
+    /**
+     * Generate a human-readable string for this window.
+     *
+     * @return a human-readable string
+     */
+    @Override
+    public String toString() {
+        return String.format("%s(%8x) \'%s\' position (%d, %d) geometry %dx%d" +
+            " hidden %s modal %s", getClass().getName(), hashCode(), title,
+            getX(), getY(), getWidth(), getHeight(), hidden, isModal());
+    }
+
 }