Expose width/height in TApplication constructor, attempt on ECMA48
[fanfix.git] / src / jexer / TList.java
CommitLineData
3649b921
KL
1/*
2 * Jexer - Java Text User Interface
3 *
e16dda65 4 * The MIT License (MIT)
3649b921 5 *
a2018e99 6 * Copyright (C) 2017 Kevin Lamonte
3649b921 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:
3649b921 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.
3649b921 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.
3649b921
KL
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
31import java.util.ArrayList;
32import java.util.List;
33
34import jexer.bits.CellAttributes;
35import jexer.event.TKeypressEvent;
36import jexer.event.TMouseEvent;
37import static jexer.TKeypress.*;
38
39/**
40 * TList shows a list of strings, and lets the user select one.
41 */
56661844 42public class TList extends TScrollableWidget {
3649b921
KL
43
44 /**
45 * The list of strings to display.
46 */
47 private List<String> strings;
48
49 /**
50 * Selected string.
51 */
52 private int selectedString = -1;
53
54 /**
55 * Get the selection index.
56 *
57 * @return -1 if nothing is selected, otherwise the index into the list
58 */
59 public final int getSelectedIndex() {
60 return selectedString;
61 }
62
63 /**
64 * Set the selected string index.
65 *
66 * @param index -1 to unselect, otherwise the index into the list
67 */
68 public final void setSelectedIndex(final int index) {
69 selectedString = index;
70 }
71
72 /**
73 * Get the selected string.
74 *
75 * @return the selected string, or null of nothing is selected yet
76 */
77 public final String getSelected() {
78 if ((selectedString >= 0) && (selectedString <= strings.size() - 1)) {
79 return strings.get(selectedString);
80 }
81 return null;
82 }
83
fe0770f9
KL
84 /**
85 * Get the maximum selection index value.
86 *
87 * @return -1 if the list is empty
88 */
89 public final int getMaxSelectedIndex() {
90 return strings.size() - 1;
91 }
92
3649b921
KL
93 /**
94 * Set the new list of strings to display.
95 *
96 * @param list new list of strings
97 */
98 public final void setList(final List<String> list) {
99 strings.clear();
100 strings.addAll(list);
56661844 101 reflowData();
3649b921
KL
102 }
103
104 /**
105 * Maximum width of a single line.
106 */
107 private int maxLineWidth;
108
109 /**
110 * The action to perform when the user selects an item (clicks or enter).
111 */
112 private TAction enterAction = null;
113
114 /**
115 * The action to perform when the user navigates with keyboard.
116 */
117 private TAction moveAction = null;
118
119 /**
120 * Perform user selection action.
121 */
122 public void dispatchEnter() {
123 assert (selectedString >= 0);
124 assert (selectedString < strings.size());
125 if (enterAction != null) {
126 enterAction.DO();
127 }
128 }
129
130 /**
131 * Perform list movement action.
132 */
133 public void dispatchMove() {
134 assert (selectedString >= 0);
135 assert (selectedString < strings.size());
136 if (moveAction != null) {
137 moveAction.DO();
138 }
139 }
140
141 /**
142 * Resize for a new width/height.
143 */
56661844
KL
144 @Override
145 public void reflowData() {
3649b921
KL
146
147 // Reset the lines
148 selectedString = -1;
149 maxLineWidth = 0;
150
151 for (int i = 0; i < strings.size(); i++) {
152 String line = strings.get(i);
153 if (line.length() > maxLineWidth) {
154 maxLineWidth = line.length();
155 }
156 }
157
56661844
KL
158 setBottomValue(strings.size() - getHeight() + 1);
159 if (getBottomValue() < 0) {
160 setBottomValue(0);
3649b921 161 }
3649b921 162
56661844
KL
163 setRightValue(maxLineWidth - getWidth() + 1);
164 if (getRightValue() < 0) {
165 setRightValue(0);
3649b921 166 }
3649b921
KL
167 }
168
169 /**
170 * Public constructor.
171 *
172 * @param parent parent widget
173 * @param strings list of strings to show
174 * @param x column relative to parent
175 * @param y row relative to parent
176 * @param width width of text area
177 * @param height height of text area
178 */
179 public TList(final TWidget parent, final List<String> strings, final int x,
180 final int y, final int width, final int height) {
181
182 this(parent, strings, x, y, width, height, null);
183 }
184
185 /**
186 * Public constructor.
187 *
188 * @param parent parent widget
189 * @param strings list of strings to show. This is allowed to be null
190 * and set later with setList() or by subclasses.
191 * @param x column relative to parent
192 * @param y row relative to parent
193 * @param width width of text area
194 * @param height height of text area
195 * @param enterAction action to perform when an item is selected
196 */
197 public TList(final TWidget parent, final List<String> strings, final int x,
198 final int y, final int width, final int height,
199 final TAction enterAction) {
200
201 super(parent, x, y, width, height);
202 this.enterAction = enterAction;
203 this.strings = new ArrayList<String>();
204 if (strings != null) {
205 this.strings.addAll(strings);
206 }
56661844
KL
207
208 hScroller = new THScroller(this, 0, getHeight() - 1, getWidth() - 1);
209 vScroller = new TVScroller(this, getWidth() - 1, 0, getHeight() - 1);
210 reflowData();
3649b921
KL
211 }
212
213 /**
214 * Public constructor.
215 *
216 * @param parent parent widget
217 * @param strings list of strings to show. This is allowed to be null
218 * and set later with setList() or by subclasses.
219 * @param x column relative to parent
220 * @param y row relative to parent
221 * @param width width of text area
222 * @param height height of text area
223 * @param enterAction action to perform when an item is selected
224 * @param moveAction action to perform when the user navigates to a new
225 * item with arrow/page keys
226 */
227 public TList(final TWidget parent, final List<String> strings, final int x,
228 final int y, final int width, final int height,
229 final TAction enterAction, final TAction moveAction) {
230
231 super(parent, x, y, width, height);
232 this.enterAction = enterAction;
233 this.moveAction = moveAction;
234 this.strings = new ArrayList<String>();
235 if (strings != null) {
236 this.strings.addAll(strings);
237 }
56661844
KL
238
239 hScroller = new THScroller(this, 0, getHeight() - 1, getWidth() - 1);
240 vScroller = new TVScroller(this, getWidth() - 1, 0, getHeight() - 1);
241 reflowData();
3649b921
KL
242 }
243
244 /**
245 * Draw the files list.
246 */
247 @Override
248 public void draw() {
249 CellAttributes color = null;
56661844 250 int begin = getVerticalValue();
3649b921
KL
251 int topY = 0;
252 for (int i = begin; i < strings.size(); i++) {
253 String line = strings.get(i);
56661844
KL
254 if (getHorizontalValue() < line.length()) {
255 line = line.substring(getHorizontalValue());
3649b921
KL
256 } else {
257 line = "";
258 }
259 if (i == selectedString) {
260 color = getTheme().getColor("tlist.selected");
261 } else if (isAbsoluteActive()) {
262 color = getTheme().getColor("tlist");
263 } else {
264 color = getTheme().getColor("tlist.inactive");
265 }
266 String formatString = "%-" + Integer.toString(getWidth() - 1) + "s";
267 getScreen().putStringXY(0, topY, String.format(formatString, line),
268 color);
269 topY++;
270 if (topY >= getHeight() - 1) {
271 break;
272 }
273 }
274
275 if (isAbsoluteActive()) {
276 color = getTheme().getColor("tlist");
277 } else {
278 color = getTheme().getColor("tlist.inactive");
279 }
280
281 // Pad the rest with blank lines
282 for (int i = topY; i < getHeight() - 1; i++) {
283 getScreen().hLineXY(0, i, getWidth() - 1, ' ', color);
284 }
285 }
286
287 /**
288 * Handle mouse press events.
289 *
290 * @param mouse mouse button press event
291 */
292 @Override
293 public void onMouseDown(final TMouseEvent mouse) {
294 if (mouse.isMouseWheelUp()) {
56661844 295 verticalDecrement();
3649b921
KL
296 return;
297 }
298 if (mouse.isMouseWheelDown()) {
56661844 299 verticalIncrement();
3649b921
KL
300 return;
301 }
302
303 if ((mouse.getX() < getWidth() - 1)
304 && (mouse.getY() < getHeight() - 1)) {
56661844
KL
305 if (getVerticalValue() + mouse.getY() < strings.size()) {
306 selectedString = getVerticalValue() + mouse.getY();
3649b921 307 }
3649b921
KL
308 return;
309 }
310
311 // Pass to children
312 super.onMouseDown(mouse);
313 }
314
b6faeac0
KL
315 /**
316 * Handle mouse double click.
317 *
318 * @param mouse mouse double click event
319 */
320 @Override
321 public void onMouseDoubleClick(final TMouseEvent mouse) {
322 if ((mouse.getX() < getWidth() - 1)
323 && (mouse.getY() < getHeight() - 1)) {
324 if (getVerticalValue() + mouse.getY() < strings.size()) {
325 selectedString = getVerticalValue() + mouse.getY();
326 dispatchEnter();
327 }
328 return;
329 }
330
331 // Pass to children
332 super.onMouseDoubleClick(mouse);
333 }
334
3649b921
KL
335 /**
336 * Handle keystrokes.
337 *
338 * @param keypress keystroke event
339 */
340 @Override
341 public void onKeypress(final TKeypressEvent keypress) {
342 if (keypress.equals(kbLeft)) {
56661844 343 horizontalDecrement();
3649b921 344 } else if (keypress.equals(kbRight)) {
56661844 345 horizontalIncrement();
3649b921
KL
346 } else if (keypress.equals(kbUp)) {
347 if (strings.size() > 0) {
348 if (selectedString >= 0) {
349 if (selectedString > 0) {
56661844
KL
350 if (selectedString - getVerticalValue() == 0) {
351 verticalDecrement();
3649b921
KL
352 }
353 selectedString--;
354 }
355 } else {
356 selectedString = strings.size() - 1;
357 }
358 }
359 if (selectedString >= 0) {
360 dispatchMove();
361 }
362 } else if (keypress.equals(kbDown)) {
363 if (strings.size() > 0) {
364 if (selectedString >= 0) {
365 if (selectedString < strings.size() - 1) {
366 selectedString++;
56661844
KL
367 if (selectedString - getVerticalValue() == getHeight() - 1) {
368 verticalIncrement();
3649b921
KL
369 }
370 }
371 } else {
372 selectedString = 0;
373 }
374 }
375 if (selectedString >= 0) {
376 dispatchMove();
377 }
378 } else if (keypress.equals(kbPgUp)) {
56661844 379 bigVerticalDecrement();
3649b921
KL
380 if (selectedString >= 0) {
381 selectedString -= getHeight() - 1;
382 if (selectedString < 0) {
383 selectedString = 0;
384 }
385 }
386 if (selectedString >= 0) {
387 dispatchMove();
388 }
389 } else if (keypress.equals(kbPgDn)) {
56661844 390 bigVerticalIncrement();
3649b921
KL
391 if (selectedString >= 0) {
392 selectedString += getHeight() - 1;
393 if (selectedString > strings.size() - 1) {
394 selectedString = strings.size() - 1;
395 }
396 }
397 if (selectedString >= 0) {
398 dispatchMove();
399 }
400 } else if (keypress.equals(kbHome)) {
56661844 401 toTop();
3649b921
KL
402 if (strings.size() > 0) {
403 selectedString = 0;
404 }
405 if (selectedString >= 0) {
406 dispatchMove();
407 }
408 } else if (keypress.equals(kbEnd)) {
56661844 409 toBottom();
3649b921
KL
410 if (strings.size() > 0) {
411 selectedString = strings.size() - 1;
412 }
413 if (selectedString >= 0) {
414 dispatchMove();
415 }
416 } else if (keypress.equals(kbTab)) {
417 getParent().switchWidget(true);
418 } else if (keypress.equals(kbShiftTab) || keypress.equals(kbBackTab)) {
419 getParent().switchWidget(false);
420 } else if (keypress.equals(kbEnter)) {
421 if (selectedString >= 0) {
422 dispatchEnter();
423 }
424 } else {
425 // Pass other keys (tab etc.) on
426 super.onKeypress(keypress);
427 }
428 }
429
430}