From fc2af49443133106c95da9aaf8b7126be8c7dedd Mon Sep 17 00:00:00 2001 From: Kevin Lamonte Date: Sat, 17 Aug 2019 20:10:55 -0500 Subject: [PATCH] #46 BoxLayoutManager working --- src/jexer/TComboBox.java | 8 +- src/jexer/TPanel.java | 69 +++++++++ src/jexer/TText.java | 22 ++- src/jexer/TWidget.java | 22 ++- src/jexer/demos/Demo7.java | 102 +++++++++++++ src/jexer/demos/Demo7.properties | 1 + src/jexer/demos/DemoCheckBoxWindow.java | 3 +- src/jexer/demos/DemoMainWindow.java | 3 +- src/jexer/demos/DemoMsgBoxWindow.java | 3 +- src/jexer/demos/DemoTextFieldWindow.java | 3 +- src/jexer/layout/BoxLayoutManager.java | 161 +++++++++++++++++++++ src/jexer/layout/StretchLayoutManager.java | 4 + 12 files changed, 388 insertions(+), 13 deletions(-) create mode 100644 src/jexer/TPanel.java create mode 100644 src/jexer/demos/Demo7.java create mode 100644 src/jexer/demos/Demo7.properties create mode 100644 src/jexer/layout/BoxLayoutManager.java diff --git a/src/jexer/TComboBox.java b/src/jexer/TComboBox.java index fe1366d..2d1b2c0 100644 --- a/src/jexer/TComboBox.java +++ b/src/jexer/TComboBox.java @@ -222,8 +222,12 @@ public class TComboBox extends TWidget { */ @Override public void setWidth(final int width) { - field.setWidth(width - 3); - list.setWidth(width); + if (field != null) { + field.setWidth(width - 3); + } + if (list != null) { + list.setWidth(width); + } super.setWidth(width); } diff --git a/src/jexer/TPanel.java b/src/jexer/TPanel.java new file mode 100644 index 0000000..1a8dab1 --- /dev/null +++ b/src/jexer/TPanel.java @@ -0,0 +1,69 @@ +/* + * Jexer - Java Text User Interface + * + * The MIT License (MIT) + * + * Copyright (C) 2019 Kevin Lamonte + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 + */ +package jexer; + +/** + * TPanel is an empty container for other widgets. + */ +public class TPanel extends TWidget { + + // ------------------------------------------------------------------------ + // Variables -------------------------------------------------------------- + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + // Constructors ----------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Public constructor. + * + * @param parent parent widget + * @param x column relative to parent + * @param y row relative to parent + * @param width width of widget + * @param height height of widget + */ + public TPanel(final TWidget parent, final int x, final int y, + final int width, final int height) { + + super(parent, x, y, width, height); + } + + // ------------------------------------------------------------------------ + // TWidget ---------------------------------------------------------------- + // ------------------------------------------------------------------------ + + + // ------------------------------------------------------------------------ + // TPanel ----------------------------------------------------------------- + // ------------------------------------------------------------------------ + + +} diff --git a/src/jexer/TText.java b/src/jexer/TText.java index e47a162..6fea16f 100644 --- a/src/jexer/TText.java +++ b/src/jexer/TText.java @@ -164,8 +164,10 @@ public class TText extends TScrollableWidget { lines = new LinkedList(); - vScroller = new TVScroller(this, getWidth() - 1, 0, getHeight() - 1); - hScroller = new THScroller(this, 0, getHeight() - 1, getWidth() - 1); + vScroller = new TVScroller(this, getWidth() - 1, 0, + Math.max(1, getHeight() - 1)); + hScroller = new THScroller(this, 0, getHeight() - 1, + Math.max(1, getWidth() - 1)); reflowData(); } @@ -181,8 +183,12 @@ public class TText extends TScrollableWidget { @Override public void setWidth(final int width) { super.setWidth(width); - hScroller.setWidth(getWidth() - 1); - vScroller.setX(getWidth() - 1); + if (hScroller != null) { + hScroller.setWidth(getWidth() - 1); + } + if (vScroller != null) { + vScroller.setX(getWidth() - 1); + } } /** @@ -194,8 +200,12 @@ public class TText extends TScrollableWidget { @Override public void setHeight(final int height) { super.setHeight(height); - hScroller.setY(getHeight() - 1); - vScroller.setHeight(getHeight() - 1); + if (hScroller != null) { + hScroller.setY(getHeight() - 1); + } + if (vScroller != null) { + vScroller.setHeight(getHeight() - 1); + } } /** diff --git a/src/jexer/TWidget.java b/src/jexer/TWidget.java index 9dd21c1..d48ffe4 100644 --- a/src/jexer/TWidget.java +++ b/src/jexer/TWidget.java @@ -577,7 +577,12 @@ public abstract class TWidget implements Comparable { width = resize.getWidth(); height = resize.getHeight(); if (layout != null) { - layout.onResize(resize); + if (this instanceof TWindow) { + layout.onResize(new TResizeEvent(TResizeEvent.Type.WIDGET, + width - 2, height - 2)); + } else { + layout.onResize(resize); + } } } else { // Let children see the screen resize @@ -2487,4 +2492,19 @@ public abstract class TWidget implements Comparable { gridRows); } + /** + * Convenience function to add a panel to this container/window. + * + * @param x column relative to parent + * @param y row relative to parent + * @param width width of text area + * @param height height of text area + * @return the new panel + */ + public final TPanel addPanel(final int x, final int y, final int width, + final int height) { + + return new TPanel(this, x, y, width, height); + } + } diff --git a/src/jexer/demos/Demo7.java b/src/jexer/demos/Demo7.java new file mode 100644 index 0000000..5f92347 --- /dev/null +++ b/src/jexer/demos/Demo7.java @@ -0,0 +1,102 @@ +/* + * Jexer - Java Text User Interface + * + * The MIT License (MIT) + * + * Copyright (C) 2019 Kevin Lamonte + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 + */ +package jexer.demos; + +import java.util.ResourceBundle; + +import jexer.TApplication; +import jexer.TPanel; +import jexer.TText; +import jexer.TWindow; +import jexer.layout.BoxLayoutManager; + +/** + * This class shows off BoxLayout and TPanel. + */ +public class Demo7 { + + /** + * Translated strings. + */ + private static final ResourceBundle i18n = ResourceBundle.getBundle(Demo7.class.getName()); + + // ------------------------------------------------------------------------ + // Demo7 ------------------------------------------------------------------ + // ------------------------------------------------------------------------ + + /** + * Main entry point. + * + * @param args Command line arguments + */ + public static void main(final String [] args) throws Exception { + // This demo will build everything "from the outside". + + // Swing is the default backend on Windows unless explicitly + // overridden by jexer.Swing. + TApplication.BackendType backendType = TApplication.BackendType.XTERM; + if (System.getProperty("os.name").startsWith("Windows")) { + backendType = TApplication.BackendType.SWING; + } + if (System.getProperty("os.name").startsWith("Mac")) { + backendType = TApplication.BackendType.SWING; + } + if (System.getProperty("jexer.Swing") != null) { + if (System.getProperty("jexer.Swing", "false").equals("true")) { + backendType = TApplication.BackendType.SWING; + } else { + backendType = TApplication.BackendType.XTERM; + } + } + TApplication app = new TApplication(backendType); + app.addToolMenu(); + app.addFileMenu(); + TWindow window = new TWindow(app, i18n.getString("windowTitle"), + 60, 22); + window.setLayoutManager(new BoxLayoutManager(window.getWidth() - 2, + window.getHeight() - 2, false)); + + TPanel right = window.addPanel(0, 0, 10, 10); + TPanel left = window.addPanel(0, 0, 10, 10); + right.setLayoutManager(new BoxLayoutManager(right.getWidth(), + right.getHeight(), true)); + left.setLayoutManager(new BoxLayoutManager(left.getWidth(), + left.getHeight(), true)); + + left.addText("C1", 0, 0, left.getWidth(), left.getHeight()); + left.addText("C2", 0, 0, left.getWidth(), left.getHeight()); + left.addText("C3", 0, 0, left.getWidth(), left.getHeight()); + right.addText("C4", 0, 0, right.getWidth(), right.getHeight()); + right.addText("C5", 0, 0, right.getWidth(), right.getHeight()); + right.addText("C6", 0, 0, right.getWidth(), right.getHeight()); + + app.run(); + } + +} diff --git a/src/jexer/demos/Demo7.properties b/src/jexer/demos/Demo7.properties new file mode 100644 index 0000000..e6fd7ee --- /dev/null +++ b/src/jexer/demos/Demo7.properties @@ -0,0 +1 @@ +windowTitle=BoxLayoutManager Demo diff --git a/src/jexer/demos/DemoCheckBoxWindow.java b/src/jexer/demos/DemoCheckBoxWindow.java index aa29506..fda7bd7 100644 --- a/src/jexer/demos/DemoCheckBoxWindow.java +++ b/src/jexer/demos/DemoCheckBoxWindow.java @@ -88,7 +88,8 @@ public class DemoCheckBoxWindow extends TWindow { // centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 60, 17, flags); - setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + setLayoutManager(new StretchLayoutManager(getWidth() - 2, + getHeight() - 2)); int row = 1; diff --git a/src/jexer/demos/DemoMainWindow.java b/src/jexer/demos/DemoMainWindow.java index 1c8b4fb..0be7088 100644 --- a/src/jexer/demos/DemoMainWindow.java +++ b/src/jexer/demos/DemoMainWindow.java @@ -109,7 +109,8 @@ public class DemoMainWindow extends TWindow { // centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 64, 23, flags); - setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + setLayoutManager(new StretchLayoutManager(getWidth() - 2, + getHeight() - 2)); int row = 1; diff --git a/src/jexer/demos/DemoMsgBoxWindow.java b/src/jexer/demos/DemoMsgBoxWindow.java index 7d106c7..0485f51 100644 --- a/src/jexer/demos/DemoMsgBoxWindow.java +++ b/src/jexer/demos/DemoMsgBoxWindow.java @@ -74,7 +74,8 @@ public class DemoMsgBoxWindow extends TWindow { // will be centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 64, 18, flags); - setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + setLayoutManager(new StretchLayoutManager(getWidth() - 2, + getHeight() - 2)); int row = 1; diff --git a/src/jexer/demos/DemoTextFieldWindow.java b/src/jexer/demos/DemoTextFieldWindow.java index 6e6b330..2c6116a 100644 --- a/src/jexer/demos/DemoTextFieldWindow.java +++ b/src/jexer/demos/DemoTextFieldWindow.java @@ -101,7 +101,8 @@ public class DemoTextFieldWindow extends TWindow { // will be centered on screen. super(parent, i18n.getString("windowTitle"), 0, 0, 60, 20, flags); - setLayoutManager(new StretchLayoutManager(getWidth(), getHeight())); + setLayoutManager(new StretchLayoutManager(getWidth() - 2, + getHeight() - 2)); int row = 1; diff --git a/src/jexer/layout/BoxLayoutManager.java b/src/jexer/layout/BoxLayoutManager.java new file mode 100644 index 0000000..c3d1280 --- /dev/null +++ b/src/jexer/layout/BoxLayoutManager.java @@ -0,0 +1,161 @@ +/* + * Jexer - Java Text User Interface + * + * The MIT License (MIT) + * + * Copyright (C) 2019 Kevin Lamonte + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * @author Kevin Lamonte [kevin.lamonte@gmail.com] + * @version 1 + */ +package jexer.layout; + +import java.util.ArrayList; + +import jexer.TWidget; +import jexer.event.TResizeEvent; + +/** + * BoxLayoutManager repositions child widgets based on the order they are + * added to the parent widget and desired orientation. + */ +public class BoxLayoutManager implements LayoutManager { + + // ------------------------------------------------------------------------ + // Variables -------------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * If true, orient vertically. If false, orient horizontally. + */ + private boolean vertical = true; + + /** + * Current width. + */ + private int width = 0; + + /** + * Current height. + */ + private int height = 0; + + /** + * Widgets being managed. + */ + private ArrayList children = new ArrayList(); + + // ------------------------------------------------------------------------ + // Constructors ----------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Public constructor. + * + * @param width the width of the parent widget + * @param height the height of the parent widget + * @param vertical if true, arrange widgets vertically + */ + public BoxLayoutManager(final int width, final int height, + final boolean vertical) { + + this.width = width; + this.height = height; + this.vertical = vertical; + } + + // ------------------------------------------------------------------------ + // LayoutManager ---------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Process the parent widget's resize event, and resize/reposition child + * widgets. + * + * @param resize resize event + */ + public void onResize(final TResizeEvent resize) { + if (resize.getType() == TResizeEvent.Type.WIDGET) { + width = resize.getWidth(); + height = resize.getHeight(); + layoutChildren(); + } + } + + /** + * Add a child widget to manage. + * + * @param child the widget to manage + */ + public void add(final TWidget child) { + children.add(child); + layoutChildren(); + } + + /** + * Remove a child widget from those managed by this LayoutManager. + * + * @param child the widget to remove + */ + public void remove(final TWidget child) { + children.remove(child); + layoutChildren(); + } + + // ------------------------------------------------------------------------ + // BoxLayoutManager ------------------------------------------------------- + // ------------------------------------------------------------------------ + + /** + * Resize/reposition child widgets based on horizontal/vertical + * arrangement. + */ + public void layoutChildren() { + if (children.size() == 0) { + return; + } + if (vertical) { + int widgetHeight = Math.max(1, height / children.size()); + int leftoverHeight = height % children.size(); + for (int i = 0; i < children.size() - 1; i++) { + TWidget child = children.get(i); + child.setDimensions(child.getX(), i * widgetHeight, + width, widgetHeight); + } + TWidget child = children.get(children.size() - 1); + child.setDimensions(child.getX(), + (children.size() - 1) * widgetHeight, width, + widgetHeight + leftoverHeight); + } else { + int widgetWidth = Math.max(1, width / children.size()); + int leftoverWidth = width % children.size(); + for (int i = 0; i < children.size() - 1; i++) { + TWidget child = children.get(i); + child.setDimensions(i * widgetWidth, child.getY(), + widgetWidth, height); + } + TWidget child = children.get(children.size() - 1); + child.setDimensions((children.size() - 1) * widgetWidth, + child.getY(), widgetWidth + leftoverWidth, height); + } + } + +} diff --git a/src/jexer/layout/StretchLayoutManager.java b/src/jexer/layout/StretchLayoutManager.java index 3dd7452..0ae7dff 100644 --- a/src/jexer/layout/StretchLayoutManager.java +++ b/src/jexer/layout/StretchLayoutManager.java @@ -82,6 +82,8 @@ public class StretchLayoutManager implements LayoutManager { public StretchLayoutManager(final int width, final int height) { originalWidth = width; originalHeight = height; + this.width = width; + this.height = height; } // ------------------------------------------------------------------------ @@ -111,6 +113,7 @@ public class StretchLayoutManager implements LayoutManager { Rectangle rect = new Rectangle(child.getX(), child.getY(), child.getWidth(), child.getHeight()); children.put(child, rect); + layoutChildren(); } /** @@ -120,6 +123,7 @@ public class StretchLayoutManager implements LayoutManager { */ public void remove(final TWidget child) { children.remove(child); + layoutChildren(); } // ------------------------------------------------------------------------ -- 2.27.0