55import javafx .collections .ListChangeListener ;
66import javafx .collections .ObservableList ;
77import javafx .geometry .Bounds ;
8+ import javafx .geometry .Pos ;
89import javafx .scene .Node ;
9- import javafx .scene .control .Button ;
10- import javafx .scene .control .ListCell ;
11- import javafx .scene .control .ListView ;
12- import javafx .scene .control .TextField ;
10+ import javafx .scene .control .*;
1311import javafx .scene .input .KeyCode ;
12+ import javafx .scene .layout .HBox ;
13+ import javafx .scene .layout .Priority ;
14+ import javafx .scene .layout .StackPane ;
1415import javafx .stage .Popup ;
1516
1617import java .util .function .Consumer ;
@@ -32,7 +33,6 @@ public class SearchPopup<T> {
3233 public SearchPopup () {
3334 popup .setAutoHide (true );
3435 popup .getContent ().add (suggestionList );
35- suggestionList .setMaxHeight (150 );
3636
3737 setupStyle ();
3838
@@ -74,8 +74,13 @@ public SearchPopup() {
7474 } else if (ev .getCode () == KeyCode .UP &&
7575 suggestionList .getSelectionModel ().getSelectedIndex () == 0 ) {
7676 searchField .requestFocus ();
77+ } else if (ev .getCode () == KeyCode .ESCAPE ) {
78+ hide ();
79+ searchField .getParent ().requestFocus ();
7780 }
7881 });
82+
83+ // Mouse events
7984 suggestionList .setOnMouseClicked (ev -> {
8085 T selected = suggestionList .getSelectionModel ().getSelectedItem ();
8186 if (selected != null ) {
@@ -84,14 +89,7 @@ public SearchPopup() {
8489
8590 });
8691
87- // Custom string for suggestions
88- suggestionList .setCellFactory (listView -> new ListCell <>() {
89- @ Override
90- protected void updateItem (T item , boolean empty ) {
91- super .updateItem (item , empty );
92- setText ((empty || item == null ) ? null : displayTextFunction .apply (item ));
93- }
94- });
92+ searchField .setOnMouseClicked (ev -> show (searchField ));
9593 }
9694
9795 private void filterList (String input ) {
@@ -113,10 +111,42 @@ private void handleSelection(T selected) {
113111 if (selectionHandler != null ) selectionHandler .accept (selected );
114112 popup .hide ();
115113 searchField .clear ();
114+ searchField .setPromptText ("Select project…" );
115+ searchField .getParent ().requestFocus ();
116116 }
117117
118118 private void setupStyle () {
119- searchField .getStyleClass ().add ("text-field" );
119+ HBox .setHgrow (searchField , Priority .ALWAYS );
120+ searchField .setPromptText ("Select project…" );
121+ searchField .getStyleClass ().add ("combo-box" );
122+
123+ suggestionList .getStyleClass ().add ("scroll-pane" );
124+ suggestionList .setMaxHeight (200 );
125+
126+ suggestionList .setCellFactory (listView -> new ListCell <>() {
127+ private final Label label = new Label ();
128+ private final StackPane pane = new StackPane (label );
129+
130+ {
131+ label .setWrapText (true );
132+ label .setStyle ("-fx-padding: 5;" );
133+ pane .setAlignment (Pos .CENTER_LEFT );
134+ pane .setMinWidth (0 );
135+ pane .setPrefWidth (1 );
136+ }
137+
138+ @ Override
139+ protected void updateItem (T item , boolean empty ) {
140+ super .updateItem (item , empty );
141+ if (empty || item == null ) {
142+ setGraphic (null );
143+ } else {
144+ label .setText (displayTextFunction .apply (item ));
145+ setGraphic (pane );
146+ }
147+ }
148+ });
149+
120150 showSuggestionsButton .getStyleClass ().add ("secondary-button" );
121151 }
122152
@@ -152,6 +182,7 @@ public Button getSuggestionsButton() {
152182 public void show (Node owner ) {
153183 if (owner == null ) return ;
154184 Bounds bounds = owner .localToScreen (owner .getBoundsInLocal ());
185+ suggestionList .setPrefWidth (searchField .getWidth ());
155186 popup .show (owner , bounds .getMinX (), bounds .getMaxY ());
156187 }
157188
0 commit comments