hideStatusBar and hideMenuBar
[fanfix.git] / src / jexer / TText.java
CommitLineData
daa4106c 1/*
cc99cba8
KL
2 * Jexer - Java Text User Interface
3 *
e16dda65 4 * The MIT License (MIT)
cc99cba8 5 *
a69ed767 6 * Copyright (C) 2019 Kevin Lamonte
cc99cba8 7 *
e16dda65
KL
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:
cc99cba8 14 *
e16dda65
KL
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
cc99cba8 17 *
e16dda65
KL
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.
cc99cba8
KL
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
a69ed767 31import java.util.Arrays;
cc99cba8
KL
32import java.util.LinkedList;
33import java.util.List;
34
35import jexer.bits.CellAttributes;
e820d5dd 36import jexer.bits.StringUtils;
cc99cba8
KL
37import jexer.event.TKeypressEvent;
38import jexer.event.TMouseEvent;
615a0d99
KL
39import static jexer.TKeypress.kbDown;
40import static jexer.TKeypress.kbEnd;
41import static jexer.TKeypress.kbHome;
42import static jexer.TKeypress.kbLeft;
43import static jexer.TKeypress.kbPgDn;
44import static jexer.TKeypress.kbPgUp;
45import static jexer.TKeypress.kbRight;
46import static jexer.TKeypress.kbUp;
cc99cba8
KL
47
48/**
7c870d89
KL
49 * TText implements a simple scrollable text area. It reflows automatically on
50 * resize.
cc99cba8 51 */
051e2913 52public class TText extends TScrollableWidget {
cc99cba8 53
615a0d99
KL
54 // ------------------------------------------------------------------------
55 // Constants --------------------------------------------------------------
56 // ------------------------------------------------------------------------
57
7657ad8c
KL
58 /**
59 * Available text justifications.
60 */
61 public enum Justification {
a69ed767
KL
62
63 /**
64 * Not justified at all, use spacing as provided by the client.
65 */
66 NONE,
67
7657ad8c
KL
68 /**
69 * Left-justified text.
70 */
71 LEFT,
72
73 /**
74 * Centered text.
75 */
76 CENTER,
77
78 /**
79 * Right-justified text.
80 */
81 RIGHT,
82
83 /**
84 * Fully-justified text.
85 */
86 FULL,
87 }
88
615a0d99
KL
89 // ------------------------------------------------------------------------
90 // Variables --------------------------------------------------------------
91 // ------------------------------------------------------------------------
92
7657ad8c
KL
93 /**
94 * How to justify the text.
95 */
96 private Justification justification = Justification.LEFT;
97
cc99cba8
KL
98 /**
99 * Text to display.
100 */
101 private String text;
102
103 /**
104 * Text converted to lines.
105 */
106 private List<String> lines;
107
108 /**
109 * Text color.
110 */
111 private String colorKey;
112
113 /**
56661844 114 * Maximum width of a single line.
cc99cba8 115 */
56661844 116 private int maxLineWidth;
cc99cba8
KL
117
118 /**
56661844 119 * Number of lines between each paragraph.
cc99cba8 120 */
56661844 121 private int lineSpacing = 1;
cc99cba8 122
615a0d99
KL
123 // ------------------------------------------------------------------------
124 // Constructors -----------------------------------------------------------
125 // ------------------------------------------------------------------------
cc99cba8
KL
126
127 /**
128 * Public constructor.
129 *
5dfd1c11
KL
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
cc99cba8
KL
136 */
137 public TText(final TWidget parent, final String text, final int x,
7c870d89 138 final int y, final int width, final int height) {
cc99cba8
KL
139
140 this(parent, text, x, y, width, height, "ttext");
141 }
142
143 /**
144 * Public constructor.
145 *
5dfd1c11
KL
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".
cc99cba8
KL
154 */
155 public TText(final TWidget parent, final String text, final int x,
7c870d89
KL
156 final int y, final int width, final int height,
157 final String colorKey) {
cc99cba8
KL
158
159 // Set parent and window
a83fea2b 160 super(parent, x, y, width, height);
cc99cba8 161
cc99cba8
KL
162 this.text = text;
163 this.colorKey = colorKey;
164
165 lines = new LinkedList<String>();
166
fc2af494
KL
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));
56661844 171 reflowData();
cc99cba8
KL
172 }
173
615a0d99
KL
174 // ------------------------------------------------------------------------
175 // TScrollableWidget ------------------------------------------------------
176 // ------------------------------------------------------------------------
177
8f62f06e
KL
178 /**
179 * Override TWidget's width: we need to set child widget widths.
180 *
181 * @param width new widget width
182 */
183 @Override
184 public void setWidth(final int width) {
185 super.setWidth(width);
fc2af494
KL
186 if (hScroller != null) {
187 hScroller.setWidth(getWidth() - 1);
188 }
189 if (vScroller != null) {
190 vScroller.setX(getWidth() - 1);
191 }
8f62f06e
KL
192 }
193
194 /**
195 * Override TWidget's height: we need to set child widget heights.
196 * time.
197 *
198 * @param height new widget height
199 */
200 @Override
201 public void setHeight(final int height) {
202 super.setHeight(height);
fc2af494
KL
203 if (hScroller != null) {
204 hScroller.setY(getHeight() - 1);
205 }
206 if (vScroller != null) {
207 vScroller.setHeight(getHeight() - 1);
208 }
8f62f06e
KL
209 }
210
cc99cba8
KL
211 /**
212 * Draw the text box.
213 */
214 @Override
215 public void draw() {
216 // Setup my color
217 CellAttributes color = getTheme().getColor(colorKey);
218
219 int begin = vScroller.getValue();
220 int topY = 0;
221 for (int i = begin; i < lines.size(); i++) {
222 String line = lines.get(i);
e820d5dd 223 if (hScroller.getValue() < StringUtils.width(line)) {
cc99cba8
KL
224 line = line.substring(hScroller.getValue());
225 } else {
226 line = "";
227 }
228 String formatString = "%-" + Integer.toString(getWidth() - 1) + "s";
a69ed767 229 putStringXY(0, topY, String.format(formatString, line), color);
cc99cba8
KL
230 topY++;
231
7c870d89 232 if (topY >= (getHeight() - 1)) {
cc99cba8
KL
233 break;
234 }
235 }
236
237 // Pad the rest with blank lines
7c870d89 238 for (int i = topY; i < (getHeight() - 1); i++) {
a69ed767 239 hLineXY(0, i, getWidth() - 1, ' ', color);
cc99cba8
KL
240 }
241
242 }
243
244 /**
245 * Handle mouse press events.
246 *
5dfd1c11 247 * @param mouse mouse button press event
cc99cba8
KL
248 */
249 @Override
250 public void onMouseDown(final TMouseEvent mouse) {
7c870d89 251 if (mouse.isMouseWheelUp()) {
cc99cba8
KL
252 vScroller.decrement();
253 return;
254 }
7c870d89 255 if (mouse.isMouseWheelDown()) {
cc99cba8
KL
256 vScroller.increment();
257 return;
258 }
259
260 // Pass to children
261 super.onMouseDown(mouse);
262 }
263
264 /**
265 * Handle keystrokes.
266 *
5dfd1c11 267 * @param keypress keystroke event
cc99cba8
KL
268 */
269 @Override
270 public void onKeypress(final TKeypressEvent keypress) {
271 if (keypress.equals(kbLeft)) {
272 hScroller.decrement();
273 } else if (keypress.equals(kbRight)) {
274 hScroller.increment();
275 } else if (keypress.equals(kbUp)) {
276 vScroller.decrement();
277 } else if (keypress.equals(kbDown)) {
278 vScroller.increment();
279 } else if (keypress.equals(kbPgUp)) {
280 vScroller.bigDecrement();
281 } else if (keypress.equals(kbPgDn)) {
282 vScroller.bigIncrement();
283 } else if (keypress.equals(kbHome)) {
284 vScroller.toTop();
285 } else if (keypress.equals(kbEnd)) {
286 vScroller.toBottom();
287 } else {
288 // Pass other keys (tab etc.) on
289 super.onKeypress(keypress);
290 }
291 }
292
615a0d99
KL
293 /**
294 * Resize text and scrollbars for a new width/height.
295 */
296 @Override
297 public void reflowData() {
298 // Reset the lines
299 lines.clear();
300
301 // Break up text into paragraphs
302 String[] paragraphs = text.split("\n\n");
303 for (String p : paragraphs) {
304 switch (justification) {
a69ed767
KL
305 case NONE:
306 lines.addAll(Arrays.asList(p.split("\n")));
307 break;
615a0d99
KL
308 case LEFT:
309 lines.addAll(jexer.bits.StringUtils.left(p,
310 getWidth() - 1));
311 break;
312 case CENTER:
313 lines.addAll(jexer.bits.StringUtils.center(p,
314 getWidth() - 1));
315 break;
316 case RIGHT:
317 lines.addAll(jexer.bits.StringUtils.right(p,
318 getWidth() - 1));
319 break;
320 case FULL:
321 lines.addAll(jexer.bits.StringUtils.full(p,
322 getWidth() - 1));
323 break;
324 }
325
326 for (int i = 0; i < lineSpacing; i++) {
327 lines.add("");
328 }
329 }
330 computeBounds();
331 }
332
333 // ------------------------------------------------------------------------
334 // TText ------------------------------------------------------------------
335 // ------------------------------------------------------------------------
336
337 /**
338 * Set the text.
339 *
340 * @param text new text to display
341 */
342 public void setText(final String text) {
343 this.text = text;
344 reflowData();
345 }
346
347 /**
348 * Get the text.
349 *
350 * @return the text
351 */
352 public String getText() {
353 return text;
354 }
355
356 /**
357 * Convenience method used by TWindowLoggerOutput.
358 *
359 * @param line new line to add
360 */
361 public void addLine(final String line) {
e820d5dd 362 if (StringUtils.width(text) == 0) {
615a0d99
KL
363 text = line;
364 } else {
365 text += "\n\n";
366 text += line;
367 }
368 reflowData();
369 }
370
371 /**
372 * Recompute the bounds for the scrollbars.
373 */
374 private void computeBounds() {
375 maxLineWidth = 0;
376 for (String line : lines) {
e820d5dd
KL
377 if (StringUtils.width(line) > maxLineWidth) {
378 maxLineWidth = StringUtils.width(line);
615a0d99
KL
379 }
380 }
381
382 vScroller.setTopValue(0);
383 vScroller.setBottomValue((lines.size() - getHeight()) + 1);
384 if (vScroller.getBottomValue() < 0) {
385 vScroller.setBottomValue(0);
386 }
387 if (vScroller.getValue() > vScroller.getBottomValue()) {
388 vScroller.setValue(vScroller.getBottomValue());
389 }
390
391 hScroller.setLeftValue(0);
392 hScroller.setRightValue((maxLineWidth - getWidth()) + 1);
393 if (hScroller.getRightValue() < 0) {
394 hScroller.setRightValue(0);
395 }
396 if (hScroller.getValue() > hScroller.getRightValue()) {
397 hScroller.setValue(hScroller.getRightValue());
398 }
399 }
400
401 /**
402 * Set justification.
403 *
404 * @param justification LEFT, CENTER, RIGHT, or FULL
405 */
406 public void setJustification(final Justification justification) {
407 this.justification = justification;
408 reflowData();
409 }
410
411 /**
412 * Left-justify the text.
413 */
414 public void leftJustify() {
415 justification = Justification.LEFT;
416 reflowData();
417 }
418
419 /**
420 * Center-justify the text.
421 */
422 public void centerJustify() {
423 justification = Justification.CENTER;
424 reflowData();
425 }
426
427 /**
428 * Right-justify the text.
429 */
430 public void rightJustify() {
431 justification = Justification.RIGHT;
432 reflowData();
433 }
434
435 /**
436 * Fully-justify the text.
437 */
438 public void fullJustify() {
439 justification = Justification.FULL;
440 reflowData();
441 }
442
cc99cba8 443}