acpi: Narrow workaround for broken interrupt settings
[dragonfly.git] / contrib / dialog / fselect.c
blob282653ee6893cc61ca4180c18bfe5c1eeddadf27
1 /*
2 * $Id: fselect.c,v 1.119 2022/04/03 22:38:16 tom Exp $
4 * fselect.c -- implements the file-selector box
6 * Copyright 2000-2021,2022 Thomas E. Dickey
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License, version 2.1
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to
19 * Free Software Foundation, Inc.
20 * 51 Franklin St., Fifth Floor
21 * Boston, MA 02110, USA.
24 #include <dlg_internals.h>
25 #include <dlg_keys.h>
27 #define EXT_WIDE 1
28 #define HDR_HIGH 1
29 #define BTN_HIGH (1 + 2 * MARGIN) /* Ok/Cancel, also input-box */
30 #define MIN_HIGH (HDR_HIGH - MARGIN + (BTN_HIGH * 2) + 4 * MARGIN)
31 #define MIN_WIDE (2 * MAX(dlg_count_columns(d_label), dlg_count_columns(f_label)) + 6 * MARGIN + 2 * EXT_WIDE)
33 #define MOUSE_D (KEY_MAX + 0)
34 #define MOUSE_F (KEY_MAX + 10000)
35 #define MOUSE_T (KEY_MAX + 20000)
37 typedef enum {
38 sDIRS = -3
39 ,sFILES = -2
40 ,sTEXT = -1
41 } STATES;
43 typedef struct {
44 WINDOW *par; /* parent window */
45 WINDOW *win; /* this window */
46 int length; /* length of the data[] array */
47 int offset; /* index of first item on screen */
48 int choice; /* index of the selection */
49 int mousex; /* base of mouse-code return-values */
50 unsigned allocd;
51 char **data;
52 } LIST;
54 typedef struct {
55 int length;
56 char **data;
57 } MATCH;
59 static void
60 init_list(LIST * list, WINDOW *par, WINDOW *win, int mousex)
62 list->par = par;
63 list->win = win;
64 list->length = 0;
65 list->offset = 0;
66 list->choice = 0;
67 list->mousex = mousex;
68 list->allocd = 0;
69 list->data = 0;
70 dlg_mouse_mkbigregion(getbegy(win), getbegx(win),
71 getmaxy(win), getmaxx(win),
72 mousex, 1, 1, 1 /* by lines */ );
75 static char *
76 leaf_of(char *path)
78 char *leaf = strrchr(path, '/');
79 if (leaf != 0)
80 leaf++;
81 else
82 leaf = path;
83 return leaf;
86 static char *
87 data_of(LIST * list)
89 if (list != 0
90 && list->data != 0)
91 return list->data[list->choice];
92 return 0;
95 static void
96 free_list(LIST * list, int reinit)
98 if (list->data != 0) {
99 int n;
101 for (n = 0; list->data[n] != 0; n++)
102 free(list->data[n]);
103 free(list->data);
104 list->data = 0;
106 if (reinit)
107 init_list(list, list->par, list->win, list->mousex);
110 static void
111 add_to_list(LIST * list, char *text)
113 unsigned need;
115 need = (unsigned) (list->length + 1);
116 if (need + 1 > list->allocd) {
117 list->allocd = 2 * (need + 1);
118 if (list->data == 0) {
119 list->data = dlg_malloc(char *, list->allocd);
120 } else {
121 list->data = dlg_realloc(char *, list->allocd, list->data);
123 assert_ptr(list->data, "add_to_list");
125 list->data[list->length++] = dlg_strclone(text);
126 list->data[list->length] = 0;
129 static void
130 keep_visible(LIST * list)
132 int high = getmaxy(list->win);
134 if (list->choice < list->offset) {
135 list->offset = list->choice;
137 if (list->choice - list->offset >= high)
138 list->offset = list->choice - high + 1;
141 #define Value(c) (int)((c) & 0xff)
143 static int
144 find_choice(char *target, LIST * list)
146 int choice = list->choice;
148 if (*target == 0) {
149 list->choice = 0;
150 } else {
151 int n;
152 int len_1, cmp_1;
154 /* find the match with the longest length. If more than one has the
155 * same length, choose the one with the closest match of the final
156 * character.
158 len_1 = 0;
159 cmp_1 = 256;
160 for (n = 0; n < list->length; n++) {
161 char *a = target;
162 char *b = list->data[n];
163 int len_2, cmp_2;
165 len_2 = 0;
166 while ((*a != 0) && (*b != 0) && (*a == *b)) {
167 a++;
168 b++;
169 len_2++;
171 cmp_2 = Value(*a) - Value(*b);
172 if (cmp_2 < 0)
173 cmp_2 = -cmp_2;
174 if ((len_2 > len_1)
175 || (len_1 == len_2 && cmp_2 < cmp_1)) {
176 len_1 = len_2;
177 cmp_1 = cmp_2;
178 list->choice = n;
182 if (choice != list->choice) {
183 keep_visible(list);
185 return (choice != list->choice);
188 static void
189 display_list(LIST * list)
191 if (list->win != 0) {
192 int n;
193 int x;
194 int y;
195 int top;
196 int bottom;
198 dlg_attr_clear(list->win, getmaxy(list->win), getmaxx(list->win), item_attr);
199 for (n = list->offset; n < list->length && list->data[n]; n++) {
200 y = n - list->offset;
201 if (y >= getmaxy(list->win))
202 break;
203 (void) wmove(list->win, y, 0);
204 if (n == list->choice)
205 dlg_attrset(list->win, item_selected_attr);
206 (void) waddstr(list->win, list->data[n]);
207 dlg_attrset(list->win, item_attr);
209 dlg_attrset(list->win, item_attr);
211 getparyx(list->win, y, x);
213 top = y - 1;
214 bottom = y + getmaxy(list->win);
215 dlg_draw_scrollbar(list->par,
216 (long) list->offset,
217 (long) list->offset,
218 (long) (list->offset + getmaxy(list->win)),
219 (long) (list->length),
220 x + 1,
221 x + getmaxx(list->win),
222 top,
223 bottom,
224 menubox_border2_attr,
225 menubox_border_attr);
227 (void) wmove(list->win, list->choice - list->offset, 0);
228 (void) wnoutrefresh(list->win);
232 /* FIXME: see arrows.c
233 * This workaround is used to allow two lists to have scroll-tabs at the same
234 * time, by reassigning their return-values to be different. Just for
235 * readability, we use the names of keys with similar connotations, though all
236 * that is really required is that they're distinct, so we can put them in a
237 * switch statement.
239 #if USE_MOUSE
240 static void
241 fix_arrows(LIST * list)
243 if (list->win != 0) {
244 int x;
245 int y;
246 int top;
247 int right;
248 int bottom;
250 getparyx(list->win, y, x);
251 top = y - 1;
252 right = getmaxx(list->win);
253 bottom = y + getmaxy(list->win);
255 mouse_mkbutton(top, x, right,
256 ((list->mousex == MOUSE_D)
257 ? KEY_PREVIOUS
258 : KEY_PPAGE));
259 mouse_mkbutton(bottom, x, right,
260 ((list->mousex == MOUSE_D)
261 ? KEY_NEXT
262 : KEY_NPAGE));
266 #else
267 #define fix_arrows(list) /* nothing */
268 #endif
270 static bool
271 show_list(char *target, LIST * list, bool keep)
273 bool changed = keep || find_choice(target, list);
274 display_list(list);
275 return changed;
279 * Highlight the closest match to 'target' in the given list, setting offset
280 * to match.
282 static bool
283 show_both_lists(char *input, LIST * d_list, LIST * f_list, bool keep)
285 char *leaf = leaf_of(input);
287 return show_list(leaf, d_list, keep) || show_list(leaf, f_list, keep);
291 * Move up/down in the given list
293 static bool
294 change_list(int choice, LIST * list)
296 if (data_of(list) != 0) {
297 int last = list->length - 1;
299 choice += list->choice;
300 if (choice < 0)
301 choice = 0;
302 if (choice > last)
303 choice = last;
304 list->choice = choice;
305 keep_visible(list);
306 display_list(list);
307 return TRUE;
309 return FALSE;
312 static void
313 scroll_list(int direction, LIST * list)
315 if (data_of(list) != 0) {
316 int length = getmaxy(list->win);
317 if (change_list(direction * length, list))
318 return;
320 beep();
323 static int
324 compar(const void *a, const void *b)
326 return strcmp(*(const char *const *) a, *(const char *const *) b);
329 static void
330 match(char *name, LIST * d_list, LIST * f_list, MATCH * match_list)
332 char *test = leaf_of(name);
333 size_t test_len = strlen(test);
334 char **matches = dlg_malloc(char *, (size_t) (d_list->length + f_list->length));
335 size_t data_len = 0;
337 if (matches != 0) {
338 int i;
339 char **new_ptr;
341 for (i = 2; i < d_list->length; i++) {
342 if (strncmp(test, d_list->data[i], test_len) == 0) {
343 matches[data_len++] = d_list->data[i];
346 for (i = 0; i < f_list->length; i++) {
347 if (strncmp(test, f_list->data[i], test_len) == 0) {
348 matches[data_len++] = f_list->data[i];
351 if ((new_ptr = dlg_realloc(char *, data_len + 1, matches)) != 0) {
352 matches = new_ptr;
353 } else {
354 free(matches);
355 matches = 0;
356 data_len = 0;
359 match_list->data = matches;
360 match_list->length = (int) data_len;
363 static void
364 free_match(MATCH * match_list)
366 free(match_list->data);
367 match_list->length = 0;
370 static int
371 complete(char *name, LIST * d_list, LIST * f_list, char **buff_ptr)
373 MATCH match_list;
374 char *test;
375 size_t test_len;
376 size_t i;
377 char *buff;
379 match(name, d_list, f_list, &match_list);
380 if (match_list.length == 0) {
381 free(match_list.data);
382 *buff_ptr = NULL;
383 return 0;
386 test = match_list.data[0];
387 test_len = strlen(test);
388 buff = dlg_malloc(char, test_len + 2);
389 if (match_list.length == 1) {
390 strcpy(buff, test);
391 i = test_len;
392 if (test == data_of(d_list)) {
393 buff[test_len] = '/';
394 i++;
396 } else {
397 int j;
398 char *next;
400 for (i = 0; i < test_len; i++) {
401 char test_char = test[i];
402 if (test_char == '\0')
403 break;
404 for (j = 0; j < match_list.length; j++) {
405 if (match_list.data[j][i] != test_char) {
406 break;
409 if (j == match_list.length) {
410 (buff)[i] = test_char;
411 } else
412 break;
414 next = dlg_realloc(char, i + 1, buff);
415 if (next == NULL) {
416 free(buff);
417 *buff_ptr = NULL;
418 return 0;
420 buff = next;
422 free_match(&match_list);
423 buff[i] = '\0';
424 *buff_ptr = buff;
425 return (i != 0);
428 static bool
429 fill_lists(char *current, char *input, LIST * d_list, LIST * f_list, bool keep)
431 bool result = TRUE;
432 bool rescan = FALSE;
433 struct stat sb;
434 int n;
435 char path[MAX_LEN + 1];
437 /* check if we've updated the lists */
438 for (n = 0; current[n] && input[n]; n++) {
439 if (current[n] != input[n])
440 break;
443 if (current[n] == input[n]) {
444 result = FALSE;
445 rescan = (n == 0 && d_list->length == 0);
446 } else if (strchr(current + n, '/') == 0
447 && strchr(input + n, '/') == 0) {
448 result = show_both_lists(input, d_list, f_list, keep);
449 } else {
450 rescan = TRUE;
453 if (rescan) {
454 DIR *dp;
455 size_t have = strlen(input);
456 char *leaf;
458 if (have > MAX_LEN)
459 have = MAX_LEN;
460 memcpy(current, input, have);
461 current[have] = '\0';
463 /* refill the lists */
464 free_list(d_list, TRUE);
465 free_list(f_list, TRUE);
466 memcpy(path, current, have);
467 path[have] = '\0';
468 if ((leaf = strrchr(path, '/')) != 0) {
469 *++leaf = 0;
470 } else {
471 strcpy(path, "./");
472 leaf = path + strlen(path);
474 DLG_TRACE(("opendir '%s'\n", path));
475 if ((dp = opendir(path)) != 0) {
476 DIRENT *de;
478 while ((de = readdir(dp)) != 0) {
479 size_t len = NAMLEN(de);
480 if (len == 0 || (len + have + 2) >= MAX_LEN)
481 continue;
482 memcpy(leaf, de->d_name, len);
483 leaf[len] = '\0';
484 if (stat(path, &sb) == 0) {
485 if ((sb.st_mode & S_IFMT) == S_IFDIR)
486 add_to_list(d_list, leaf);
487 else if (f_list->win)
488 add_to_list(f_list, leaf);
491 (void) closedir(dp);
492 /* sort the lists */
493 if (d_list->data != 0 && d_list->length > 1) {
494 qsort(d_list->data,
495 (size_t) d_list->length,
496 sizeof(d_list->data[0]),
497 compar);
499 if (f_list->data != 0 && f_list->length > 1) {
500 qsort(f_list->data,
501 (size_t) f_list->length,
502 sizeof(f_list->data[0]),
503 compar);
507 (void) show_both_lists(input, d_list, f_list, FALSE);
508 d_list->offset = d_list->choice;
509 f_list->offset = f_list->choice;
510 result = TRUE;
512 return result;
515 static bool
516 usable_state(int state, LIST * dirs, LIST * files)
518 bool result;
520 switch (state) {
521 case sDIRS:
522 result = (dirs->win != 0) && (data_of(dirs) != 0);
523 break;
524 case sFILES:
525 result = (files->win != 0) && (data_of(files) != 0);
526 break;
527 default:
528 result = TRUE;
529 break;
531 return result;
534 #define which_list() ((state == sFILES) \
535 ? &f_list \
536 : ((state == sDIRS) \
537 ? &d_list \
538 : 0))
539 #define NAVIGATE_BINDINGS \
540 DLG_KEYS_DATA( DLGK_FIELD_NEXT, KEY_RIGHT ), \
541 DLG_KEYS_DATA( DLGK_FIELD_NEXT, TAB ), \
542 DLG_KEYS_DATA( DLGK_FIELD_PREV, KEY_BTAB ), \
543 DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_DOWN ), \
544 DLG_KEYS_DATA( DLGK_ITEM_NEXT, CHR_NEXT ), \
545 DLG_KEYS_DATA( DLGK_ITEM_NEXT, KEY_NEXT ), \
546 DLG_KEYS_DATA( DLGK_ITEM_PREV, CHR_PREVIOUS ), \
547 DLG_KEYS_DATA( DLGK_ITEM_PREV, KEY_UP ), \
548 DLG_KEYS_DATA( DLGK_PAGE_NEXT, KEY_NPAGE ), \
549 DLG_KEYS_DATA( DLGK_PAGE_PREV, KEY_PPAGE )
552 * Display a dialog box for entering a filename
554 static int
555 dlg_fselect(const char *title, const char *path, int height, int width, int dselect)
557 /* *INDENT-OFF* */
558 static DLG_KEYS_BINDING binding[] = {
559 HELPKEY_BINDINGS,
560 ENTERKEY_BINDINGS,
561 NAVIGATE_BINDINGS,
562 TOGGLEKEY_BINDINGS,
563 END_KEYS_BINDING
565 static DLG_KEYS_BINDING binding2[] = {
566 INPUTSTR_BINDINGS,
567 HELPKEY_BINDINGS,
568 ENTERKEY_BINDINGS,
569 NAVIGATE_BINDINGS,
570 TOGGLEKEY_BINDINGS,
571 END_KEYS_BINDING
573 /* *INDENT-ON* */
575 #ifdef KEY_RESIZE
576 int old_height = height;
577 int old_width = width;
578 bool resized = FALSE;
579 #endif
580 int tbox_y, tbox_x, tbox_width, tbox_height;
581 int dbox_y, dbox_x, dbox_width, dbox_height;
582 int fbox_y, fbox_x, fbox_width, fbox_height;
583 int show_buttons = TRUE;
584 int offset = 0;
585 int key = 0;
586 int fkey = FALSE;
587 int code;
588 int result = DLG_EXIT_UNKNOWN;
589 int state = dialog_vars.default_button >= 0 ? dlg_default_button() : sTEXT;
590 int button;
591 bool first = (state == sTEXT);
592 bool first_trace = TRUE;
593 char *input;
594 char *completed;
595 char current[MAX_LEN + 1];
596 WINDOW *dialog = 0;
597 WINDOW *w_text = 0;
598 WINDOW *w_work = 0;
599 const char **buttons = dlg_ok_labels();
600 const char *d_label = _("Directories");
601 const char *f_label = _("Files");
602 char *partial = 0;
603 int min_wide = MIN_WIDE;
604 int min_items = height ? 0 : 4;
605 LIST d_list, f_list;
607 DLG_TRACE(("# %s args:\n", dselect ? "dselect" : "fselect"));
608 DLG_TRACE2S("title", title);
609 DLG_TRACE2S("path", path);
610 DLG_TRACE2N("height", height);
611 DLG_TRACE2N("width", width);
613 dlg_does_output();
615 /* Set up the initial value */
616 input = dlg_set_result(path);
617 offset = (int) strlen(input);
618 *current = 0;
620 dlg_button_layout(buttons, &min_wide);
622 #ifdef KEY_RESIZE
623 retry:
624 #endif
625 if (height > 0)
626 height += MIN_HIGH;
627 dlg_auto_size(title, "", &height, &width, MIN_HIGH + min_items, min_wide);
629 dlg_print_size(height, width);
630 dlg_ctl_size(height, width);
632 dialog = dlg_new_window(height, width,
633 dlg_box_y_ordinate(height),
634 dlg_box_x_ordinate(width));
635 dlg_register_window(dialog, "fselect", binding);
636 dlg_register_buttons(dialog, "fselect", buttons);
638 dlg_mouse_setbase(0, 0);
640 dlg_draw_box2(dialog, 0, 0, height, width, dialog_attr, border_attr, border2_attr);
641 dlg_draw_bottom_box2(dialog, border_attr, border2_attr, dialog_attr);
642 dlg_draw_title(dialog, title);
644 dlg_attrset(dialog, dialog_attr);
646 /* Draw the input field box */
647 tbox_height = 1;
648 tbox_width = width - (4 * MARGIN + 2);
649 tbox_y = height - (BTN_HIGH * 2) + MARGIN;
650 tbox_x = (width - tbox_width) / 2;
652 w_text = dlg_der_window(dialog, tbox_height, tbox_width, tbox_y, tbox_x);
653 if (w_text == 0) {
654 result = DLG_EXIT_ERROR;
655 goto finish;
658 dlg_draw_box(dialog, tbox_y - MARGIN, tbox_x - MARGIN,
659 (2 * MARGIN + 1), tbox_width + (MARGIN + EXT_WIDE),
660 menubox_border_attr, menubox_border2_attr);
661 dlg_mouse_mkbigregion(getbegy(dialog) + tbox_y - MARGIN,
662 getbegx(dialog) + tbox_x - MARGIN,
663 1 + (2 * MARGIN),
664 tbox_width + (MARGIN + EXT_WIDE),
665 MOUSE_T, 1, 1, 3 /* doesn't matter */ );
667 dlg_register_window(w_text, "fselect2", binding2);
669 /* Draw the directory listing box */
670 if (dselect)
671 dbox_width = (width - (6 * MARGIN));
672 else
673 dbox_width = (width - (6 * MARGIN + 2 * EXT_WIDE)) / 2;
674 dbox_height = height - MIN_HIGH;
675 dbox_y = (2 * MARGIN + 1);
676 dbox_x = tbox_x;
678 w_work = dlg_der_window(dialog, dbox_height, dbox_width, dbox_y, dbox_x);
679 if (w_work == 0) {
680 result = DLG_EXIT_ERROR;
681 goto finish;
684 (void) mvwaddstr(dialog, dbox_y - (MARGIN + 1), dbox_x - MARGIN, d_label);
685 dlg_draw_box(dialog,
686 dbox_y - MARGIN, dbox_x - MARGIN,
687 dbox_height + (MARGIN + 1), dbox_width + (MARGIN + 1),
688 menubox_border_attr, menubox_border2_attr);
689 init_list(&d_list, dialog, w_work, MOUSE_D);
691 if (!dselect) {
692 /* Draw the filename listing box */
693 fbox_height = dbox_height;
694 fbox_width = dbox_width;
695 fbox_y = dbox_y;
696 fbox_x = tbox_x + dbox_width + (2 * MARGIN);
698 w_work = dlg_der_window(dialog, fbox_height, fbox_width, fbox_y, fbox_x);
699 if (w_work == 0) {
700 result = DLG_EXIT_ERROR;
701 goto finish;
704 (void) mvwaddstr(dialog, fbox_y - (MARGIN + 1), fbox_x - MARGIN, f_label);
705 dlg_draw_box(dialog,
706 fbox_y - MARGIN, fbox_x - MARGIN,
707 fbox_height + (MARGIN + 1), fbox_width + (MARGIN + 1),
708 menubox_border_attr, menubox_border2_attr);
709 init_list(&f_list, dialog, w_work, MOUSE_F);
710 } else {
711 memset(&f_list, 0, sizeof(f_list));
714 while (result == DLG_EXIT_UNKNOWN) {
716 if (fill_lists(current, input, &d_list, &f_list, state < sTEXT))
717 show_buttons = TRUE;
719 #ifdef KEY_RESIZE
720 if (resized) {
721 resized = FALSE;
722 dlg_show_string(w_text, input, offset, inputbox_attr,
723 0, 0, tbox_width, FALSE, first);
725 #endif
728 * The last field drawn determines where the cursor is shown:
730 if (show_buttons) {
731 show_buttons = FALSE;
732 button = (state < 0) ? 0 : state;
733 dlg_draw_buttons(dialog, height - 2, 0, buttons, button, FALSE, width);
736 if (first_trace) {
737 first_trace = FALSE;
738 dlg_trace_win(dialog);
741 if (state < 0) {
742 switch (state) {
743 case sTEXT:
744 dlg_set_focus(dialog, w_text);
745 break;
746 case sFILES:
747 dlg_set_focus(dialog, f_list.win);
748 break;
749 case sDIRS:
750 dlg_set_focus(dialog, d_list.win);
751 break;
755 if (first) {
756 (void) wrefresh(dialog);
757 } else {
758 fix_arrows(&d_list);
759 fix_arrows(&f_list);
760 key = dlg_mouse_wgetch((state == sTEXT) ? w_text : dialog, &fkey);
761 if (dlg_result_key(key, fkey, &result)) {
762 if (!dlg_button_key(result, &button, &key, &fkey))
763 break;
767 if (key == DLGK_TOGGLE) {
768 key = DLGK_SELECT;
769 fkey = TRUE;
772 if (fkey) {
773 switch (key) {
774 case DLGK_MOUSE(KEY_PREVIOUS):
775 state = sDIRS;
776 scroll_list(-1, which_list());
777 continue;
778 case DLGK_MOUSE(KEY_NEXT):
779 state = sDIRS;
780 scroll_list(1, which_list());
781 continue;
782 case DLGK_MOUSE(KEY_PPAGE):
783 state = sFILES;
784 scroll_list(-1, which_list());
785 continue;
786 case DLGK_MOUSE(KEY_NPAGE):
787 state = sFILES;
788 scroll_list(1, which_list());
789 continue;
790 case DLGK_PAGE_PREV:
791 scroll_list(-1, which_list());
792 continue;
793 case DLGK_PAGE_NEXT:
794 scroll_list(1, which_list());
795 continue;
796 case DLGK_ITEM_PREV:
797 if (change_list(-1, which_list()))
798 continue;
799 /* FALLTHRU */
800 case DLGK_FIELD_PREV:
801 show_buttons = TRUE;
802 do {
803 state = dlg_prev_ok_buttonindex(state, sDIRS);
804 } while (!usable_state(state, &d_list, &f_list));
805 continue;
806 case DLGK_ITEM_NEXT:
807 if (change_list(1, which_list()))
808 continue;
809 /* FALLTHRU */
810 case DLGK_FIELD_NEXT:
811 show_buttons = TRUE;
812 do {
813 state = dlg_next_ok_buttonindex(state, sDIRS);
814 } while (!usable_state(state, &d_list, &f_list));
815 continue;
816 case DLGK_SELECT:
817 completed = 0;
818 if (partial != 0) {
819 free(partial);
820 partial = 0;
822 if (state == sFILES && !dselect) {
823 completed = data_of(&f_list);
824 } else if (state == sDIRS) {
825 completed = data_of(&d_list);
826 } else {
827 if (complete(input, &d_list, &f_list, &partial)) {
828 completed = partial;
831 if (completed != 0) {
832 state = sTEXT;
833 show_buttons = TRUE;
834 strcpy(leaf_of(input), completed);
835 offset = (int) strlen(input);
836 dlg_show_string(w_text, input, offset, inputbox_attr,
837 0, 0, tbox_width, 0, first);
838 if (partial != NULL) {
839 free(partial);
840 partial = 0;
842 continue;
843 } else { /* if (state < sTEXT) */
844 (void) beep();
845 continue;
847 /* FALLTHRU */
848 case DLGK_ENTER:
849 result = (state > 0) ? dlg_enter_buttoncode(state) : DLG_EXIT_OK;
850 continue;
851 case DLGK_LEAVE:
852 if (state >= 0)
853 result = dlg_ok_buttoncode(state);
854 break;
855 #ifdef KEY_RESIZE
856 case KEY_RESIZE:
857 dlg_will_resize(dialog);
858 /* reset data */
859 height = old_height;
860 width = old_width;
861 show_buttons = TRUE;
862 *current = 0;
863 resized = TRUE;
864 /* repaint */
865 free_list(&d_list, FALSE);
866 free_list(&f_list, FALSE);
867 _dlg_resize_cleanup(dialog);
868 goto retry;
869 #endif
870 default:
871 if (key >= DLGK_MOUSE(MOUSE_T)) {
872 state = sTEXT;
873 continue;
874 } else if (key >= DLGK_MOUSE(MOUSE_F)) {
875 if (f_list.win != 0) {
876 state = sFILES;
877 f_list.choice = (key - DLGK_MOUSE(MOUSE_F)) + f_list.offset;
878 display_list(&f_list);
880 continue;
881 } else if (key >= DLGK_MOUSE(MOUSE_D)) {
882 if (d_list.win != 0) {
883 state = sDIRS;
884 d_list.choice = (key - DLGK_MOUSE(MOUSE_D)) + d_list.offset;
885 display_list(&d_list);
887 continue;
888 } else if (is_DLGK_MOUSE(key)
889 && (code = dlg_ok_buttoncode(key - M_EVENT)) >= 0) {
890 result = code;
891 continue;
893 break;
897 if (state < 0) { /* Input box selected if we're editing */
898 int edit = dlg_edit_string(input, &offset, key, fkey, first);
900 if (edit) {
901 dlg_show_string(w_text, input, offset, inputbox_attr,
902 0, 0, tbox_width, 0, first);
903 first = FALSE;
904 state = sTEXT;
906 } else if ((code = dlg_char_to_button(key, buttons)) >= 0) {
907 result = dlg_ok_buttoncode(code);
908 break;
911 AddLastKey();
913 dlg_unregister_window(w_text);
914 dlg_del_window(dialog);
915 dlg_mouse_free_regions();
916 free_list(&d_list, FALSE);
917 free_list(&f_list, FALSE);
919 finish:
920 if (partial != 0)
921 free(partial);
922 return result;
926 * Display a dialog box for entering a filename
929 dialog_fselect(const char *title, const char *path, int height, int width)
931 return dlg_fselect(title, path, height, width, FALSE);
935 * Display a dialog box for entering a directory
938 dialog_dselect(const char *title, const char *path, int height, int width)
940 return dlg_fselect(title, path, height, width, TRUE);