2 * Jexer - Java Text User Interface
4 * The MIT License (MIT)
6 * Copyright (C) 2019 Kevin Lamonte
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
31 import java
.util
.Arrays
;
32 import java
.util
.ArrayList
;
33 import java
.util
.List
;
35 import jexer
.bits
.CellAttributes
;
36 import jexer
.bits
.StringUtils
;
37 import jexer
.event
.TKeypressEvent
;
38 import jexer
.event
.TMouseEvent
;
39 import static jexer
.TKeypress
.kbDown
;
40 import static jexer
.TKeypress
.kbEnd
;
41 import static jexer
.TKeypress
.kbHome
;
42 import static jexer
.TKeypress
.kbLeft
;
43 import static jexer
.TKeypress
.kbPgDn
;
44 import static jexer
.TKeypress
.kbPgUp
;
45 import static jexer
.TKeypress
.kbRight
;
46 import static jexer
.TKeypress
.kbUp
;
49 * TText implements a simple scrollable text area. It reflows automatically on
52 public class TText
extends TScrollableWidget
{
54 // ------------------------------------------------------------------------
55 // Constants --------------------------------------------------------------
56 // ------------------------------------------------------------------------
59 * Available text justifications.
61 public enum Justification
{
64 * Not justified at all, use spacing as provided by the client.
69 * Left-justified text.
79 * Right-justified text.
84 * Fully-justified text.
89 // ------------------------------------------------------------------------
90 // Variables --------------------------------------------------------------
91 // ------------------------------------------------------------------------
94 * How to justify the text.
96 private Justification justification
= Justification
.LEFT
;
104 * Text converted to lines.
106 private List
<String
> lines
;
111 private String colorKey
;
114 * Maximum width of a single line.
116 private int maxLineWidth
;
119 * Number of lines between each paragraph.
121 private int lineSpacing
= 1;
123 // ------------------------------------------------------------------------
124 // Constructors -----------------------------------------------------------
125 // ------------------------------------------------------------------------
128 * Public constructor.
130 * @param parent parent widget
131 * @param text text on the screen
132 * @param x column relative to parent
133 * @param y row relative to parent
134 * @param width width of text area
135 * @param height height of text area
137 public TText(final TWidget parent
, final String text
, final int x
,
138 final int y
, final int width
, final int height
) {
140 this(parent
, text
, x
, y
, width
, height
, "ttext");
144 * Public constructor.
146 * @param parent parent widget
147 * @param text text on the screen
148 * @param x column relative to parent
149 * @param y row relative to parent
150 * @param width width of text area
151 * @param height height of text area
152 * @param colorKey ColorTheme key color to use for foreground
153 * text. Default is "ttext".
155 public TText(final TWidget parent
, final String text
, final int x
,
156 final int y
, final int width
, final int height
,
157 final String colorKey
) {
159 // Set parent and window
160 super(parent
, x
, y
, width
, height
);
163 this.colorKey
= colorKey
;
165 lines
= new ArrayList
<String
>();
167 vScroller
= new TVScroller(this, getWidth() - 1, 0,
168 Math
.max(1, getHeight() - 1));
169 hScroller
= new THScroller(this, 0, getHeight() - 1,
170 Math
.max(1, getWidth() - 1));
174 // ------------------------------------------------------------------------
175 // TScrollableWidget ------------------------------------------------------
176 // ------------------------------------------------------------------------
179 * Override TWidget's width: we need to set child widget widths.
181 * @param width new widget width
184 public void setWidth(final int width
) {
185 super.setWidth(width
);
186 if (hScroller
!= null) {
187 hScroller
.setWidth(getWidth() - 1);
189 if (vScroller
!= null) {
190 vScroller
.setX(getWidth() - 1);
195 * Override TWidget's height: we need to set child widget heights.
198 * @param height new widget height
201 public void setHeight(final int height
) {
202 super.setHeight(height
);
203 if (hScroller
!= null) {
204 hScroller
.setY(getHeight() - 1);
206 if (vScroller
!= null) {
207 vScroller
.setHeight(getHeight() - 1);
217 CellAttributes color
= getTheme().getColor(colorKey
);
219 int begin
= vScroller
.getValue();
221 for (int i
= begin
; i
< lines
.size(); i
++) {
222 String line
= lines
.get(i
);
223 if (hScroller
.getValue() < StringUtils
.width(line
)) {
224 line
= line
.substring(hScroller
.getValue());
228 if (getWidth() > 3) {
229 String formatString
= "%-" + Integer
.toString(getWidth() - 1) + "s";
230 putStringXY(0, topY
, String
.format(formatString
, line
), color
);
234 if (topY
>= (getHeight() - 1)) {
239 // Pad the rest with blank lines
240 for (int i
= topY
; i
< (getHeight() - 1); i
++) {
241 hLineXY(0, i
, getWidth() - 1, ' ', color
);
247 * Handle mouse press events.
249 * @param mouse mouse button press event
252 public void onMouseDown(final TMouseEvent mouse
) {
253 if (mouse
.isMouseWheelUp()) {
254 vScroller
.decrement();
257 if (mouse
.isMouseWheelDown()) {
258 vScroller
.increment();
263 super.onMouseDown(mouse
);
269 * @param keypress keystroke event
272 public void onKeypress(final TKeypressEvent keypress
) {
273 if (keypress
.equals(kbLeft
)) {
274 hScroller
.decrement();
275 } else if (keypress
.equals(kbRight
)) {
276 hScroller
.increment();
277 } else if (keypress
.equals(kbUp
)) {
278 vScroller
.decrement();
279 } else if (keypress
.equals(kbDown
)) {
280 vScroller
.increment();
281 } else if (keypress
.equals(kbPgUp
)) {
282 vScroller
.bigDecrement();
283 } else if (keypress
.equals(kbPgDn
)) {
284 vScroller
.bigIncrement();
285 } else if (keypress
.equals(kbHome
)) {
287 } else if (keypress
.equals(kbEnd
)) {
288 vScroller
.toBottom();
290 // Pass other keys (tab etc.) on
291 super.onKeypress(keypress
);
296 * Resize text and scrollbars for a new width/height.
299 public void reflowData() {
303 // Break up text into paragraphs
304 String
[] paragraphs
= text
.split("\n\n");
305 for (String p
: paragraphs
) {
306 switch (justification
) {
308 lines
.addAll(Arrays
.asList(p
.split("\n")));
311 lines
.addAll(jexer
.bits
.StringUtils
.left(p
,
315 lines
.addAll(jexer
.bits
.StringUtils
.center(p
,
319 lines
.addAll(jexer
.bits
.StringUtils
.right(p
,
323 lines
.addAll(jexer
.bits
.StringUtils
.full(p
,
328 for (int i
= 0; i
< lineSpacing
; i
++) {
335 // ------------------------------------------------------------------------
336 // TText ------------------------------------------------------------------
337 // ------------------------------------------------------------------------
342 * @param text new text to display
344 public void setText(final String text
) {
354 public String
getText() {
359 * Convenience method used by TWindowLoggerOutput.
361 * @param line new line to add
363 public void addLine(final String line
) {
364 if (StringUtils
.width(text
) == 0) {
374 * Recompute the bounds for the scrollbars.
376 private void computeBounds() {
378 for (String line
: lines
) {
379 if (StringUtils
.width(line
) > maxLineWidth
) {
380 maxLineWidth
= StringUtils
.width(line
);
384 vScroller
.setTopValue(0);
385 vScroller
.setBottomValue((lines
.size() - getHeight()) + 1);
386 if (vScroller
.getBottomValue() < 0) {
387 vScroller
.setBottomValue(0);
389 if (vScroller
.getValue() > vScroller
.getBottomValue()) {
390 vScroller
.setValue(vScroller
.getBottomValue());
393 hScroller
.setLeftValue(0);
394 hScroller
.setRightValue((maxLineWidth
- getWidth()) + 1);
395 if (hScroller
.getRightValue() < 0) {
396 hScroller
.setRightValue(0);
398 if (hScroller
.getValue() > hScroller
.getRightValue()) {
399 hScroller
.setValue(hScroller
.getRightValue());
406 * @param justification NONE, LEFT, CENTER, RIGHT, or FULL
408 public void setJustification(final Justification justification
) {
409 this.justification
= justification
;
414 * Left-justify the text.
416 public void leftJustify() {
417 justification
= Justification
.LEFT
;
422 * Center-justify the text.
424 public void centerJustify() {
425 justification
= Justification
.CENTER
;
430 * Right-justify the text.
432 public void rightJustify() {
433 justification
= Justification
.RIGHT
;
438 * Fully-justify the text.
440 public void fullJustify() {
441 justification
= Justification
.FULL
;
446 * Un-justify the text.
448 public void unJustify() {
449 justification
= Justification
.NONE
;