* clear out some warnings by gcc 9.3.1.
[alpine.git] / alpine / listsel.c
blobf4de9f60e77eb07ca2adc04a18ae955291b145b3
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: listsel.c 918 2008-01-23 19:39:38Z hubert@u.washington.edu $";
3 #endif
4 /* ========================================================================
5 * Copyright 2013-2020 Eduardo Chappa
6 * Copyright 2006-2008 University of Washington
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * ========================================================================
18 #include "headers.h"
19 #include "listsel.h"
20 #include "status.h"
21 #include "confscroll.h"
22 #include "../pith/state.h"
26 * Internal prototypes
28 int select_from_list_tool(struct pine *, int, CONF_S **, unsigned);
29 int select_from_list_tool_allow_noselections(struct pine *, int, CONF_S **, unsigned);
33 * This is intended to be a generic tool to select strings from a list
34 * of strings.
36 * Args lsel -- the items as well as the answer are contained in this list
37 * flags -- There is some inconsistent flags usage. Notice that the
38 * flag SFL_ALLOW_LISTMODE is a flag passed in the flags
39 * argument whereas the flag SFL_NOSELECT is a per item
40 * (that is, per LIST_SEL_S) flag.
41 * title -- passed to conf_scroll_screen
42 * pdesc -- passed to conf_scroll_screen
43 * help -- passed to conf_scroll_screen
44 * helptitle -- passed to conf_scroll_screen
46 * You have screen width - 4 columns to work with. If you want to overflow to
47 * a second (or third or fourth) line for an item just send another item
48 * in the list but with the SFL_NOSELECT flag set. Only the selectable lines
49 * will be highlighted, which is kind of a crock, but it looked like a lot
50 * of work to fix that.
52 * Returns 0 on successful choice
53 * -1 if cancelled
55 int
56 select_from_list_screen(LIST_SEL_S *lsel, long unsigned int flags, char *title,
57 char *pdesc, HelpType help, char *htitle,
58 LIST_SEL_S *starting_val)
60 CONF_S *ctmp = NULL, *first_line = NULL;
61 OPT_SCREEN_S screen;
62 int j, lv, ret = -1;
63 LIST_SEL_S *p;
64 char *display;
65 size_t l;
66 ScreenMode listmode = SingleMode;
67 int (*tool)(struct pine *, int, CONF_S **, unsigned);
69 if(!lsel)
70 return(ret);
72 /* find longest value's length */
73 for(lv = 0, p = lsel; p; p = p->next){
74 if(!(p->flags & SFL_NOSELECT)){
75 display = p->display_item ? p->display_item :
76 p->item ? p->item : "";
77 if(lv < (j = utf8_width(display)))
78 lv = j;
82 lv = MIN(lv, ps_global->ttyo->screen_cols - 4);
84 tool = (flags & SFL_CTRLC) ? select_from_list_tool_allow_noselections
85 : select_from_list_tool;
88 * Convert the passed in list to conf_scroll lines.
91 if(flags & SFL_ALLOW_LISTMODE){
93 if(flags & SFL_ONLY_LISTMODE) {assert(flags & SFL_STARTIN_LISTMODE);}
95 for(p = lsel; p; p = p->next){
97 display = p->display_item ? p->display_item :
98 p->item ? p->item : "";
99 new_confline(&ctmp);
100 if(!first_line && !(p->flags & SFL_NOSELECT))
101 first_line = ctmp;
102 if(!first_line && !(p->flags & SFL_NOSELECT))
103 if(!starting_val || (starting_val == p))
104 first_line = ctmp;
106 /* generous allocation */
107 l = lv + 4 + strlen(display);
108 ctmp->value = (char *) fs_get((l + 1) * sizeof(char));
109 utf8_snprintf(ctmp->value, l+1, " %-*.*w", lv, lv, display);
110 ctmp->value[l] = '\0';
112 ctmp->d.l.lsel = p;
113 ctmp->d.l.listmode = &listmode;
114 if(flags & SFL_ONLY_LISTMODE){
115 if(flags & SFL_CTRLC)
116 ctmp->keymenu = &sel_from_list_olm_ctrlc;
117 else
118 ctmp->keymenu = &sel_from_list_olm;
120 else{
121 if(flags & SFL_CTRLC)
122 ctmp->keymenu = &sel_from_list_sm_ctrlc;
123 else
124 ctmp->keymenu = &sel_from_list_sm;
127 ctmp->help = help;
128 ctmp->help_title = htitle;
129 ctmp->tool = tool;
130 ctmp->flags = CF_STARTITEM |
131 ((p->flags & SFL_NOSELECT) ? CF_NOSELECT : 0);
134 else{
136 assert(!(flags & SFL_ONLY_LISTMODE));
137 assert(!(flags & SFL_STARTIN_LISTMODE));
139 for(p = lsel; p; p = p->next){
141 display = p->display_item ? p->display_item :
142 p->item ? p->item : "";
143 new_confline(&ctmp);
144 if(!first_line && !(p->flags & SFL_NOSELECT))
145 if(!starting_val || (starting_val == p))
146 first_line = ctmp;
148 l = lv + strlen(display);
149 ctmp->value = (char *) fs_get((l + 1) * sizeof(char));
150 utf8_snprintf(ctmp->value, l+1, "%-*.*w", lv, lv, display);
151 ctmp->value[l] = '\0';
153 ctmp->d.l.lsel = p;
154 ctmp->d.l.listmode = &listmode;
155 if(flags & SFL_CTRLC)
156 ctmp->keymenu = &sel_from_list_ctrlc;
157 else
158 ctmp->keymenu = &sel_from_list;
160 ctmp->help = help;
161 ctmp->help_title = htitle;
162 ctmp->tool = tool;
163 ctmp->flags = CF_STARTITEM |
164 ((p->flags & SFL_NOSELECT) ? CF_NOSELECT : 0);
165 ctmp->valoffset = 4;
169 /* just convert to start in listmode after the fact, easier that way */
170 if(flags & SFL_STARTIN_LISTMODE){
171 listmode = ListMode;
173 for(ctmp = first_line; ctmp; ctmp = next_confline(ctmp))
174 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
175 ctmp->value[0] = '[';
176 ctmp->value[1] = ctmp->d.l.lsel->selected ? 'X' : SPACE;
177 ctmp->value[2] = ']';
178 if(flags & SFL_ONLY_LISTMODE){
179 if(flags & SFL_CTRLC)
180 ctmp->keymenu = &sel_from_list_olm_ctrlc;
181 else
182 ctmp->keymenu = &sel_from_list_olm;
184 else{
185 if(flags & SFL_CTRLC)
186 ctmp->keymenu = &sel_from_list_lm_ctrlc;
187 else
188 ctmp->keymenu = &sel_from_list_lm;
193 memset(&screen, 0, sizeof(screen));
194 switch(conf_scroll_screen(ps_global, &screen, first_line, title, pdesc, 0, NULL)){
195 case 1:
196 ret = 0;
197 break;
199 default:
200 break;
203 ps_global->mangled_screen = 1;
204 return(ret);
209 select_from_list_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
211 CONF_S *ctmp;
212 int retval = 0;
214 switch(cmd){
215 case MC_SELECT :
216 if(*(*cl)->d.l.listmode == SingleMode){
217 (*cl)->d.l.lsel->selected = 1;
218 retval = 3;
220 else{
221 /* check if anything is selected */
222 /* go to first line */
223 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
226 for(; ctmp; ctmp = next_confline(ctmp))
227 if(!(ctmp->flags & CF_NOSELECT) && ctmp->d.l.lsel->selected){
228 retval = 3;
229 break;
232 if(retval == 0){
233 q_status_message(SM_ORDER, 0, 3,
234 _("Nothing selected, use Exit to exit without a selection."));
238 break;
240 case MC_LISTMODE :
241 if(*(*cl)->d.l.listmode == SingleMode){
243 * UnHide the checkboxes
246 *(*cl)->d.l.listmode = ListMode;
248 /* go to first line */
249 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
252 for(; ctmp; ctmp = next_confline(ctmp))
253 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
254 ctmp->value[0] = '[';
255 ctmp->value[1] = ctmp->d.l.lsel->selected ? 'X' : SPACE;
256 ctmp->value[2] = ']';
257 ctmp->keymenu = &sel_from_list_lm;
260 else{
262 * Hide the checkboxes
265 *(*cl)->d.l.listmode = SingleMode;
267 /* go to first line */
268 for(ctmp = *cl; prev_confline(ctmp); ctmp = prev_confline(ctmp))
271 for(; ctmp; ctmp = next_confline(ctmp))
272 if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){
273 ctmp->value[0] = ctmp->value[1] = ctmp->value[2] = SPACE;
274 ctmp->keymenu = &sel_from_list_sm;
278 ps->mangled_body = ps->mangled_footer = 1;
279 break;
281 case MC_TOGGLE :
282 if((*cl)->value[1] == 'X'){
283 (*cl)->d.l.lsel->selected = 0;
284 (*cl)->value[1] = SPACE;
286 else{
287 (*cl)->d.l.lsel->selected = 1;
288 (*cl)->value[1] = 'X';
291 ps->mangled_body = 1;
292 break;
294 case MC_EXIT :
295 retval = simple_exit_cmd(flags);
296 break;
298 default:
299 retval = -1;
300 break;
303 if(retval > 0)
304 ps->mangled_body = 1;
306 return(retval);
311 select_from_list_tool_allow_noselections(struct pine *ps, int cmd, CONF_S **cl, unsigned int flags)
313 int retval = 0;
315 switch(cmd){
316 case MC_SELECT :
317 retval = 3;
318 if(*(*cl)->d.l.listmode == SingleMode)
319 (*cl)->d.l.lsel->selected = 1;
321 break;
323 default:
324 retval = select_from_list_tool(ps, cmd, cl, flags);
325 break;
328 if(retval > 0)
329 ps->mangled_body = 1;
331 return(retval);