1 /* ========================================================================
2 * Copyright 2013-2021 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 * ========================================================================
18 #include "confscroll.h"
19 #include "../pith/state.h"
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
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
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
;
63 ScreenMode listmode
= SingleMode
;
64 int (*tool
)(struct pine
*, int, CONF_S
**, unsigned);
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
)))
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
: "";
97 if(!first_line
&& !(p
->flags
& SFL_NOSELECT
))
99 if(!first_line
&& !(p
->flags
& SFL_NOSELECT
))
100 if(!starting_val
|| (starting_val
== p
))
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';
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
;
115 ctmp
->keymenu
= &sel_from_list_olm
;
118 if(flags
& SFL_CTRLC
)
119 ctmp
->keymenu
= &sel_from_list_sm_ctrlc
;
121 ctmp
->keymenu
= &sel_from_list_sm
;
125 ctmp
->help_title
= htitle
;
127 ctmp
->flags
= CF_STARTITEM
|
128 ((p
->flags
& SFL_NOSELECT
) ? CF_NOSELECT
: 0);
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
: "";
141 if(!first_line
&& !(p
->flags
& SFL_NOSELECT
))
142 if(!starting_val
|| (starting_val
== p
))
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';
151 ctmp
->d
.l
.listmode
= &listmode
;
152 if(flags
& SFL_CTRLC
)
153 ctmp
->keymenu
= &sel_from_list_ctrlc
;
155 ctmp
->keymenu
= &sel_from_list
;
158 ctmp
->help_title
= htitle
;
160 ctmp
->flags
= CF_STARTITEM
|
161 ((p
->flags
& SFL_NOSELECT
) ? CF_NOSELECT
: 0);
166 /* just convert to start in listmode after the fact, easier that way */
167 if(flags
& SFL_STARTIN_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
;
179 ctmp
->keymenu
= &sel_from_list_olm
;
182 if(flags
& SFL_CTRLC
)
183 ctmp
->keymenu
= &sel_from_list_lm_ctrlc
;
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
)){
200 ps_global
->mangled_screen
= 1;
206 select_from_list_tool(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned int flags
)
213 if(*(*cl
)->d
.l
.listmode
== SingleMode
){
214 (*cl
)->d
.l
.lsel
->selected
= 1;
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
){
230 q_status_message(SM_ORDER
, 0, 3,
231 _("Nothing selected, use Exit to exit without a selection."));
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
;
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;
279 if((*cl
)->value
[1] == 'X'){
280 (*cl
)->d
.l
.lsel
->selected
= 0;
281 (*cl
)->value
[1] = SPACE
;
284 (*cl
)->d
.l
.lsel
->selected
= 1;
285 (*cl
)->value
[1] = 'X';
288 ps
->mangled_body
= 1;
292 retval
= simple_exit_cmd(flags
);
301 ps
->mangled_body
= 1;
308 select_from_list_tool_allow_noselections(struct pine
*ps
, int cmd
, CONF_S
**cl
, unsigned int flags
)
315 if(*(*cl
)->d
.l
.listmode
== SingleMode
)
316 (*cl
)->d
.l
.lsel
->selected
= 1;
321 retval
= select_from_list_tool(ps
, cmd
, cl
, flags
);
326 ps
->mangled_body
= 1;