diff --git a/src/main/java/edu/unl/cse/bohn/StringBox.java b/src/main/java/edu/unl/cse/bohn/StringBox.java index 1f6a00413cfe66f405cc21a10923b00ef4ebc2f7..7847fdab8ec050bb26c4eaa8b1f2dcfb35630b2b 100644 --- a/src/main/java/edu/unl/cse/bohn/StringBox.java +++ b/src/main/java/edu/unl/cse/bohn/StringBox.java @@ -4,6 +4,22 @@ package edu.unl.cse.bohn; +/** + * <p>A very simple terminal-based display. Can be used to place arbitrary strings in arbitrary locations in a terminal + * window. StringBox will <i>not</i> redraw the screen. Instead, it will produce a string that, when printed, will fill + * the screen, causing the screen's previous contents to scroll off of the screen.</p> + * + * <p>A typical usage is:</p> + * <pre><code> + * StringBox stringBox = new StringBox(); + * String screen = stringBox + * .placeString(...) + * ⋮ + * .placeString(...) + * .toString(); + * System.out.println(screen); + * </code></pre> + */ public class StringBox { private int maximumWidth; private int maximumHeight; @@ -11,10 +27,31 @@ public class StringBox { private StringRow[] rows; + /** + * <p>Produces a StringBox suitably-sized for a standard 24x80 terminal. The StringBox will be 23x80; if the string + * is printed with <code>System.out.println()</code> then it will leave the cursor on the 24th line, where the + * user can enter their input without scrolling the top of the string off the screen.</p> + * + * <p>Alternatively, you might create a 24x80 StringBox using {@link #StringBox(int, int)}. If the string is printed + * with <code>System.out.print()</code> then it will leave the cursor at the end of the 24th line without scrolling + * the top of the string off of the screen. This particular style would be useful if you place the prompt on the + * 24th line.</p> + */ public StringBox() { this(23, 80); // standard terminal is 24x80, but leave room for the user's input } + /** + * <p>Produces an arbitrarily-sized StringBox. The StringBox should be no wider than your terminal and should be + * at least one line shorter than your terminal. If the string is printed with <code>System.out.println()</code> + * then it will leave the cursor on the last line, where the user can enter their input without scrolling the top + * of the string off the screen.</p> + * + * <p>Alternatively, you might create a StringBox whose height is the height of your terminal. If the string is + * printed with <code>System.out.print()</code> then it will leave the cursor at the end of the last line without + * scrolling the top of the string off of the screen. This particular style would be useful if you place the + * prompt on the last line.</p> + */ public StringBox(int maximumHeight, int maximumWidth) { if (maximumHeight > 0 && maximumWidth > 0) { this.maximumHeight = maximumHeight; @@ -30,10 +67,34 @@ public class StringBox { } } + /** + * <p>Places a string in the StringBox with its upper-left corner in the specified location. If the string + * contains multiple lines, each line after the first will be placed in the row subsequent to the previous line, + * and the lines will be left-justified. Any portions of the string that would be placed outside the StringBox's + * defined boundaries will be silently truncated.</p> + * + * <p>Equivalent to {@link #placeStringAlignTopLeft(String, int, int)}</p> + * + * @param string the string to be placed in the StringBox + * @param topRow the row on which the first line of the string should be placed + * @param leftColumn the column in which the first character of each row should be placed + * @return the current StringBox object, suitable for chained calls + */ public StringBox placeString(String string, int topRow, int leftColumn) { return placeStringAlignTopLeft(string, topRow, leftColumn); } + /** + * Places a string in the StringBox with its upper-left corner in the specified location. If the string + * contains multiple lines, each line after the first will be placed in the row subsequent to the previous line, + * and the lines will be left-justified. Any portions of the string that would be placed outside the StringBox's + * defined boundaries will be silently truncated. + * + * @param string the string to be placed in the StringBox + * @param topRow the row on which the first line of the string should be placed + * @param leftColumn the column in which the first character of each row should be placed + * @return the current StringBox object, suitable for chained calls + */ public StringBox placeStringAlignTopLeft(String string, int topRow, int leftColumn) { String[] strings = string.split("\n"); int firstRow = Math.max(topRow, 0); @@ -46,26 +107,59 @@ public class StringBox { return this; } + /** + * Places a string in the StringBox with its lower-left corner in the specified location. If the string + * contains multiple lines, each line before the last will be placed in the row previous to the subsequent line, + * and the lines will be left-justified. Any portions of the string that would be placed outside the StringBox's + * defined boundaries will be silently truncated. + * + * @param string the string to be placed in the StringBox + * @param bottomRow the row on which the last line of the string should be placed + * @param leftColumn the column in which the first character of each row should be placed + * @return the current StringBox object, suitable for chained calls + */ public StringBox placeStringAlignBottomLeft(String string, int bottomRow, int leftColumn) { String[] strings = string.split("\n"); return placeStringAlignTopLeft(string, bottomRow - strings.length + 1, leftColumn); } - public StringBox placeStringAlignTopRight(String string, int topRow, int leftColumn) { + /** + * Places a string in the StringBox with its upper-right corner in the specified location. If the string + * contains multiple lines, each line after the first will be placed in the row subsequent to the previous line, + * and the lines will be right-justified. Any portions of the string that would be placed outside the StringBox's + * defined boundaries will be silently truncated. + * + * @param string the string to be placed in the StringBox + * @param topRow the row on which the first line of the string should be placed + * @param rightColumn the column in which the last character of each row should be placed + * @return the current StringBox object, suitable for chained calls + */ + public StringBox placeStringAlignTopRight(String string, int topRow, int rightColumn) { String[] strings = string.split("\n"); int firstRow = Math.max(topRow, 0); int lastRow = Math.min(topRow + strings.length, maximumHeight); int offset = -topRow; for (int i = firstRow; i < lastRow; i++) { - rows[i].placeSubstringAlignRight(strings[i + offset], leftColumn); + rows[i].placeSubstringAlignRight(strings[i + offset], rightColumn); } logicalHeight = Math.max(logicalHeight, lastRow); return this; } - public StringBox placeStringAlignBottomRight(String string, int bottomRow, int leftColumn) { + /** + * Places a string in the StringBox with its lower-right corner in the specified location. If the string + * contains multiple lines, each line before the last will be placed in the row previous to the subsequent line, + * and the lines will be right-justified. Any portions of the string that would be placed outside the StringBox's + * defined boundaries will be silently truncated. + * + * @param string the string to be placed in the StringBox + * @param bottomRow the row on which the last line of the string should be placed + * @param rightColumn the column in which the first character of each row should be placed + * @return the current StringBox object, suitable for chained calls + */ + public StringBox placeStringAlignBottomRight(String string, int bottomRow, int rightColumn) { String[] strings = string.split("\n"); - return placeStringAlignTopRight(string, bottomRow - strings.length + 1, leftColumn); + return placeStringAlignTopRight(string, bottomRow - strings.length + 1, rightColumn); } @Override @@ -73,6 +167,16 @@ public class StringBox { return toString(false); } + /** + * <p>Generates the string that the client code produced by calling {@link #placeString(String, int, int)} and + * its related methods. If this method's argument is <code>true</code>, then any unused lines between the last line + * of text and the bottom of the StringBox will be filled with newLines so that when the string is printed, the + * previous string will fully scroll off of the screen. If the argument is <code>false</code>, then the returned + * string will stop after the last line of text.</p> + * + * @param padToHeight indicates whether newlines should be placed after the last line of text + * @return the string built by calls to {@link #placeString(String, int, int)} and its related methods + */ public String toString(boolean padToHeight) { StringBuilder returnString = new StringBuilder(maximumHeight * (maximumWidth + 1)); if (logicalHeight > 0) { @@ -89,6 +193,9 @@ public class StringBox { return returnString.toString(); } + /** + * A helper inner class. Client code should not directly access StringRow objects. + */ static class StringRow { private StringBuilder stringBuilder; private int maximumWidth;