* New version 2.26
[alpine.git] / alpine / listsel.c
blobd6076f15977b8e0c64d28860f8101af932875aca
1 /* ========================================================================
2 * Copyright 2013-2022 Eduardo Chappa
3 * Copyright 2006-2008 University of Washington
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * ========================================================================
15 #include "headers.h"
16 #include "listsel.h"
17 #include "status.h"
18 #include "confscroll.h"
19 #include "../pith/state.h"
23 * Internal prototypes
25 int select_from_list_tool(struct pine *, int, CONF_S **, unsigned);
26 int select_from_list_tool_allow_noselections(struct pine *, int, CONF_S **, unsigned);
30 * This is intended to be a generic tool to select strings from a list
31 * of strings.
33 * Args lsel -- the items as well as the answer are contained in this list
34 * flags -- There is some inconsistent flags usage. Notice that the
35 * flag SFL_ALLOW_LISTMODE is a flag passed in the flags
36 * argument whereas the flag SFL_NOSELECT is a per item
37 * (that is, per LIST_SEL_S) flag.
38 * title -- passed to conf_scroll_screen
39 * pdesc -- passed to conf_scroll_screen
40 * help -- passed to conf_scroll_screen
41 * helptitle -- passed to conf_scroll_screen
43 * You have screen width - 4 columns to work with. If you want to overflow to
44 * a second (or third or fourth) line for an item just send another item
45 * in the list but with the SFL_NOSELECT flag set. Only the selectable lines
46 * will be highlighted, which is kind of a crock, but it looked like a lot
47 * of work to fix that.
49 * Returns 0 on successful choice
50 * -1 if cancelled
52 int
53 select_from_list_screen(LIST_SEL_S *lsel, long unsigned int flags, char *title,
54 char *pdesc, HelpType help, char *htitle,
55 LIST_SEL_S *starting_val)
57 CONF_S *ctmp = NULL, *first_line = NULL;
58 OPT_SCREEN_S screen;
59 int j, lv, ret = -1;
60 LIST_SEL_S *p;
61 char *display;
62 size_t l;
63 ScreenMode listmode = SingleMode;
64 int (*tool)(struct pine *, int, CONF_S **, unsigned);
66 if(!lsel)
67 return(ret);
69 /* find longest value's length */
70 for(lv = 0, p = lsel; p; p = p->next){
71 if(!(p->flags & SFL_NOSELECT)){
72 display = p->display_item ? p->display_item :
73 p->item ? p->item : "";
74 if(lv < (j = utf8_width(display)))
75 lv = j;
79 lv = MIN(lv, ps_global->ttyo->screen_cols - 4);
81 tool = (flags & SFL_CTRLC) ? select_from_list_tool_allow_noselections
82 : select_from_list_tool;
85 * Convert the passed in list to conf_scroll lines.
88 if(flags & SFL_ALLOW_LISTMODE){
90 if(flags & SFL_ONLY_LISTMODE) {assert(flags & SFL_STARTIN_LISTMODE);}
92 for(p = lsel; p; p = p->next){
94 display = p->display_item ? p->display_item :
95 p->item ? p->item : "";
96 new_confline(&ctmp);
97 if(!first_line && !(p->flags & SFL_NOSELECT))
98 first_line = ctmp;
99 if(!first_line && !(p->flags & SFL_NOSELECT))
100 if(!starting_val || (starting_val == p))
101 first_line = ctmp;
103 /* generous allocation */
104 l = lv + 4 + strlen(display);
105 ctmp->value = (char *) fs_get((l + 1) * sizeof(char));
106 utf8_snprintf(ctmp->value, l+1, " %-*.*w", lv, lv, display);
107 ctmp->value[l] = '\0';
109 ctmp->d.l.lsel = p;
110 ctmp->d.l.listmode = &listmode;
111 if(flags & SFL_ONLY_LISTMODE){
112 if(flags & SFL_CTRLC)
113 ctmp->keymenu = &sel_from_list_olm_ctrlc;
114 else
115 ctmp->keymenu = &sel_from_list_olm;
117 else{
118 if(flags & SFL_CTRLC)
119 ctmp->keymenu = &sel_from_list_sm_ctrlc;
120 else
121 ctmp->keymenu = &sel_from_list_sm;
124 ctmp->help = help;
125 ctmp->help_title = htitle;
126 ctmp->tool = tool;
127 ctmp->flags = CF_STARTITEM |
128 ((p->flags & SFL_NOSELECT) ? CF_NOSELECT : 0);
131 else{
133 assert(!(flags & SFL_ONLY_LISTMODE));
134 assert(!(flags & SFL_STARTIN_LISTMODE));
136 for(p = lsel; p; p = p->next){
138 display = p->display_item ? p->display_item :
139 p->item ? p->item : "";
140 new_confline(&ctmp);
141 if(!first_line && !(p->flags & SFL_NOSELECT))
142 if(!starting_val || (starting_val == p))
143 first_line = ctmp;
145 l = lv + strlen(display);
146 ctmp->value = (char *) fs_get((l + 1) * sizeof(char));
147 utf8_snprintf(ctmp->value, l+1, "%-*.*w", lv, lv, display);
148 ctmp->value[l] = '\0';
150 ctmp->d.l.lsel = p;
151 ctmp->d.l.listmode = &listmode;
152 if(flags & SFL_CTRLC)
153 ctmp->keymenu = &sel_from_list_ctrlc;
154 else
155 ctmp->keymenu = &sel_from_list;
157 ctmp->help = help;
158 ctmp->help_title = htitle;
159 ctmp->tool = tool;
160 ctmp->flags = CF_STARTITEM |
161 ((p->flags & SFL_NOSELECT) ? CF_NOSELECT : 0);
162 ctmp->valoffset = 4;
166 /* just convert to start in listmode after the fact, easier that way */
167 if(flags & SFL_STARTIN_LISTMODE){
168 listmode = ListMode;
170 for(ctmp = first_line; ctmp; ctmp = next_confline(ctmp))
171 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
172 ctmp->value[0] = '[';
173 ctmp->value[1] = ctmp->d.l.lsel->selected ? 'X' : SPACE;
174 ctmp->value[2] = ']';
175 if(flags & SFL_ONLY_LISTMODE){
176 if(flags & SFL_CTRLC)
177 ctmp->keymenu = &sel_from_list_olm_ctrlc;
178 else
179 ctmp->keymenu = &sel_from_list_olm;
181 else{
182 if(flags & SFL_CTRLC)
183 ctmp->keymenu = &sel_from_list_lm_ctrlc;
184 else
185 ctmp->keymenu = &sel_from_list_lm;
190 memset(&screen, 0, sizeof(screen));
191 switch(conf_scroll_screen(ps_global, &screen, first_line, title, pdesc, 0, NULL)){
192 case 1:
193 ret = 0;
194 break;
196 default:
197 break;
200 ps_global->mangled_screen = 1;
201 return(ret);
206 select_from_list_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
208 CONF_S *ctmp;
209 int retval = 0;
211 switch(cmd){
212 case MC_SELECT :
213 if(*(*cl)->d.l.listmode == SingleMode){
214 (*cl)->d.l.lsel->selected = 1;
215 retval = 3;
217 else{
218 /* check if anything is selected */
219 /* go to first line */
220 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
223 for(; ctmp; ctmp = next_confline(ctmp))
224 if(!(ctmp->flags & CF_NOSELECT) && ctmp->d.l.lsel->selected){
225 retval = 3;
226 break;
229 if(retval == 0){
230 q_status_message(SM_ORDER, 0, 3,
231 _("Nothing selected, use Exit to exit without a selection."));
235 break;
237 case MC_LISTMODE :
238 if(*(*cl)->d.l.listmode == SingleMode){
240 * UnHide the checkboxes
243 *(*cl)->d.l.listmode = ListMode;
245 /* go to first line */
246 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
249 for(; ctmp; ctmp = next_confline(ctmp))
250 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
251 ctmp->value[0] = '[';
252 ctmp->value[1] = ctmp->d.l.lsel->selected ? 'X' : SPACE;
253 ctmp->value[2] = ']';
254 ctmp->keymenu = &sel_from_list_lm;
257 else{
259 * Hide the checkboxes
262 *(*cl)->d.l.listmode = SingleMode;
264 /* go to first line */
265 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
268 for(; ctmp; ctmp = next_confline(ctmp))
269 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
270 ctmp->value[0] = ctmp->value[1] = ctmp->value[2] = SPACE;
271 ctmp->keymenu = &sel_from_list_sm;
275 ps->mangled_body = ps->mangled_footer = 1;
276 break;
278 case MC_TOGGLE :
279 if((*cl)->value[1] == 'X'){
280 (*cl)->d.l.lsel->selected = 0;
281 (*cl)->value[1] = SPACE;
283 else{
284 (*cl)->d.l.lsel->selected = 1;
285 (*cl)->value[1] = 'X';
288 ps->mangled_body = 1;
289 break;
291 case MC_EXIT :
292 retval = simple_exit_cmd(flags);
293 break;
295 default:
296 retval = -1;
297 break;
300 if(retval > 0)
301 ps->mangled_body = 1;
303 return(retval);
308 select_from_list_tool_allow_noselections(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
310 int retval = 0;
312 switch(cmd){
313 case MC_SELECT :
314 retval = 3;
315 if(*(*cl)->d.l.listmode == SingleMode)
316 (*cl)->d.l.lsel->selected = 1;
318 break;
320 default:
321 retval = select_from_list_tool(ps, cmd, cl, flags);
322 break;
325 if(retval > 0)
326 ps->mangled_body = 1;
328 return(retval);