X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fjexer%2FTComboBox.java;h=1164e6c53f9699e224611f304391e22ee966471b;hb=12b90437b5f22c2ae6e9b9b14c3b62b60f6143e5;hp=38224b89e8c3037ac94855324dff2dbc90b6ef0f;hpb=051e29138b18fb4b731a72f8727475b10e4c74e4;p=fanfix.git diff --git a/src/jexer/TComboBox.java b/src/jexer/TComboBox.java index 38224b8..1164e6c 100644 --- a/src/jexer/TComboBox.java +++ b/src/jexer/TComboBox.java @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (C) 2017 Kevin Lamonte + * Copyright (C) 2019 Kevin Lamonte * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -28,12 +28,15 @@ */ package jexer; +import java.util.ArrayList; import java.util.List; import jexer.bits.CellAttributes; import jexer.bits.GraphicsChars; import jexer.event.TKeypressEvent; import jexer.event.TMouseEvent; +import jexer.event.TResizeEvent; +import jexer.event.TResizeEvent.Type; import static jexer.TKeypress.*; /** @@ -61,6 +64,33 @@ public class TComboBox extends TWidget { */ private TAction updateAction = null; + /** + * If true, the field cannot be updated to a value not on the list. + */ + private boolean limitToListValue = true; + + /** + * The height of the list of values when it is shown, or -1 to use the + * number of values in the list as the height. + */ + private int valuesHeight = -1; + + /** + * The values shown by the drop-down list. + */ + private List values = new ArrayList(); + + /** + * When looking for a link between the displayed text and the list + * of values, do a case sensitive search. + */ + private boolean caseSensitive = true; + + /** + * The maximum height of the values drop-down when it is visible. + */ + private int maxValuesHeight = 3; + // ------------------------------------------------------------------------ // Constructors ----------------------------------------------------------- // ------------------------------------------------------------------------ @@ -76,7 +106,7 @@ public class TComboBox extends TWidget { * @param valuesIndex the initial index in values, or -1 for no default * value * @param valuesHeight the height of the values drop-down when it is - * visible + * visible, or -1 to use the number of values as the height of the list * @param updateAction action to call when a new value is selected from * the list or enter is pressed in the edit field */ @@ -87,33 +117,24 @@ public class TComboBox extends TWidget { // Set parent and window super(parent, x, y, width, 1); + assert (values != null); + this.updateAction = updateAction; + this.values = values; + this.valuesHeight = valuesHeight; - field = new TField(this, 0, 0, width - 1, false, "", + field = new TField(this, 0, 0, Math.max(0, width - 3), false, "", updateAction, null); if (valuesIndex >= 0) { field.setText(values.get(valuesIndex)); } - list = new TList(this, values, 0, 1, width, valuesHeight, - new TAction() { - public void DO() { - field.setText(list.getSelected()); - list.setEnabled(false); - list.setVisible(false); - TComboBox.this.setHeight(1); - TComboBox.this.activate(field); - if (updateAction != null) { - updateAction.DO(); - } - } - } - ); - - list.setEnabled(false); - list.setVisible(false); setHeight(1); - activate(field); + if (limitToListValue) { + field.setEnabled(false); + } else { + activate(field); + } } // ------------------------------------------------------------------------ @@ -128,7 +149,8 @@ public class TComboBox extends TWidget { */ private boolean mouseOnArrow(final TMouseEvent mouse) { if ((mouse.getY() == 0) - && (mouse.getX() == getWidth() - 1) + && (mouse.getX() >= getWidth() - 3) + && (mouse.getX() <= getWidth() - 1) ) { return true; } @@ -144,18 +166,15 @@ public class TComboBox extends TWidget { public void onMouseDown(final TMouseEvent mouse) { if ((mouseOnArrow(mouse)) && (mouse.isMouse1())) { // Make the list visible or not. - if (list.isActive()) { - list.setEnabled(false); - list.setVisible(false); - setHeight(1); - activate(field); + if (list != null) { + hideDropdown(); } else { - list.setEnabled(true); - list.setVisible(true); - setHeight(list.getHeight() + 1); - activate(list); + displayDropdown(); } } + + // Pass to parent for the things we don't care about. + super.onMouseDown(mouse); } /** @@ -165,11 +184,15 @@ public class TComboBox extends TWidget { */ @Override public void onKeypress(final TKeypressEvent keypress) { + if (keypress.equals(kbEsc)) { + if (list != null) { + hideDropdown(); + return; + } + } + if (keypress.equals(kbAltDown)) { - list.setEnabled(true); - list.setVisible(true); - setHeight(list.getHeight() + 1); - activate(list); + displayDropdown(); return; } @@ -177,11 +200,8 @@ public class TComboBox extends TWidget { || (keypress.equals(kbShiftTab)) || (keypress.equals(kbBackTab)) ) { - if (list.isActive()) { - list.setEnabled(false); - list.setVisible(false); - setHeight(1); - activate(field); + if (list != null) { + hideDropdown(); return; } } @@ -194,6 +214,33 @@ public class TComboBox extends TWidget { // TWidget ---------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Override TWidget's width: we need to set child widget widths. + * + * @param width new widget width + */ + @Override + public void setWidth(final int width) { + if (field != null) { + field.setWidth(width - 3); + } + if (list != null) { + list.setWidth(width); + } + super.setWidth(width); + } + + /** + * Override TWidget's height: we can only set height at construction + * time. + * + * @param height new widget height (ignored) + */ + @Override + public void setHeight(final int height) { + // Do nothing + } + /** * Draw the combobox down arrow. */ @@ -201,13 +248,22 @@ public class TComboBox extends TWidget { public void draw() { CellAttributes comboBoxColor; + if (!isAbsoluteActive()) { + // We lost focus, turn off the list. + hideDropdown(); + } + if (isAbsoluteActive()) { comboBoxColor = getTheme().getColor("tcombobox.active"); } else { comboBoxColor = getTheme().getColor("tcombobox.inactive"); } - getScreen().putCharXY(getWidth() - 1, 0, GraphicsChars.DOWNARROW, + putCharXY(getWidth() - 3, 0, GraphicsChars.DOWNARROWLEFT, + comboBoxColor); + putCharXY(getWidth() - 2, 0, GraphicsChars.DOWNARROW, + comboBoxColor); + putCharXY(getWidth() - 1, 0, GraphicsChars.DOWNARROWRIGHT, comboBoxColor); } @@ -215,6 +271,28 @@ public class TComboBox extends TWidget { // TComboBox -------------------------------------------------------------- // ------------------------------------------------------------------------ + /** + * Hide the drop-down list. + */ + public void hideList() { + list.setEnabled(false); + list.setVisible(false); + super.setHeight(1); + if (limitToListValue == false) { + activate(field); + } + } + + /** + * Show the drop-down list. + */ + public void showList() { + list.setEnabled(true); + list.setVisible(true); + super.setHeight(list.getHeight() + 1); + activate(list); + } + /** * Get combobox text value. * @@ -230,14 +308,158 @@ public class TComboBox extends TWidget { * @param text the new text in the edit field */ public void setText(final String text) { - field.setText(text); - for (int i = 0; i < list.getMaxSelectedIndex(); i++) { - if (list.getSelected().equals(text)) { - list.setSelectedIndex(i); - return; - } + setText(text, true); + } + + /** + * Set combobox text value. + * + * @param text the new text in the edit field + * @param caseSensitive if true, perform a case-sensitive search for the + * list item + */ + public void setText(final String text, final boolean caseSensitive) { + this.caseSensitive = caseSensitive; + field.setText(text); + if (list != null) { + displayDropdown(); } - list.setSelectedIndex(-1); } + /** + * Set combobox text to one of the list values. + * + * @param index the index in the list + */ + public void setIndex(final int index) { + list.setSelectedIndex(index); + field.setText(list.getSelected()); + } + + /** + * Get a copy of the list of strings to display. + * + * @return the list of strings + */ + public final List getList() { + return list.getList(); + } + + /** + * Set the new list of strings to display. + * + * @param list new list of strings + */ + public final void setList(final List list) { + this.list.setList(list); + this.list.setHeight(Math.max(3, Math.min(list.size() + 1, + maxValuesHeight))); + field.setText(""); + } + + /** + * Make sure the widget displays all its elements correctly according to + * the current size and content. + */ + public void reflowData() { + // TODO: why setW/setH/reflow not enough for the scrollbars? + TList list = this.list; + if (list != null) { + int valuesHeight = this.valuesHeight; + if (valuesHeight < 0) { + valuesHeight = values == null ? 0 : values.size() + 1; + } + + list.onResize(new TResizeEvent(Type.WIDGET, getWidth(), + valuesHeight)); + setHeight(valuesHeight + 1); + } + + field.onResize(new TResizeEvent(Type.WIDGET, getWidth(), + field.getHeight())); + } + + @Override + public void onResize(TResizeEvent resize) { + super.onResize(resize); + reflowData(); + } + + /** + * Display the drop-down menu represented by {@link TComboBox#list}. + */ + private void displayDropdown() { + if (this.list != null) { + hideDropdown(); + } + + int valuesHeight = this.valuesHeight; + if (valuesHeight < 0) { + valuesHeight = values == null ? 0 : values.size() + 1; + } + + TList list = new TList(this, values, 0, 1, getWidth(), valuesHeight, + new TAction() { + @Override + public void DO() { + TList list = TComboBox.this.list; + if (list == null) { + return; + } + + field.setText(list.getSelected()); + hideDropdown(); + + if (updateAction != null) { + updateAction.DO(); + } + } + } + ); + + int i = -1; + if (values != null) { + String current = field.getText(); + for (i = 0 ; i < values.size() ; i++) { + String value = values.get(i); + if ((caseSensitive && current.equals(value)) + || (!caseSensitive && current.equalsIgnoreCase(value))) { + break; + } + } + + if (i >= values.size()) { + i = -1; + } + } + list.setSelectedIndex(i); + + list.setEnabled(true); + list.setVisible(true); + + this.list = list; + + reflowData(); + activate(list); + } + + /** + * Hide the drop-down menu represented by {@link TComboBox#list}. + */ + private void hideDropdown() { + TList list = this.list; + + if (list != null) { + list.setEnabled(false); + list.setVisible(false); + removeChild(list); + + setHeight(1); + if (limitToListValue == false) { + activate(field); + } + + this.list = null; + } + } }