#46 stubs for LayoutManager
[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);
117 TComboBox.this.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);
133 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
218 /**
219 * Draw the combobox down arrow.
220 */
221 @Override
222 public void draw() {
223 CellAttributes comboBoxColor;
224
a69ed767
KL
225 if (!isAbsoluteActive()) {
226 // We lost focus, turn off the list.
227 if (list.isActive()) {
8ab60a33 228 hideList();
a69ed767
KL
229 }
230 }
231
e23ea538 232 if (isAbsoluteActive()) {
051e2913
KL
233 comboBoxColor = getTheme().getColor("tcombobox.active");
234 } else {
235 comboBoxColor = getTheme().getColor("tcombobox.inactive");
236 }
237
a69ed767
KL
238 putCharXY(getWidth() - 3, 0, GraphicsChars.DOWNARROWLEFT,
239 comboBoxColor);
240 putCharXY(getWidth() - 2, 0, GraphicsChars.DOWNARROW,
241 comboBoxColor);
242 putCharXY(getWidth() - 1, 0, GraphicsChars.DOWNARROWRIGHT,
051e2913
KL
243 comboBoxColor);
244 }
245
246 // ------------------------------------------------------------------------
247 // TComboBox --------------------------------------------------------------
248 // ------------------------------------------------------------------------
249
8ab60a33
KL
250 /**
251 * Hide the drop-down list.
252 */
253 public void hideList() {
254 list.setEnabled(false);
255 list.setVisible(false);
256 setHeight(1);
257 if (limitToListValue == false) {
258 activate(field);
259 }
260 }
261
262 /**
263 * Show the drop-down list.
264 */
265 public void showList() {
266 list.setEnabled(true);
267 list.setVisible(true);
268 setHeight(list.getHeight() + 1);
269 activate(list);
270 }
271
051e2913
KL
272 /**
273 * Get combobox text value.
274 *
275 * @return text in the edit field
276 */
277 public String getText() {
278 return field.getText();
279 }
280
281 /**
282 * Set combobox text value.
283 *
284 * @param text the new text in the edit field
285 */
286 public void setText(final String text) {
af56159c
KL
287 setText(text, true);
288 }
289
290 /**
291 * Set combobox text value.
292 *
293 * @param text the new text in the edit field
294 * @param caseSensitive if true, perform a case-sensitive search for the
295 * list item
296 */
297 public void setText(final String text, final boolean caseSensitive) {
051e2913
KL
298 field.setText(text);
299 for (int i = 0; i < list.getMaxSelectedIndex(); i++) {
af56159c
KL
300 if (caseSensitive == true) {
301 if (list.getListItem(i).equals(text)) {
302 list.setSelectedIndex(i);
303 return;
304 }
305 } else {
306 if (list.getListItem(i).toLowerCase().equals(text.toLowerCase())) {
307 list.setSelectedIndex(i);
308 return;
309 }
051e2913
KL
310 }
311 }
312 list.setSelectedIndex(-1);
313 }
314
a69ed767
KL
315 /**
316 * Set combobox text to one of the list values.
317 *
318 * @param index the index in the list
319 */
320 public void setIndex(final int index) {
321 list.setSelectedIndex(index);
322 field.setText(list.getSelected());
323 }
324
325 /**
326 * Get a copy of the list of strings to display.
327 *
328 * @return the list of strings
329 */
330 public final List<String> getList() {
331 return list.getList();
332 }
333
334 /**
335 * Set the new list of strings to display.
336 *
337 * @param list new list of strings
338 */
339 public final void setList(final List<String> list) {
340 this.list.setList(list);
8ab60a33
KL
341 this.list.setHeight(Math.max(3, Math.min(list.size() + 1,
342 maxValuesHeight)));
a69ed767
KL
343 field.setText("");
344 }
345
051e2913 346}