#34 call onResize() when window size is changed
[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 *
a2018e99 6 * Copyright (C) 2017 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
31import java.util.LinkedList;
32import java.util.List;
33
34import jexer.bits.CellAttributes;
35import jexer.event.TKeypressEvent;
36import jexer.event.TMouseEvent;
d36057df 37import static jexer.TKeypress.*;
cc99cba8
KL
38
39/**
7c870d89
KL
40 * TText implements a simple scrollable text area. It reflows automatically on
41 * resize.
cc99cba8 42 */
051e2913 43public class TText extends TScrollableWidget {
cc99cba8 44
7657ad8c
KL
45 /**
46 * Available text justifications.
47 */
48 public enum Justification {
49 /**
50 * Left-justified text.
51 */
52 LEFT,
53
54 /**
55 * Centered text.
56 */
57 CENTER,
58
59 /**
60 * Right-justified text.
61 */
62 RIGHT,
63
64 /**
65 * Fully-justified text.
66 */
67 FULL,
68 }
69
70 /**
71 * How to justify the text.
72 */
73 private Justification justification = Justification.LEFT;
74
cc99cba8
KL
75 /**
76 * Text to display.
77 */
78 private String text;
79
80 /**
81 * Text converted to lines.
82 */
83 private List<String> lines;
84
85 /**
86 * Text color.
87 */
88 private String colorKey;
89
90 /**
56661844 91 * Maximum width of a single line.
cc99cba8 92 */
56661844 93 private int maxLineWidth;
cc99cba8
KL
94
95 /**
56661844 96 * Number of lines between each paragraph.
cc99cba8 97 */
56661844 98 private int lineSpacing = 1;
cc99cba8
KL
99
100 /**
56661844
KL
101 * Set the text.
102 *
103 * @param text new text to display
cc99cba8 104 */
56661844
KL
105 public void setText(final String text) {
106 this.text = text;
107 reflowData();
108 }
cc99cba8
KL
109
110 /**
56661844
KL
111 * Get the text.
112 *
113 * @return the text
cc99cba8 114 */
56661844
KL
115 public String getText() {
116 return text;
117 }
cc99cba8
KL
118
119 /**
120 * Convenience method used by TWindowLoggerOutput.
121 *
5dfd1c11 122 * @param line new line to add
cc99cba8
KL
123 */
124 public void addLine(final String line) {
125 if (text.length() == 0) {
126 text = line;
127 } else {
128 text += "\n\n";
129 text += line;
130 }
56661844 131 reflowData();
cc99cba8
KL
132 }
133
134 /**
135 * Recompute the bounds for the scrollbars.
136 */
137 private void computeBounds() {
138 maxLineWidth = 0;
7c870d89 139 for (String line : lines) {
cc99cba8
KL
140 if (line.length() > maxLineWidth) {
141 maxLineWidth = line.length();
142 }
143 }
144
56661844 145 vScroller.setTopValue(0);
7c870d89 146 vScroller.setBottomValue((lines.size() - getHeight()) + 1);
cc99cba8
KL
147 if (vScroller.getBottomValue() < 0) {
148 vScroller.setBottomValue(0);
149 }
150 if (vScroller.getValue() > vScroller.getBottomValue()) {
151 vScroller.setValue(vScroller.getBottomValue());
152 }
153
56661844 154 hScroller.setLeftValue(0);
7c870d89 155 hScroller.setRightValue((maxLineWidth - getWidth()) + 1);
cc99cba8
KL
156 if (hScroller.getRightValue() < 0) {
157 hScroller.setRightValue(0);
158 }
159 if (hScroller.getValue() > hScroller.getRightValue()) {
160 hScroller.setValue(hScroller.getRightValue());
161 }
162 }
163
164 /**
7657ad8c 165 * Set justification.
cc99cba8 166 *
7657ad8c
KL
167 * @param justification LEFT, CENTER, RIGHT, or FULL
168 */
169 public void setJustification(final Justification justification) {
170 this.justification = justification;
56661844 171 reflowData();
7657ad8c 172 }
cc99cba8 173
7657ad8c
KL
174 /**
175 * Left-justify the text.
176 */
177 public void leftJustify() {
178 justification = Justification.LEFT;
56661844 179 reflowData();
7657ad8c
KL
180 }
181
182 /**
183 * Center-justify the text.
184 */
185 public void centerJustify() {
186 justification = Justification.CENTER;
56661844 187 reflowData();
7657ad8c
KL
188 }
189
190 /**
191 * Right-justify the text.
192 */
193 public void rightJustify() {
194 justification = Justification.RIGHT;
56661844 195 reflowData();
7657ad8c
KL
196 }
197
198 /**
199 * Fully-justify the text.
200 */
201 public void fullJustify() {
202 justification = Justification.FULL;
56661844 203 reflowData();
cc99cba8
KL
204 }
205
cc99cba8
KL
206 /**
207 * Resize text and scrollbars for a new width/height.
208 */
56661844
KL
209 @Override
210 public void reflowData() {
cc99cba8
KL
211 // Reset the lines
212 lines.clear();
213
214 // Break up text into paragraphs
7c870d89
KL
215 String[] paragraphs = text.split("\n\n");
216 for (String p : paragraphs) {
7657ad8c
KL
217 switch (justification) {
218 case LEFT:
d36057df 219 lines.addAll(jexer.bits.StringUtils.left(p,
7657ad8c
KL
220 getWidth() - 1));
221 break;
222 case CENTER:
d36057df 223 lines.addAll(jexer.bits.StringUtils.center(p,
7657ad8c
KL
224 getWidth() - 1));
225 break;
226 case RIGHT:
d36057df 227 lines.addAll(jexer.bits.StringUtils.right(p,
7657ad8c
KL
228 getWidth() - 1));
229 break;
230 case FULL:
d36057df 231 lines.addAll(jexer.bits.StringUtils.full(p,
7657ad8c
KL
232 getWidth() - 1));
233 break;
cc99cba8 234 }
7657ad8c 235
cc99cba8
KL
236 for (int i = 0; i < lineSpacing; i++) {
237 lines.add("");
238 }
239 }
cc99cba8
KL
240 computeBounds();
241 }
242
243 /**
244 * Public constructor.
245 *
5dfd1c11
KL
246 * @param parent parent widget
247 * @param text text on the screen
248 * @param x column relative to parent
249 * @param y row relative to parent
250 * @param width width of text area
251 * @param height height of text area
cc99cba8
KL
252 */
253 public TText(final TWidget parent, final String text, final int x,
7c870d89 254 final int y, final int width, final int height) {
cc99cba8
KL
255
256 this(parent, text, x, y, width, height, "ttext");
257 }
258
259 /**
260 * Public constructor.
261 *
5dfd1c11
KL
262 * @param parent parent widget
263 * @param text text on the screen
264 * @param x column relative to parent
265 * @param y row relative to parent
266 * @param width width of text area
267 * @param height height of text area
268 * @param colorKey ColorTheme key color to use for foreground
269 * text. Default is "ttext".
cc99cba8
KL
270 */
271 public TText(final TWidget parent, final String text, final int x,
7c870d89
KL
272 final int y, final int width, final int height,
273 final String colorKey) {
cc99cba8
KL
274
275 // Set parent and window
a83fea2b 276 super(parent, x, y, width, height);
cc99cba8 277
cc99cba8
KL
278 this.text = text;
279 this.colorKey = colorKey;
280
281 lines = new LinkedList<String>();
282
56661844
KL
283 vScroller = new TVScroller(this, getWidth() - 1, 0, getHeight() - 1);
284 hScroller = new THScroller(this, 0, getHeight() - 1, getWidth() - 1);
285 reflowData();
cc99cba8
KL
286 }
287
288 /**
289 * Draw the text box.
290 */
291 @Override
292 public void draw() {
293 // Setup my color
294 CellAttributes color = getTheme().getColor(colorKey);
295
296 int begin = vScroller.getValue();
297 int topY = 0;
298 for (int i = begin; i < lines.size(); i++) {
299 String line = lines.get(i);
300 if (hScroller.getValue() < line.length()) {
301 line = line.substring(hScroller.getValue());
302 } else {
303 line = "";
304 }
305 String formatString = "%-" + Integer.toString(getWidth() - 1) + "s";
0d47c546 306 getScreen().putStringXY(0, topY, String.format(formatString, line),
7c870d89 307 color);
cc99cba8
KL
308 topY++;
309
7c870d89 310 if (topY >= (getHeight() - 1)) {
cc99cba8
KL
311 break;
312 }
313 }
314
315 // Pad the rest with blank lines
7c870d89 316 for (int i = topY; i < (getHeight() - 1); i++) {
cc99cba8
KL
317 getScreen().hLineXY(0, i, getWidth() - 1, ' ', color);
318 }
319
320 }
321
322 /**
323 * Handle mouse press events.
324 *
5dfd1c11 325 * @param mouse mouse button press event
cc99cba8
KL
326 */
327 @Override
328 public void onMouseDown(final TMouseEvent mouse) {
7c870d89 329 if (mouse.isMouseWheelUp()) {
cc99cba8
KL
330 vScroller.decrement();
331 return;
332 }
7c870d89 333 if (mouse.isMouseWheelDown()) {
cc99cba8
KL
334 vScroller.increment();
335 return;
336 }
337
338 // Pass to children
339 super.onMouseDown(mouse);
340 }
341
342 /**
343 * Handle keystrokes.
344 *
5dfd1c11 345 * @param keypress keystroke event
cc99cba8
KL
346 */
347 @Override
348 public void onKeypress(final TKeypressEvent keypress) {
349 if (keypress.equals(kbLeft)) {
350 hScroller.decrement();
351 } else if (keypress.equals(kbRight)) {
352 hScroller.increment();
353 } else if (keypress.equals(kbUp)) {
354 vScroller.decrement();
355 } else if (keypress.equals(kbDown)) {
356 vScroller.increment();
357 } else if (keypress.equals(kbPgUp)) {
358 vScroller.bigDecrement();
359 } else if (keypress.equals(kbPgDn)) {
360 vScroller.bigIncrement();
361 } else if (keypress.equals(kbHome)) {
362 vScroller.toTop();
363 } else if (keypress.equals(kbEnd)) {
364 vScroller.toBottom();
365 } else {
366 // Pass other keys (tab etc.) on
367 super.onKeypress(keypress);
368 }
369 }
370
371}