From: Niki Roo Date: Thu, 24 Oct 2019 17:44:01 +0000 (+0200) Subject: Merge branch 'upstream-sep2019-tcombo' into subtree X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=commitdiff_plain;h=738dd8c426dcc6ed2508d68b7985f68d66549889;hp=-c Merge branch 'upstream-sep2019-tcombo' into subtree --- 738dd8c426dcc6ed2508d68b7985f68d66549889 diff --combined TComboBox.java index b64dbde,1164e6c..1164e6c --- a/TComboBox.java +++ b/TComboBox.java @@@ -28,12 -28,15 +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.*; /** @@@ -65,6 -68,23 +68,23 @@@ public class TComboBox extends TWidget * 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. @@@ -85,14 -105,14 +105,14 @@@ * @param values the possible values for the box, shown in the drop-down * @param valuesIndex the initial index in values, or -1 for no default * value - * @param maxValuesHeight the maximum height of the values drop-down when - * it is visible + * @param valuesHeight the height of the values drop-down when it is + * 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 */ public TComboBox(final TWidget parent, final int x, final int y, final int width, final List values, final int valuesIndex, - final int maxValuesHeight, final TAction updateAction) { + final int valuesHeight, final TAction updateAction) { // Set parent and window super(parent, x, y, width, 1); @@@ -100,37 -120,16 +120,16 @@@ assert (values != null); this.updateAction = updateAction; - this.maxValuesHeight = maxValuesHeight; + this.values = values; + this.valuesHeight = valuesHeight; - field = addField(0, 0, width - 3, false, "", updateAction, null); - if ((valuesIndex >= 0) && (valuesIndex < values.size())) { - field.setText(values.get(valuesIndex)); - } - - list = addList(values, 0, 1, width, - Math.max(3, Math.min(values.size() + 1, maxValuesHeight)), - new TAction() { - public void DO() { - field.setText(list.getSelected()); - list.setEnabled(false); - list.setVisible(false); - TComboBox.super.setHeight(1); - if (TComboBox.this.limitToListValue == false) { - TComboBox.this.activate(field); - } - if (updateAction != null) { - updateAction.DO(TComboBox.this); - } - } - } - ); + field = new TField(this, 0, 0, Math.max(0, width - 3), false, "", + updateAction, null); if (valuesIndex >= 0) { - list.setSelectedIndex(valuesIndex); + field.setText(values.get(valuesIndex)); } - list.setEnabled(false); - list.setVisible(false); - super.setHeight(1); + setHeight(1); if (limitToListValue) { field.setEnabled(false); } else { @@@ -167,10 -166,10 +166,10 @@@ public void onMouseDown(final TMouseEvent mouse) { if ((mouseOnArrow(mouse)) && (mouse.isMouse1())) { // Make the list visible or not. - if (list.isActive()) { - hideList(); + if (list != null) { + hideDropdown(); } else { - showList(); + displayDropdown(); } } @@@ -186,14 -185,14 +185,14 @@@ @Override public void onKeypress(final TKeypressEvent keypress) { if (keypress.equals(kbEsc)) { - if (list.isActive()) { - hideList(); + if (list != null) { + hideDropdown(); return; } } if (keypress.equals(kbAltDown)) { - showList(); + displayDropdown(); return; } @@@ -201,8 -200,8 +200,8 @@@ || (keypress.equals(kbShiftTab)) || (keypress.equals(kbBackTab)) ) { - if (list.isActive()) { - hideList(); + if (list != null) { + hideDropdown(); return; } } @@@ -251,9 -250,7 +250,7 @@@ if (!isAbsoluteActive()) { // We lost focus, turn off the list. - if (list.isActive()) { - hideList(); - } + hideDropdown(); } if (isAbsoluteActive()) { @@@ -322,21 -319,11 +319,11 @@@ * list item */ public void setText(final String text, final boolean caseSensitive) { - field.setText(text); - for (int i = 0; i < list.getMaxSelectedIndex(); i++) { - if (caseSensitive == true) { - if (list.getListItem(i).equals(text)) { - list.setSelectedIndex(i); - return; - } - } else { - if (list.getListItem(i).toLowerCase().equals(text.toLowerCase())) { - list.setSelectedIndex(i); - return; - } - } + this.caseSensitive = caseSensitive; + field.setText(text); + if (list != null) { + displayDropdown(); } - list.setSelectedIndex(-1); } /** @@@ -369,5 -356,110 +356,110 @@@ 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; + } + } } diff --combined TWidget.java index e94fed2,eb06175..eb06175 --- a/TWidget.java +++ b/TWidget.java @@@ -184,14 -184,7 +184,7 @@@ public abstract class TWidget implement * @param enabled if true assume enabled */ protected TWidget(final TWidget parent, final boolean enabled) { - this.enabled = enabled; - this.parent = parent; - children = new ArrayList(); - - if (parent != null) { - this.window = parent.window; - parent.addChild(this); - } + this(parent, enabled, 0, 0, 0, 0); } /** @@@ -1145,6 -1138,7 +1138,7 @@@ * @return difference between this.tabOrder and that.tabOrder, or * difference between this.z and that.z, or String.compareTo(text) */ + @Override public final int compareTo(final TWidget that) { if ((this instanceof TWindow) && (that instanceof TWindow) @@@ -1398,6 -1392,29 +1392,29 @@@ children.get(i).tabOrder = i; } } + + /** + * Remove and {@link TWidget#close()} the given child from this {@link TWidget}. + *

+ * Will also reorder the tab values of the remaining children. + * + * @param child the child to remove + * + * @return TRUE if the child was removed, FALSE if it was not found + */ + public boolean removeChild(final TWidget child) { + if (children.remove(child)) { + child.close(); + child.parent = null; + child.window = null; + + resetTabOrder(); + + return true; + } + + return false; + } /** * Switch the active child.