X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTText.java;h=f6d7febcc0aefdcd159aa3e5af50d72f1631be0f;hb=505be508ae7d3fb48122be548b310a238cfb91eb;hp=6d2fe27faaf6e3ae9652761acd52e9c7ea8d1830;hpb=a83fea2bae838f4b9bbf59ce3832e0e67be41378;p=fanfix.git diff --git a/src/jexer/TText.java b/src/jexer/TText.java index 6d2fe27..f6d7feb 100644 --- a/src/jexer/TText.java +++ b/src/jexer/TText.java @@ -1,72 +1,114 @@ -/** +/* * Jexer - Java Text User Interface * - * License: LGPLv3 or later - * - * This module is licensed under the GNU Lesser General Public License - * Version 3. Please see the file "COPYING" in this directory for more - * information about the GNU Lesser General Public License Version 3. + * The MIT License (MIT) * - * Copyright (C) 2015 Kevin Lamonte + * Copyright (C) 2019 Kevin Lamonte * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 3 of - * the License, or (at your option) any later version. + * 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: * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see - * http://www.gnu.org/licenses/, or write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA + * 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; -import java.util.LinkedList; +import java.util.Arrays; +import java.util.ArrayList; import java.util.List; import jexer.bits.CellAttributes; +import jexer.bits.StringUtils; import jexer.event.TKeypressEvent; import jexer.event.TMouseEvent; -import static jexer.TKeypress.*; +import static jexer.TKeypress.kbDown; +import static jexer.TKeypress.kbEnd; +import static jexer.TKeypress.kbHome; +import static jexer.TKeypress.kbLeft; +import static jexer.TKeypress.kbPgDn; +import static jexer.TKeypress.kbPgUp; +import static jexer.TKeypress.kbRight; +import static jexer.TKeypress.kbUp; /** - * TText implements a simple text windget. + * TText implements a simple scrollable text area. It reflows automatically on + * resize. */ -public final class TText extends TWidget { +public class TText extends TScrollableWidget { + + // ------------------------------------------------------------------------ + // Constants -------------------------------------------------------------- + // ------------------------------------------------------------------------ /** - * Text to display. + * Available text justifications. */ - private String text; + public enum Justification { + + /** + * Not justified at all, use spacing as provided by the client. + */ + NONE, + + /** + * Left-justified text. + */ + LEFT, + + /** + * Centered text. + */ + CENTER, + + /** + * Right-justified text. + */ + RIGHT, + + /** + * Fully-justified text. + */ + FULL, + } + + // ------------------------------------------------------------------------ + // Variables -------------------------------------------------------------- + // ------------------------------------------------------------------------ /** - * Text converted to lines. + * How to justify the text. */ - private List lines; + private Justification justification = Justification.LEFT; /** - * Text color. + * Text to display. */ - private String colorKey; + private String text; /** - * Vertical scrollbar. + * Text converted to lines. */ - private TVScroller vScroller; + private List lines; /** - * Horizontal scrollbar. + * Text color. */ - private THScroller hScroller; + private String colorKey; /** * Maximum width of a single line. @@ -78,138 +120,9 @@ public final class TText extends TWidget { */ private int lineSpacing = 1; - /** - * Convenience method used by TWindowLoggerOutput. - * - * @param line new line to add - */ - public void addLine(final String line) { - if (text.length() == 0) { - text = line; - } else { - text += "\n\n"; - text += line; - } - reflow(); - } - - /** - * Recompute the bounds for the scrollbars. - */ - private void computeBounds() { - maxLineWidth = 0; - for (String line: lines) { - if (line.length() > maxLineWidth) { - maxLineWidth = line.length(); - } - } - - vScroller.setBottomValue(lines.size() - getHeight() + 1); - if (vScroller.getBottomValue() < 0) { - vScroller.setBottomValue(0); - } - if (vScroller.getValue() > vScroller.getBottomValue()) { - vScroller.setValue(vScroller.getBottomValue()); - } - - hScroller.setRightValue(maxLineWidth - getWidth() + 1); - if (hScroller.getRightValue() < 0) { - hScroller.setRightValue(0); - } - if (hScroller.getValue() > hScroller.getRightValue()) { - hScroller.setValue(hScroller.getRightValue()); - } - } - - /** - * Insert newlines into a string to wrap it to a maximum column. - * Terminate the final string with a newline. Note that interior - * newlines are converted to spaces. - * - * @param str the string - * @param n the maximum number of characters in a line - * @return the wrapped string - */ - private String wrap(final String str, final int n) { - assert (n > 0); - - StringBuilder sb = new StringBuilder(); - StringBuilder word = new StringBuilder(); - int col = 0; - for (int i = 0; i < str.length(); i++) { - char ch = str.charAt(i); - if (ch == '\n') { - ch = ' '; - } - if (ch == ' ') { - sb.append(word.toString()); - sb.append(ch); - if (word.length() >= n - 1) { - sb.append('\n'); - col = 0; - } - word = new StringBuilder(); - } else { - word.append(ch); - } - - col++; - if (col >= n - 1) { - sb.append('\n'); - col = 0; - } - } - sb.append(word.toString()); - sb.append('\n'); - return sb.toString(); - } - - - /** - * Resize text and scrollbars for a new width/height. - */ - public void reflow() { - // Reset the lines - lines.clear(); - - // Break up text into paragraphs - String [] paragraphs = text.split("\n\n"); - for (String p: paragraphs) { - String paragraph = wrap(p, getWidth() - 1); - for (String line: paragraph.split("\n")) { - lines.add(line); - } - for (int i = 0; i < lineSpacing; i++) { - lines.add(""); - } - } - - // Start at the top - if (vScroller == null) { - vScroller = new TVScroller(this, getWidth() - 1, 0, - getHeight() - 1); - vScroller.setTopValue(0); - vScroller.setValue(0); - } else { - vScroller.setX(getWidth() - 1); - vScroller.setHeight(getHeight() - 1); - } - vScroller.setBigChange(getHeight() - 1); - - // Start at the left - if (hScroller == null) { - hScroller = new THScroller(this, 0, getHeight() - 1, - getWidth() - 1); - hScroller.setLeftValue(0); - hScroller.setValue(0); - } else { - hScroller.setY(getHeight() - 1); - hScroller.setWidth(getWidth() - 1); - } - hScroller.setBigChange(getWidth() - 1); - - computeBounds(); - } + // ------------------------------------------------------------------------ + // Constructors ----------------------------------------------------------- + // ------------------------------------------------------------------------ /** * Public constructor. @@ -222,7 +135,7 @@ public final class TText extends TWidget { * @param height height of text area */ public TText(final TWidget parent, final String text, final int x, - final int y, final int width, final int height) { + final int y, final int width, final int height) { this(parent, text, x, y, width, height, "ttext"); } @@ -236,11 +149,12 @@ public final class TText extends TWidget { * @param y row relative to parent * @param width width of text area * @param height height of text area - * @param colorKey ColorTheme key color to use for foreground text. - * Default is "ttext" + * @param colorKey ColorTheme key color to use for foreground + * text. Default is "ttext". */ public TText(final TWidget parent, final String text, final int x, - final int y, final int width, final int height, final String colorKey) { + final int y, final int width, final int height, + final String colorKey) { // Set parent and window super(parent, x, y, width, height); @@ -248,9 +162,50 @@ public final class TText extends TWidget { this.text = text; this.colorKey = colorKey; - lines = new LinkedList(); + lines = new ArrayList(); + + 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(); + } - reflow(); + // ------------------------------------------------------------------------ + // TScrollableWidget ------------------------------------------------------ + // ------------------------------------------------------------------------ + + /** + * Override TWidget's width: we need to set child widget widths. + * + * @param width new widget width + */ + @Override + public void setWidth(final int width) { + super.setWidth(width); + if (hScroller != null) { + hScroller.setWidth(getWidth() - 1); + } + if (vScroller != null) { + vScroller.setX(getWidth() - 1); + } + } + + /** + * Override TWidget's height: we need to set child widget heights. + * time. + * + * @param height new widget height + */ + @Override + public void setHeight(final int height) { + super.setHeight(height); + if (hScroller != null) { + hScroller.setY(getHeight() - 1); + } + if (vScroller != null) { + vScroller.setHeight(getHeight() - 1); + } } /** @@ -265,24 +220,25 @@ public final class TText extends TWidget { int topY = 0; for (int i = begin; i < lines.size(); i++) { String line = lines.get(i); - if (hScroller.getValue() < line.length()) { + if (hScroller.getValue() < StringUtils.width(line)) { line = line.substring(hScroller.getValue()); } else { line = ""; } - String formatString = "%-" + Integer.toString(getWidth() - 1) + "s"; - getScreen().putStrXY(0, topY, String.format(formatString, line), - color); + if (getWidth() > 3) { + String formatString = "%-" + Integer.toString(getWidth() - 1) + "s"; + putStringXY(0, topY, String.format(formatString, line), color); + } topY++; - if (topY >= getHeight() - 1) { + if (topY >= (getHeight() - 1)) { break; } } // Pad the rest with blank lines - for (int i = topY; i < getHeight() - 1; i++) { - getScreen().hLineXY(0, i, getWidth() - 1, ' ', color); + for (int i = topY; i < (getHeight() - 1); i++) { + hLineXY(0, i, getWidth() - 1, ' ', color); } } @@ -294,11 +250,11 @@ public final class TText extends TWidget { */ @Override public void onMouseDown(final TMouseEvent mouse) { - if (mouse.getMouseWheelUp()) { + if (mouse.isMouseWheelUp()) { vScroller.decrement(); return; } - if (mouse.getMouseWheelDown()) { + if (mouse.isMouseWheelDown()) { vScroller.increment(); return; } @@ -336,4 +292,162 @@ public final class TText extends TWidget { } } + /** + * Resize text and scrollbars for a new width/height. + */ + @Override + public void reflowData() { + // Reset the lines + lines.clear(); + + // Break up text into paragraphs + String[] paragraphs = text.split("\n\n"); + for (String p : paragraphs) { + switch (justification) { + case NONE: + lines.addAll(Arrays.asList(p.split("\n"))); + break; + case LEFT: + lines.addAll(jexer.bits.StringUtils.left(p, + getWidth() - 1)); + break; + case CENTER: + lines.addAll(jexer.bits.StringUtils.center(p, + getWidth() - 1)); + break; + case RIGHT: + lines.addAll(jexer.bits.StringUtils.right(p, + getWidth() - 1)); + break; + case FULL: + lines.addAll(jexer.bits.StringUtils.full(p, + getWidth() - 1)); + break; + } + + for (int i = 0; i < lineSpacing; i++) { + lines.add(""); + } + } + computeBounds(); + } + + // ------------------------------------------------------------------------ + // TText ------------------------------------------------------------------ + // ------------------------------------------------------------------------ + + /** + * Set the text. + * + * @param text new text to display + */ + public void setText(final String text) { + this.text = text; + reflowData(); + } + + /** + * Get the text. + * + * @return the text + */ + public String getText() { + return text; + } + + /** + * Convenience method used by TWindowLoggerOutput. + * + * @param line new line to add + */ + public void addLine(final String line) { + if (StringUtils.width(text) == 0) { + text = line; + } else { + text += "\n\n"; + text += line; + } + reflowData(); + } + + /** + * Recompute the bounds for the scrollbars. + */ + private void computeBounds() { + maxLineWidth = 0; + for (String line : lines) { + if (StringUtils.width(line) > maxLineWidth) { + maxLineWidth = StringUtils.width(line); + } + } + + vScroller.setTopValue(0); + vScroller.setBottomValue((lines.size() - getHeight()) + 1); + if (vScroller.getBottomValue() < 0) { + vScroller.setBottomValue(0); + } + if (vScroller.getValue() > vScroller.getBottomValue()) { + vScroller.setValue(vScroller.getBottomValue()); + } + + hScroller.setLeftValue(0); + hScroller.setRightValue((maxLineWidth - getWidth()) + 1); + if (hScroller.getRightValue() < 0) { + hScroller.setRightValue(0); + } + if (hScroller.getValue() > hScroller.getRightValue()) { + hScroller.setValue(hScroller.getRightValue()); + } + } + + /** + * Set justification. + * + * @param justification NONE, LEFT, CENTER, RIGHT, or FULL + */ + public void setJustification(final Justification justification) { + this.justification = justification; + reflowData(); + } + + /** + * Left-justify the text. + */ + public void leftJustify() { + justification = Justification.LEFT; + reflowData(); + } + + /** + * Center-justify the text. + */ + public void centerJustify() { + justification = Justification.CENTER; + reflowData(); + } + + /** + * Right-justify the text. + */ + public void rightJustify() { + justification = Justification.RIGHT; + reflowData(); + } + + /** + * Fully-justify the text. + */ + public void fullJustify() { + justification = Justification.FULL; + reflowData(); + } + + /** + * Un-justify the text. + */ + public void unJustify() { + justification = Justification.NONE; + reflowData(); + } + }