#46 StretchLayoutManager working
[fanfix.git] / src / jexer / TComboBox.java
CommitLineData
051e2913
KL
1/*
2 * Jexer - Java Text User Interface
3 *
4 * The MIT License (MIT)
5 *
a69ed767 6 * Copyright (C) 2019 Kevin Lamonte
051e2913
KL
7 *
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:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
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.
25 *
26 * @author Kevin Lamonte [kevin.lamonte@gmail.com]
27 * @version 1
28 */
29package jexer;
30
31import java.util.List;
32
33import jexer.bits.CellAttributes;
34import jexer.bits.GraphicsChars;
35import jexer.event.TKeypressEvent;
36import jexer.event.TMouseEvent;
37import static jexer.TKeypress.*;
38
39/**
40 * TComboBox implements a combobox containing a drop-down list and edit
41 * field. Alt-Down can be used to show the drop-down.
42 */
43public class TComboBox extends TWidget {
44
45 // ------------------------------------------------------------------------
46 // Variables --------------------------------------------------------------
47 // ------------------------------------------------------------------------
48
49 /**
50 * The list of items in the drop-down.
51 */
52 private TList list;
53
54 /**
55 * The edit field containing the value to return.
56 */
57 private TField field;
58
59 /**
60 * The action to perform when the user selects an item (clicks or enter).
61 */
62 private TAction updateAction = null;
63
a69ed767
KL
64 /**
65 * If true, the field cannot be updated to a value not on the list.
66 */
67 private boolean limitToListValue = true;
68
8ab60a33
KL
69 /**
70 * The maximum height of the values drop-down when it is visible.
71 */
72 private int maxValuesHeight = 3;
73
051e2913
KL
74 // ------------------------------------------------------------------------
75 // Constructors -----------------------------------------------------------
76 // ------------------------------------------------------------------------
77
78 /**
79 * Public constructor.
80 *
81 * @param parent parent widget
82 * @param x column relative to parent
83 * @param y row relative to parent
84 * @param width visible combobox width, including the down-arrow
85 * @param values the possible values for the box, shown in the drop-down
86 * @param valuesIndex the initial index in values, or -1 for no default
87 * value
8ab60a33
KL
88 * @param maxValuesHeight the maximum height of the values drop-down when
89 * it is visible
051e2913
KL
90 * @param updateAction action to call when a new value is selected from
91 * the list or enter is pressed in the edit field
92 */
93 public TComboBox(final TWidget parent, final int x, final int y,
94 final int width, final List<String> values, final int valuesIndex,
8ab60a33 95 final int maxValuesHeight, final TAction updateAction) {
051e2913
KL
96
97 // Set parent and window
98 super(parent, x, y, width, 1);
99
a69ed767
KL
100 assert (values != null);
101
051e2913 102 this.updateAction = updateAction;
8ab60a33 103 this.maxValuesHeight = maxValuesHeight;
051e2913 104
382bc294 105 field = addField(0, 0, width - 3, false, "", updateAction, null);
8ab60a33 106 if ((valuesIndex >= 0) && (valuesIndex < values.size())) {
051e2913
KL
107 field.setText(values.get(valuesIndex));
108 }
109
8ab60a33
KL
110 list = addList(values, 0, 1, width,
111 Math.max(3, Math.min(values.size() + 1, maxValuesHeight)),
051e2913
KL
112 new TAction() {
113 public void DO() {
114 field.setText(list.getSelected());
115 list.setEnabled(false);
116 list.setVisible(false);
d8dc8aea 117 TComboBox.super.setHeight(1);
a69ed767
KL
118 if (TComboBox.this.limitToListValue == false) {
119 TComboBox.this.activate(field);
120 }
051e2913
KL
121 if (updateAction != null) {
122 updateAction.DO();
123 }
124 }
125 }
126 );
a69ed767
KL
127 if (valuesIndex >= 0) {
128 list.setSelectedIndex(valuesIndex);
129 }
051e2913
KL
130
131 list.setEnabled(false);
132 list.setVisible(false);
d8dc8aea 133 super.setHeight(1);
a69ed767
KL
134 if (limitToListValue) {
135 field.setEnabled(false);
136 } else {
137 activate(field);
138 }
051e2913
KL
139 }
140
141 // ------------------------------------------------------------------------
142 // Event handlers ---------------------------------------------------------
143 // ------------------------------------------------------------------------
144
145 /**
146 * Returns true if the mouse is currently on the down arrow.
147 *
148 * @param mouse mouse event
149 * @return true if the mouse is currently on the down arrow
150 */
151 private boolean mouseOnArrow(final TMouseEvent mouse) {
152 if ((mouse.getY() == 0)
a69ed767
KL
153 && (mouse.getX() >= getWidth() - 3)
154 && (mouse.getX() <= getWidth() - 1)
051e2913
KL
155 ) {
156 return true;
157 }
158 return false;
159 }
160
161 /**
162 * Handle mouse down clicks.
163 *
164 * @param mouse mouse button down event
165 */
166 @Override
167 public void onMouseDown(final TMouseEvent mouse) {
168 if ((mouseOnArrow(mouse)) && (mouse.isMouse1())) {
169 // Make the list visible or not.
170 if (list.isActive()) {
8ab60a33 171 hideList();
051e2913 172 } else {
8ab60a33 173 showList();
051e2913
KL
174 }
175 }
a69ed767
KL
176
177 // Pass to parent for the things we don't care about.
178 super.onMouseDown(mouse);
051e2913
KL
179 }
180
181 /**
182 * Handle keystrokes.
183 *
184 * @param keypress keystroke event
185 */
186 @Override
187 public void onKeypress(final TKeypressEvent keypress) {
a69ed767
KL
188 if (keypress.equals(kbEsc)) {
189 if (list.isActive()) {
8ab60a33 190 hideList();
a69ed767
KL
191 return;
192 }
193 }
194
051e2913 195 if (keypress.equals(kbAltDown)) {
8ab60a33 196 showList();
051e2913
KL
197 return;
198 }
199
200 if (keypress.equals(kbTab)
201 || (keypress.equals(kbShiftTab))
202 || (keypress.equals(kbBackTab))
203 ) {
204 if (list.isActive()) {
8ab60a33 205 hideList();
051e2913
KL
206 return;
207 }
208 }
209
210 // Pass to parent for the things we don't care about.
211 super.onKeypress(keypress);
212 }
213
214 // ------------------------------------------------------------------------
215 // TWidget ----------------------------------------------------------------
216 // ------------------------------------------------------------------------
217
d8dc8aea
KL
218 /**
219 * Override TWidget's width: we can only set width at construction time.
220 *
221 * @param width new widget width (ignored)
222 */
223 @Override
224 public void setWidth(final int width) {
225 // Do nothing
226 }
227
228 /**
229 * Override TWidget's height: we can only set height at construction
230 * time.
231 *
232 * @param height new widget height (ignored)
233 */
234 @Override
235 public void setHeight(final int height) {
236 // Do nothing
237 }
238
051e2913
KL
239 /**
240 * Draw the combobox down arrow.
241 */
242 @Override
243 public void draw() {
244 CellAttributes comboBoxColor;
245
a69ed767
KL
246 if (!isAbsoluteActive()) {
247 // We lost focus, turn off the list.
248 if (list.isActive()) {
8ab60a33 249 hideList();
a69ed767
KL
250 }
251 }
252
e23ea538 253 if (isAbsoluteActive()) {
051e2913
KL
254 comboBoxColor = getTheme().getColor("tcombobox.active");
255 } else {
256 comboBoxColor = getTheme().getColor("tcombobox.inactive");
257 }
258
a69ed767
KL
259 putCharXY(getWidth() - 3, 0, GraphicsChars.DOWNARROWLEFT,
260 comboBoxColor);
261 putCharXY(getWidth() - 2, 0, GraphicsChars.DOWNARROW,
262 comboBoxColor);
263 putCharXY(getWidth() - 1, 0, GraphicsChars.DOWNARROWRIGHT,
051e2913
KL
264 comboBoxColor);
265 }
266
267 // ------------------------------------------------------------------------
268 // TComboBox --------------------------------------------------------------
269 // ------------------------------------------------------------------------
270
8ab60a33
KL
271 /**
272 * Hide the drop-down list.
273 */
274 public void hideList() {
275 list.setEnabled(false);
276 list.setVisible(false);
d8dc8aea 277 super.setHeight(1);
8ab60a33
KL
278 if (limitToListValue == false) {
279 activate(field);
280 }
281 }
282
283 /**
284 * Show the drop-down list.
285 */
286 public void showList() {
287 list.setEnabled(true);
288 list.setVisible(true);
d8dc8aea 289 super.setHeight(list.getHeight() + 1);
8ab60a33
KL
290 activate(list);
291 }
292
051e2913
KL
293 /**
294 * Get combobox text value.
295 *
296 * @return text in the edit field
297 */
298 public String getText() {
299 return field.getText();
300 }
301
302 /**
303 * Set combobox text value.
304 *
305 * @param text the new text in the edit field
306 */
307 public void setText(final String text) {
af56159c
KL
308 setText(text, true);
309 }
310
311 /**
312 * Set combobox text value.
313 *
314 * @param text the new text in the edit field
315 * @param caseSensitive if true, perform a case-sensitive search for the
316 * list item
317 */
318 public void setText(final String text, final boolean caseSensitive) {
051e2913
KL
319 field.setText(text);
320 for (int i = 0; i < list.getMaxSelectedIndex(); i++) {
af56159c
KL
321 if (caseSensitive == true) {
322 if (list.getListItem(i).equals(text)) {
323 list.setSelectedIndex(i);
324 return;
325 }
326 } else {
327 if (list.getListItem(i).toLowerCase().equals(text.toLowerCase())) {
328 list.setSelectedIndex(i);
329 return;
330 }
051e2913
KL
331 }
332 }
333 list.setSelectedIndex(-1);
334 }
335
a69ed767
KL
336 /**
337 * Set combobox text to one of the list values.
338 *
339 * @param index the index in the list
340 */
341 public void setIndex(final int index) {
342 list.setSelectedIndex(index);
343 field.setText(list.getSelected());
344 }
345
346 /**
347 * Get a copy of the list of strings to display.
348 *
349 * @return the list of strings
350 */
351 public final List<String> getList() {
352 return list.getList();
353 }
354
355 /**
356 * Set the new list of strings to display.
357 *
358 * @param list new list of strings
359 */
360 public final void setList(final List<String> list) {
361 this.list.setList(list);
8ab60a33
KL
362 this.list.setHeight(Math.max(3, Math.min(list.size() + 1,
363 maxValuesHeight)));
a69ed767
KL
364 field.setText("");
365 }
366
051e2913 367}