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