1 /* Hiearchic listboxes browser dialog commons */
11 #include "bfu/button.h"
12 #include "bfu/dialog.h"
13 #include "bfu/hierbox.h"
14 #include "bfu/inpfield.h"
15 #include "bfu/listbox.h"
16 #include "bfu/msgbox.h"
18 #include "config/kbdbind.h"
19 #include "intl/gettext/libintl.h"
20 #include "protocol/uri.h"
21 #include "session/task.h"
22 #include "terminal/screen.h"
23 #include "terminal/tab.h"
24 #include "terminal/terminal.h"
28 update_hierbox_browser(struct hierbox_browser
*browser
)
30 struct hierbox_dialog_list_item
*item
;
32 foreach (item
, browser
->dialogs
) {
33 redraw_windows(REDRAW_WINDOW_AND_FRONT
, item
->dlg_data
->win
);
38 /* Common backend for listbox adding */
40 add_listbox_item(struct hierbox_browser
*browser
, struct listbox_item
*root
,
41 enum listbox_item_type type
, void *data
, int add_position
)
43 struct listbox_item
*item
;
46 assertm(browser
!= NULL
, "Nowhere to add new list box item");
47 root
= &browser
->root
;
50 item
= mem_calloc(1, sizeof(*item
));
51 if (!item
) return NULL
;
53 init_list(item
->child
);
58 item
->depth
= root
->depth
+ 1;
60 /* TODO: Possibility to sort by making add_position into a flag */
62 add_to_list_end(root
->child
, item
);
64 add_to_list(root
->child
, item
);
66 if (browser
) update_hierbox_browser(browser
);
72 /* Find a listbox item to replace @item. This is done by trying first to
73 * traverse down then up, and if both traversals end up returning the @item
74 * (that is, it is the last item in the box), return NULL. */
75 static inline struct listbox_item
*
76 replace_listbox_item(struct listbox_item
*item
, struct listbox_data
*data
)
78 struct listbox_item
*new_item
;
80 new_item
= traverse_listbox_items_list(item
, data
, 1, 1, NULL
, NULL
);
81 if (item
!= new_item
) return new_item
;
83 new_item
= traverse_listbox_items_list(item
, data
, -1, 1, NULL
, NULL
);
84 return (item
== new_item
) ? NULL
: new_item
;
88 done_listbox_item(struct hierbox_browser
*browser
, struct listbox_item
*item
)
90 struct listbox_data
*box_data
;
92 assert(item
&& list_empty(item
->child
));
93 if_assert_failed
return;
95 /* The option dialog needs this test */
97 /* If we are removing the top or the selected box
98 * we have to figure out a replacement. */
100 foreach (box_data
, browser
->boxes
) {
101 if (box_data
->sel
== item
)
102 box_data
->sel
= replace_listbox_item(item
,
105 if (box_data
->top
== item
)
106 box_data
->top
= replace_listbox_item(item
,
112 if (item
->visible
) update_hierbox_browser(browser
);
120 recursively_set_expanded(struct listbox_item
*item
, int expanded
)
122 struct listbox_item
*child
;
124 if (item
->type
!= BI_FOLDER
)
127 item
->expanded
= expanded
;
129 foreach (child
, item
->child
)
130 recursively_set_expanded(child
, expanded
);
133 static widget_handler_status_T
134 hierbox_ev_kbd(struct dialog_data
*dlg_data
)
136 struct hierbox_browser
*browser
= dlg_data
->dlg
->udata2
;
137 struct widget_data
*widget_data
= dlg_data
->widgets_data
;
138 struct widget
*widget
= widget_data
->widget
;
139 struct listbox_data
*box
;
140 struct listbox_item
*selected
;
141 enum menu_action action_id
;
142 struct term_event
*ev
= dlg_data
->term_event
;
144 /* Check if listbox has something to say to this */
146 && widget
->ops
->kbd(dlg_data
, widget_data
)
148 return EVENT_PROCESSED
;
150 box
= get_dlg_listbox_data(dlg_data
);
152 action_id
= kbd_action(KEYMAP_MENU
, ev
, NULL
);
155 case ACT_MENU_SELECT
:
156 if (!selected
) return EVENT_PROCESSED
;
157 if (selected
->type
!= BI_FOLDER
)
158 return EVENT_NOT_PROCESSED
;
159 selected
->expanded
= !selected
->expanded
;
162 case ACT_MENU_UNEXPAND
:
163 /* Recursively unexpand all folders */
164 if (!selected
) return EVENT_PROCESSED
;
166 /* Special trick: if the folder is already
167 * folded, jump to the parent folder, so the
168 * next time when user presses the key, the
169 * whole parent folder will be closed. */
170 if (list_empty(selected
->child
)
171 || !selected
->expanded
) {
172 struct listbox_item
*root
;
174 root
= box
->ops
->get_root(selected
);
176 listbox_sel(widget_data
, root
);
179 } else if (selected
->type
== BI_FOLDER
) {
180 recursively_set_expanded(selected
, 0);
184 case ACT_MENU_EXPAND
:
185 /* Recursively expand all folders */
187 if (!selected
|| selected
->type
!= BI_FOLDER
)
188 return EVENT_PROCESSED
;
190 recursively_set_expanded(selected
, 1);
193 case ACT_MENU_SEARCH
:
194 if (!box
->ops
->match
)
195 return EVENT_NOT_PROCESSED
;
197 push_hierbox_search_button(dlg_data
, NULL
);
198 return EVENT_PROCESSED
;
201 return EVENT_NOT_PROCESSED
;
205 if (browser
->expansion_callback
)
206 browser
->expansion_callback();
208 display_widget(dlg_data
, widget_data
);
210 return EVENT_PROCESSED
;
213 static widget_handler_status_T
214 hierbox_ev_init(struct dialog_data
*dlg_data
)
216 struct hierbox_browser
*browser
= dlg_data
->dlg
->udata2
;
217 struct hierbox_dialog_list_item
*item
;
218 struct listbox_item
*litem
;
220 /* If we fail here it only means automatic updating
221 * will not be possible so no need to panic. */
222 item
= mem_alloc(sizeof(*item
));
224 item
->dlg_data
= dlg_data
;
225 add_to_list(browser
->dialogs
, item
);
228 foreach (litem
, browser
->root
.child
) {
232 /* Return this so that the generic dialog code will run and initialise
233 * the widgets and stuff. */
234 return EVENT_NOT_PROCESSED
;
237 static widget_handler_status_T
238 hierbox_ev_abort(struct dialog_data
*dlg_data
)
240 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
241 struct hierbox_browser
*browser
= dlg_data
->dlg
->udata2
;
242 struct hierbox_dialog_list_item
*item
;
244 /* Save state and delete the box structure */
245 if (!browser
->do_not_save_state
)
246 copy_struct(&browser
->box_data
, box
);
249 /* Delete the dialog list entry */
250 foreach (item
, browser
->dialogs
) {
251 if (item
->dlg_data
== dlg_data
) {
258 /* Return this so that the generic dialog code will run and initialise
259 * the widgets and stuff. */
260 return EVENT_NOT_PROCESSED
;
264 /* We install own dialog event handler, so that we can give the listbox widget
265 * an early chance to catch the event. Basically, the listbox widget is itself
266 * unselectable, instead one of the buttons below is always active. So, we
267 * always first let the listbox catch the keypress and handle it, and if it
268 * doesn't care, we pass it on to the button. */
269 static widget_handler_status_T
270 hierbox_dialog_event_handler(struct dialog_data
*dlg_data
)
272 struct term_event
*ev
= dlg_data
->term_event
;
276 return hierbox_ev_kbd(dlg_data
);
279 return hierbox_ev_init(dlg_data
);
284 return EVENT_NOT_PROCESSED
;
287 return hierbox_ev_abort(dlg_data
);
290 return EVENT_NOT_PROCESSED
;
295 hierbox_browser(struct hierbox_browser
*browser
, struct session
*ses
)
297 struct terminal
*term
= ses
->tab
->term
;
298 struct listbox_data
*listbox_data
;
300 int button
= browser
->buttons_size
+ 2;
301 int anonymous
= get_cmd_opt_bool("anonymous");
305 dlg
= calloc_dialog(button
, sizeof(*listbox_data
));
306 if (!dlg
) return NULL
;
308 listbox_data
= (struct listbox_data
*) get_dialog_offset(dlg
, button
);
310 dlg
->title
= _(browser
->title
, term
);
311 dlg
->layouter
= generic_dialog_layouter
;
312 dlg
->layout
.maximize_width
= 1;
313 dlg
->layout
.padding_top
= 1;
314 dlg
->handle_event
= hierbox_dialog_event_handler
;
316 dlg
->udata2
= browser
;
318 add_dlg_listbox(dlg
, listbox_data
);
320 for (button
= 0; button
< browser
->buttons_size
; button
++) {
321 const struct hierbox_browser_button
*but
= &browser
->buttons
[button
];
323 /* Skip buttons that should not be displayed in anonymous mode */
324 if (anonymous
&& !but
->anonymous
) {
329 add_dlg_button(dlg
, _(but
->label
, term
), B_ENTER
, but
->handler
, NULL
);
332 add_dlg_button(dlg
, _("Close", term
), B_ESC
, cancel_dialog
, NULL
);
334 /* @anonymous was initially 1 if we are running in anonymous mode so we
335 * have to subtract one. */
336 add_dlg_end(dlg
, button
+ 2 - (anonymous
? anonymous
- 1 : 0));
338 return do_dialog(term
, dlg
, getml(dlg
, (void *) NULL
));
342 /* Action info management */
345 scan_for_marks(struct listbox_item
*item
, void *info_
, int *offset
)
348 struct listbox_context
*context
= info_
;
350 context
->item
= NULL
;
358 scan_for_used(struct listbox_item
*item
, void *info_
, int *offset
)
360 struct listbox_context
*context
= info_
;
362 if (context
->box
->ops
->is_used(item
)) {
363 context
->item
= item
;
371 static struct listbox_context
*
372 init_listbox_context(struct listbox_data
*box
, struct terminal
*term
,
373 struct listbox_item
*item
,
374 int (*scanner
)(struct listbox_item
*, void *, int *))
376 struct listbox_context
*context
;
378 context
= mem_calloc(1, sizeof(*context
));
379 if (!context
) return NULL
;
381 context
->item
= item
;
382 context
->term
= term
;
385 if (!scanner
) return context
;
387 /* Look if it wouldn't be more interesting to blast off the marked
389 assert(!list_empty(*box
->items
));
390 traverse_listbox_items_list(box
->items
->next
, box
, 0, 0,
397 done_listbox_context(void *context_
)
399 struct listbox_context
*context
= context_
;
402 context
->box
->ops
->unlock(context
->item
);
408 widget_handler_status_T
409 push_hierbox_info_button(struct dialog_data
*dlg_data
, struct widget_data
*button
)
411 /* [gettext_accelerator_context(push_hierbox_info_button)] */
412 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
413 struct listbox_item
*item
= box
->sel
;
414 struct terminal
*term
= dlg_data
->win
->term
;
415 struct listbox_context
*context
;
418 if (!item
) return EVENT_PROCESSED
;
422 context
= init_listbox_context(box
, term
, item
, NULL
);
423 if (!context
) return EVENT_PROCESSED
;
425 msg
= box
->ops
->get_info(item
, term
);
428 if (item
->type
== BI_FOLDER
) {
429 info_box(term
, 0, N_("Info"), ALIGN_CENTER
,
430 N_("Press space to expand this folder."));
432 return EVENT_PROCESSED
;
435 box
->ops
->lock(item
);
437 msg_box(term
, getml(context
, (void *) NULL
), MSGBOX_FREE_TEXT
/* | MSGBOX_SCROLLABLE */,
438 N_("Info"), ALIGN_LEFT
,
441 MSG_BOX_BUTTON(N_("~OK"), done_listbox_context
, B_ESC
| B_ENTER
));
443 return EVENT_PROCESSED
;
449 static void recursively_goto_each_listbox(struct session
*ses
,
450 struct listbox_item
*root
,
451 struct listbox_data
*box
);
454 recursively_goto_listbox(struct session
*ses
, struct listbox_item
*item
,
455 struct listbox_data
*box
)
457 if (item
->type
== BI_FOLDER
) {
458 recursively_goto_each_listbox(ses
, item
, box
);
461 } else if (item
->type
== BI_LEAF
) {
462 struct uri
*uri
= box
->ops
->get_uri(item
);
466 open_uri_in_new_tab(ses
, uri
, 1, 0);
472 recursively_goto_each_listbox(struct session
*ses
, struct listbox_item
*root
,
473 struct listbox_data
*box
)
475 struct listbox_item
*item
;
477 foreach (item
, root
->child
) {
478 recursively_goto_listbox(ses
, item
, box
);
483 goto_marked(struct listbox_item
*item
, void *data_
, int *offset
)
485 struct listbox_context
*context
= data_
;
488 struct session
*ses
= context
->dlg_data
->dlg
->udata
;
489 struct listbox_data
*box
= context
->box
;
491 recursively_goto_listbox(ses
, item
, box
);
497 widget_handler_status_T
498 push_hierbox_goto_button(struct dialog_data
*dlg_data
,
499 struct widget_data
*button
)
501 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
502 struct listbox_item
*item
= box
->sel
;
503 struct session
*ses
= dlg_data
->dlg
->udata
;
504 struct terminal
*term
= dlg_data
->win
->term
;
505 struct listbox_context
*context
;
507 if (!item
) return EVENT_PROCESSED
;
509 context
= init_listbox_context(box
, term
, item
, scan_for_marks
);
510 if (!context
) return EVENT_PROCESSED
;
512 if (!context
->item
) {
513 context
->dlg_data
= dlg_data
;
514 traverse_listbox_items_list(context
->box
->items
->next
,
516 goto_marked
, context
);
518 } else if (item
->type
== BI_FOLDER
) {
519 recursively_goto_each_listbox(ses
, item
, box
);
521 } else if (item
->type
== BI_LEAF
) {
522 struct uri
*uri
= box
->ops
->get_uri(item
);
531 return EVENT_PROCESSED
;
536 /* Close the dialog */
537 delete_window(dlg_data
->win
);
538 return EVENT_PROCESSED
;
545 DELETE_IMPOSSIBLE
= 0,
550 static const struct listbox_ops_messages default_listbox_ops_messages
= {
551 /* cant_delete_item */
552 N_("Sorry, but the item \"%s\" cannot be deleted."),
554 /* cant_delete_used_item */
555 N_("Sorry, but the item \"%s\" is being used by something else."),
557 /* cant_delete_folder */
558 N_("Sorry, but the folder \"%s\" cannot be deleted."),
560 /* cant_delete_used_folder */
561 N_("Sorry, but the folder \"%s\" is being used by something else."),
563 /* delete_marked_items_title */
564 N_("Delete marked items"),
566 /* delete_marked_items */
567 N_("Delete marked items?"),
569 /* delete_folder_title */
573 N_("Delete the folder \"%s\" and its content?"),
575 /* delete_item_title */
579 N_("Delete \"%s\"?\n\n%s"),
581 /* clear_all_items_title */
582 N_("Clear all items"),
584 /* clear_all_items */
585 N_("Do you really want to remove all items?"),
588 #define listbox_message(msg) \
589 ops->messages && ops->messages->msg \
590 ? ops->messages->msg \
591 : default_listbox_ops_messages.msg
594 print_delete_error(struct listbox_item
*item
, struct terminal
*term
,
595 const struct listbox_ops
*ops
, enum delete_error err
)
598 unsigned char *errmsg
;
602 case DELETE_IMPOSSIBLE
:
603 if (item
->type
== BI_FOLDER
) {
604 errmsg
= listbox_message(cant_delete_folder
);
606 errmsg
= listbox_message(cant_delete_item
);
611 if (item
->type
== BI_FOLDER
) {
612 errmsg
= listbox_message(cant_delete_used_folder
);
614 errmsg
= listbox_message(cant_delete_used_item
);
619 INTERNAL("Bad delete error code (%d)!", err
);
623 text
= ops
->get_text(item
, term
);
625 if (!text
|| !init_string(&msg
)) {
630 add_format_to_string(&msg
, _(errmsg
, term
), text
);
633 if (item
->type
== BI_LEAF
) {
634 unsigned char *info
= ops
->get_info(item
, term
);
637 add_format_to_string(&msg
, "\n\n%s", info
);
642 info_box(term
, MSGBOX_FREE_TEXT
, N_("Delete error"), ALIGN_LEFT
,
647 do_delete_item(struct listbox_item
*item
, struct listbox_context
*info
,
650 const struct listbox_ops
*ops
= info
->box
->ops
;
654 if (!ops
->can_delete(item
)) {
655 print_delete_error(item
, info
->term
, ops
, DELETE_IMPOSSIBLE
);
659 if (ops
->is_used(item
)) {
660 print_delete_error(item
, info
->term
, ops
, DELETE_LOCKED
);
664 ops
->delete(item
, last
);
668 delete_marked(struct listbox_item
*item
, void *data_
, int *offset
)
670 struct listbox_context
*context
= data_
;
672 if (item
->marked
&& !context
->box
->ops
->is_used(item
)) {
673 /* Save the first marked so it can be deleted last */
674 if (!context
->item
) {
675 context
->item
= item
;
677 do_delete_item(item
, context
, 0);
687 push_ok_delete_button(void *context_
)
689 struct listbox_context
*context
= context_
;
690 struct listbox_item
*root
;
694 context
->box
->ops
->unlock(context
->item
);
696 traverse_listbox_items_list(context
->box
->items
->next
,
698 delete_marked
, context
);
699 if (!context
->item
) return;
702 root
= context
->box
->ops
->get_root(context
->item
);
704 last
= context
->item
== root
->child
.prev
;
707 /* Delete the last one (traversal should save one to delete) */
708 do_delete_item(context
->item
, context
, 1);
710 /* If removing the last item in a folder move focus to previous item in
711 * the folder or the root. */
713 listbox_sel_move(context
->widget_data
, -1);
716 static widget_handler_status_T
717 query_delete_selected_item(void *context_
)
719 /* [gettext_accelerator_context(query_delete_selected_item)] */
720 struct listbox_context
*context
, *oldcontext
= context_
;
721 struct terminal
*term
= oldcontext
->term
;
722 struct listbox_data
*box
= oldcontext
->box
;
723 const struct listbox_ops
*ops
= box
->ops
;
724 struct listbox_item
*item
= box
->sel
;
726 enum delete_error
delete;
730 delete = ops
->can_delete(item
) ? DELETE_LOCKED
: DELETE_IMPOSSIBLE
;
732 if (delete == DELETE_IMPOSSIBLE
|| ops
->is_used(item
)) {
733 print_delete_error(item
, term
, ops
, delete);
734 return EVENT_PROCESSED
;
737 context
= init_listbox_context(box
, term
, item
, NULL
);
738 if (!context
) return EVENT_PROCESSED
;
740 context
->widget_data
= oldcontext
->widget_data
;
742 text
= ops
->get_text(item
, term
);
745 return EVENT_PROCESSED
;
748 if (item
->type
== BI_FOLDER
) {
750 msg_box(term
, getml(context
, (void *) NULL
), MSGBOX_FREE_TEXT
,
751 listbox_message(delete_folder_title
), ALIGN_CENTER
,
752 msg_text(term
, listbox_message(delete_folder
), text
),
754 MSG_BOX_BUTTON(N_("~Yes"), push_ok_delete_button
, B_ENTER
),
755 MSG_BOX_BUTTON(N_("~No"), done_listbox_context
, B_ESC
));
757 unsigned char *msg
= ops
->get_info(item
, term
);
761 msg_box(term
, getml(context
, (void *) NULL
), MSGBOX_FREE_TEXT
,
762 listbox_message(delete_item_title
), ALIGN_LEFT
,
763 msg_text(term
, listbox_message(delete_item
),
764 text
, empty_string_or_(msg
)),
766 MSG_BOX_BUTTON(N_("~Yes"), push_ok_delete_button
, B_ENTER
),
767 MSG_BOX_BUTTON(N_("~No"), done_listbox_context
, B_ESC
));
772 return EVENT_PROCESSED
;
776 dont_delete_marked_items(void *const context_
)
778 query_delete_selected_item(context_
);
781 widget_handler_status_T
782 push_hierbox_delete_button(struct dialog_data
*dlg_data
,
783 struct widget_data
*button
)
785 /* [gettext_accelerator_context(push_hierbox_delete_button)] */
786 struct terminal
*term
= dlg_data
->win
->term
;
787 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
788 const struct listbox_ops
*ops
= box
->ops
;
789 struct listbox_item
*item
= box
->sel
;
790 struct listbox_context
*context
;
792 if (!item
) return EVENT_PROCESSED
;
794 assert(ops
&& ops
->can_delete
&& ops
->delete);
796 context
= init_listbox_context(box
, term
, item
, scan_for_marks
);
797 if (!context
) return EVENT_PROCESSED
;
799 context
->widget_data
= dlg_data
->widgets_data
;
802 widget_handler_status_T status
;
804 status
= query_delete_selected_item(context
);
810 msg_box(term
, getml(context
, (void *) NULL
), 0,
811 listbox_message(delete_marked_items_title
), ALIGN_CENTER
,
812 listbox_message(delete_marked_items
),
814 MSG_BOX_BUTTON(N_("~Yes"), push_ok_delete_button
, B_ENTER
),
815 MSG_BOX_BUTTON(N_("~No"), dont_delete_marked_items
, B_ESC
));
817 return EVENT_PROCESSED
;
825 delete_unused(struct listbox_item
*item
, void *data_
, int *offset
)
827 struct listbox_context
*context
= data_
;
829 if (context
->box
->ops
->is_used(item
)) return 0;
831 do_delete_item(item
, context
, 0);
836 do_clear_browser(void *context_
)
838 struct listbox_context
*context
= context_
;
840 traverse_listbox_items_list(context
->box
->items
->next
,
842 delete_unused
, context
);
845 widget_handler_status_T
846 push_hierbox_clear_button(struct dialog_data
*dlg_data
,
847 struct widget_data
*button
)
849 /* [gettext_accelerator_context(push_hierbox_clear_button)] */
850 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
851 const struct listbox_ops
*ops
= box
->ops
;
852 struct terminal
*term
= dlg_data
->win
->term
;
853 struct listbox_context
*context
;
855 if (!box
->sel
) return EVENT_PROCESSED
;
859 context
= init_listbox_context(box
, term
, NULL
, scan_for_used
);
860 if (!context
) return EVENT_PROCESSED
;
863 /* FIXME: If the clear button should be used for browsers where
864 * not all items can be deleted scan_for_used() should also can
865 * for undeletable and we should be able to pass either delete
867 print_delete_error(context
->item
, term
, ops
, DELETE_LOCKED
);
869 return EVENT_PROCESSED
;
872 msg_box(term
, getml(context
, (void *) NULL
), 0,
873 listbox_message(clear_all_items_title
), ALIGN_CENTER
,
874 listbox_message(clear_all_items
),
876 MSG_BOX_BUTTON(N_("~Yes"), do_clear_browser
, B_ENTER
),
877 MSG_BOX_BUTTON(N_("~No"), NULL
, B_ESC
));
879 return EVENT_PROCESSED
;
882 #undef listbox_message
888 scan_for_matches(struct listbox_item
*item
, void *info_
, int *offset
)
890 struct listbox_context
*context
= info_
;
891 unsigned char *text
= (unsigned char *) context
->widget_data
;
898 switch (context
->box
->ops
->match(item
, context
->term
, text
)) {
899 case LISTBOX_MATCH_OK
:
900 /* Mark that we have a match by setting the item to non-NULL */
901 context
->item
= item
;
905 case LISTBOX_MATCH_NO
:
909 case LISTBOX_MATCH_IMPOSSIBLE
:
917 mark_visible(struct listbox_item
*item
, void *xxx
, int *offset
)
925 search_hierbox_browser(void *data
, unsigned char *text
)
927 struct dialog_data
*dlg_data
= data
;
928 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
929 struct terminal
*term
= dlg_data
->win
->term
;
930 struct listbox_context
*context
;
932 context
= init_listbox_context(box
, term
, NULL
, NULL
);
933 if (!context
) return;
936 context
->widget_data
= (void *) text
;
938 traverse_listbox_items_list(box
->items
->next
, box
, 0, 0,
939 scan_for_matches
, context
);
941 if (!context
->item
&& *text
) {
942 switch (get_opt_int("document.browse.search.show_not_found",
945 info_box(term
, MSGBOX_FREE_TEXT
,
946 N_("Search"), ALIGN_CENTER
,
948 N_("Search string '%s' not found"),
959 traverse_listbox_items_list(box
->items
->next
, box
, 0, 0,
966 widget_handler_status_T
967 push_hierbox_search_button(struct dialog_data
*dlg_data
,
968 struct widget_data
*button
)
970 struct terminal
*term
= dlg_data
->win
->term
;
971 struct listbox_data
*box
= get_dlg_listbox_data(dlg_data
);
973 if (!box
->sel
) return EVENT_PROCESSED
;
975 assert(box
->ops
->match
);
977 input_dialog(term
, NULL
, N_("Search"), N_("Name"),
979 MAX_STR_LEN
, "", 0, 0, NULL
,
980 search_hierbox_browser
, NULL
);
982 return EVENT_PROCESSED
;