@@ -28,19 +28,22 @@ gui_combobox_t::gui_combobox_t(gui_scrolled_list_t::item_compare_func cmp) :
2828{
2929 minimize = false ;
3030 bt_prev.set_typ (button_t ::arrowleft);
31- bt_prev.set_pos ( scr_coord (0 ,2 ) );
31+ bt_prev.set_pos (scr_coord (0 , 2 ) );
3232
3333 bt_next.set_typ (button_t ::arrowright);
3434
35- set_focusable ( true ); // needed, otherwise fails on closing when clicking elsewhere!
35+ set_focusable (true ); // needed, otherwise fails on closing when clicking elsewhere!
3636
37+ search_str[0 ] = 0 ;
3738 editstr[0 ] = 0 ;
3839 old_editstr[0 ] = 0 ;
3940 textinp.add_listener (this );
4041
4142 first_call = true ;
4243 finish = false ;
4344 wrapping = true ;
45+ force_selection = false ;
46+ selection_when_open = -1 ;
4447 droplist.set_visible (false );
4548 droplist.add_listener (this );
4649 closed_size = get_size ();
@@ -99,17 +102,31 @@ DBG_MESSAGE("event","HOWDY!");
99102 }
100103
101104 // goto next/previous choice
102- if ( IS_KEYDOWN (ev) && (ev->ev_code == SIM_KEYCODE_UP || ev->ev_code == SIM_KEYCODE_DOWN) ) {
105+ if ( IS_KEYDOWN (ev) && (ev->ev_code == SIM_KEYCODE_UP || ev->ev_code == SIM_KEYCODE_DOWN) && droplist.get_count ()>0 ) {
106+ int delta = ev->ev_code == SIM_KEYCODE_UP ? -1 : 1 ;
103107 int sel = droplist.get_selection ();
104- if ( ev->ev_code == SIM_KEYCODE_UP ) {
105- set_selection ( sel > 0 ? sel-1 : (wrapping ? droplist.get_count ()-1 : 0 ) );
108+ if (delta < 0 && sel < 0 ) {
109+ // start at last
110+ sel = 0 ;
106111 }
107- else {
108- set_selection ( sel < (sint32)droplist.get_count ()-1 ? sel+1 : (wrapping ? 0 : droplist.get_count ()-1 ) );
112+ const int cnt = droplist.get_count ();
113+ bool found = false ;
114+ for (int i = 0 ; i < droplist.get_count (); i++) {
115+ sel = (sel + delta + cnt) % cnt;
116+ if (droplist.get_element (sel)->is_visible ()) {
117+ found = true ;
118+ break ;
119+ }
120+ }
121+ if (sel != droplist.get_selection ()) {
122+ droplist.set_selection (sel);
123+ if (!droplist.is_visible ()) {
124+ // update if we are not in the open list scrolling
125+ value_t p;
126+ p.i = droplist.get_selection ();
127+ call_listeners (p);
128+ }
109129 }
110- value_t p;
111- p.i = droplist.get_selection ();
112- call_listeners ( p );
113130 return true ;
114131 }
115132
@@ -138,6 +155,7 @@ DBG_MESSAGE("event","HOWDY!");
138155
139156 // else prepare for selection (after a left mbutton release event!)
140157 droplist.set_visible (true );
158+ selection_when_open = droplist.get_selection ();
141159
142160 // determine possible size of droplist and whether open below/above input field
143161 scr_coord_val win_height = win_get_top ()->get_windowsize ().h - D_TITLEBAR_HEIGHT;
@@ -160,6 +178,9 @@ DBG_MESSAGE("event","HOWDY!");
160178 sel = 0 ;
161179 }
162180 droplist.show_selection (sel);
181+ search_str[0 ] = 0 ;
182+ textinp.set_text (NULL , 0 );
183+ textinp.set_text (search_str, lengthof (search_str));
163184 }
164185 else if (droplist.is_visible ()) {
165186
@@ -169,16 +190,8 @@ DBG_MESSAGE("event","HOWDY!");
169190 event_t ev2 = *ev;
170191 ev2.move_origin (droplist.get_pos ());
171192 if ( droplist.infowin_event (&ev2) ) {
172- if ( droplist.get_selection () != old_selection ) {
173- // close box will anyway call
174- if ( !IS_LEFTRELEASE ( ev ) ) {
175- // in case of LEFTRELEASE, close_box will call it again
176- call_listeners ( droplist.get_selection () );
177- }
178- finish = true ;
179- }
180- // we selected something?
181- if (finish && IS_LEFTRELEASE (ev)) {
193+ finish = droplist.get_selection () != old_selection;
194+ if (IS_LEFTRELEASE (ev)) {
182195 close_box ();
183196 }
184197 }
@@ -200,7 +213,27 @@ DBG_MESSAGE("gui_combobox_t::infowin_event()","close");
200213 else {
201214 // finally handle textinput
202215 gui_scrolled_list_t ::scrollitem_t *item = droplist.get_selected_item ();
203- if ( item==NULL || item->is_editable () ) {
216+ if (droplist.is_visible ()) {
217+ // we are searching, not renaming
218+ int first_match = -1 ;
219+ event_t ev2 = *ev;
220+ ev2.move_origin (textinp.get_pos ());
221+ char same = search_str[0 ];
222+ if (textinp.infowin_event (&ev2)) {
223+ if (search_str[0 ]!=same) {
224+ for (int i = 0 ; i < droplist.get_count (); i++) {
225+ droplist.get_element (i)->set_visible (strstr (droplist.get_element (i)->get_text (), search_str));
226+ if (droplist.get_element (i)->is_visible () && first_match <= droplist.get_selection ()) {
227+ first_match = i;
228+ }
229+ }
230+ droplist.show_selection (first_match);
231+ droplist.set_selection (first_match);
232+ }
233+ return true ;
234+ }
235+ }
236+ else if ( item==NULL || item->is_editable () ) {
204237 event_t ev2 = *ev;
205238 ev2.move_origin (textinp.get_pos ());
206239 return textinp.infowin_event (&ev2);
@@ -234,8 +267,11 @@ void gui_combobox_t::draw(scr_coord offset)
234267 last_draw_offset = offset;
235268 // text changed? Then update it
236269 gui_scrolled_list_t ::scrollitem_t *item = droplist.get_selected_item ();
237- if ( item && item->is_valid () && item->is_editable () && strncmp ( item->get_text (), old_editstr, 127 ) ) {
238- reset_selected_item_name ();
270+ if (!droplist.is_visible ()) {
271+ // maybe rename item unless we are searching reight now
272+ if (item && item->is_valid () && item->is_editable () && strncmp (item->get_text (), old_editstr, lengthof (old_editstr))) {
273+ reset_selected_item_name ();
274+ }
239275 }
240276
241277 offset += pos;
@@ -274,18 +310,22 @@ void gui_combobox_t::disable()
274310 */
275311void gui_combobox_t::set_selection (int s)
276312{
313+ search_str[0 ] = 0 ;
314+
277315 // try to finish renaming first
278316 rename_selected_item ();
279317
318+ // just set it
319+ if (force_selection && s < 0 && droplist.get_count () > 0 ) {
320+ // force always a valid selection unless empty
321+ s = 0 ;
322+ }
323+ droplist.set_selection (s);
280324 if (droplist.is_visible () && !finish) {
281325 // visible and not closing
282326 // change also offset of scrollbar
283327 droplist.show_selection ( s );
284328 }
285- else {
286- // just set it
287- droplist.set_selection (s);
288- }
289329 // edit the text
290330 reset_selected_item_name ();
291331}
@@ -300,7 +340,7 @@ void gui_combobox_t::rename_selected_item()
300340 // if name was not changed in the meantime, we can rename it
301341 if ( item && item->is_valid () && item->is_editable () ) {
302342 const char *current_str = ((gui_scrolled_list_t ::const_text_scrollitem_t *)item)->get_text ();
303- if ( strncmp ( current_str, old_editstr, 127 )== 0 && strncmp ( current_str, editstr, 127 )!= 0 ) {
343+ if ( strncmp ( current_str, old_editstr, lengthof (old_editstr)- 1 ) == 0 && strncmp ( current_str, editstr, lengthof (old_editstr)- 1 ) != 0 ) {
304344 item->set_text (editstr);
305345 }
306346 }
@@ -312,14 +352,18 @@ void gui_combobox_t::reset_selected_item_name()
312352 gui_scrolled_list_t ::scrollitem_t *item = droplist.get_selected_item ();
313353 if ( item==NULL ) {
314354 editstr[0 ] = 0 ;
315- textinp.set_text ( editstr, 0 );
355+ if (!droplist.is_visible ()) {
356+ textinp.set_text ( editstr, 0 );
357+ }
316358 droplist.set_selection (-1 );
317359 }
318360 else if ( item->is_valid () ) {
319361 const char *current_str = ((gui_scrolled_list_t ::const_text_scrollitem_t *)item)->get_text ();
320- if ( strncmp ( current_str, old_editstr, 127 )!=0 ) {
362+ if ( strncmp ( current_str, old_editstr, lengthof (old_editstr)- 1 )!=0 ) {
321363 tstrncpy ( editstr, current_str, lengthof (editstr) );
322- textinp.set_text ( editstr, lengthof (editstr) );
364+ if (!droplist.is_visible ()) {
365+ textinp.set_text (editstr, lengthof (editstr));
366+ }
323367 }
324368 }
325369 tstrncpy ( old_editstr, editstr, lengthof (old_editstr) );
@@ -331,12 +375,27 @@ void gui_combobox_t::reset_selected_item_name()
331375*/
332376void gui_combobox_t::close_box ()
333377{
334- if (finish) {
378+ bool selection_changed = selection_when_open != droplist.get_selection ();
379+ reset_selected_item_name ();
380+ if (finish && selection_changed) {
335381 value_t p;
336382 p.i = droplist.get_selection ();
337383 call_listeners (p);
338384 finish = false ;
339385 }
386+ if (search_str[0 ] || selection_changed) {
387+ // reset filter: set all visible again
388+ search_str[0 ] = 0 ;
389+ for (int i = 0 ; i < droplist.get_count (); i++) {
390+ droplist.get_element (i)->set_visible (true );
391+ }
392+ textinp.set_text (NULL , 0 ); // also to reset cursor position
393+ }
394+ textinp.set_text (editstr, lengthof (editstr) );
395+ if (!selection_changed) {
396+ sint32 len = strlen (editstr);
397+ textinp.set_cursor (len, len);
398+ }
340399 droplist.set_visible (false );
341400 first_call = true ;
342401}
@@ -411,6 +470,7 @@ scr_size gui_combobox_t::get_max_size() const
411470
412471void gui_combobox_t::rdwr ( loadsave_t *file )
413472{
473+ // todo: all pending edits and searches are lost/executed
414474 sint32 i = get_selection ();
415475 file->rdwr_long (i);
416476 set_selection (i);
0 commit comments