pjsip_add_use_callerid_contact: fixed alembic script
[asterisk/asterisk.git] / menuselect / menuselect_newt.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2008 Sean Bright
5  *
6  * Sean Bright <sean.bright@gmail.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*
20  * \file
21  *
22  * \author Sean Bright <sean.bright@gmail.com>
23  *
24  * \brief newt frontend for selection maintenance
25  */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <newt.h>
31
32 #include "menuselect.h"
33
34 #define MIN_X 80
35 #define MIN_Y 21
36
37 #define MIN(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); ((__a > __b) ? __b : __a);})
38 #define MAX(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); ((__a < __b) ? __b : __a);})
39
40 extern int changes_made;
41
42 static newtComponent rootOptions;
43 static newtComponent subOptions;
44
45 static newtComponent memberNameTextbox;
46 static newtComponent dependsLabel;
47 static newtComponent usesLabel;
48 static newtComponent conflictsLabel;
49 static newtComponent supportLevelLabel;
50 static newtComponent dependsDataTextbox;
51 static newtComponent usesDataTextbox;
52 static newtComponent conflictsDataTextbox;
53 static newtComponent supportLevelDataTextbox;
54
55 static newtComponent exitButton;
56 static newtComponent saveAndExitButton;
57
58 static void build_members_menu(int overlay);
59 static void root_menu_callback(newtComponent component, void *data);
60
61 static void toggle_all_options(int select)
62 {
63         struct category *cat = newtListboxGetCurrent(rootOptions);
64
65         set_all(cat, select);
66
67         /* Redraw */
68         build_members_menu(1);
69
70         return;
71 }
72
73 static void toggle_selected_option()
74 {
75         int i;
76         struct member *mem = newtListboxGetCurrent(subOptions);
77
78         toggle_enabled(mem);
79
80         /* Redraw */
81         build_members_menu(1);
82
83         /* Select the next item in the list */
84         for (i = 0; i < newtListboxItemCount(subOptions); i++) {
85                 struct member *cur;
86
87                 newtListboxGetEntry(subOptions, i, NULL, (void **) &cur);
88
89                 if (cur == mem) {
90                         i = MIN(i + 1, newtListboxItemCount(subOptions) - 1);
91                         break;
92                 }
93         }
94
95         newtListboxSetCurrent(subOptions, i);
96
97         return;
98 }
99
100 static void reset_display()
101 {
102         newtTextboxSetText(memberNameTextbox, "");
103         newtTextboxSetText(dependsDataTextbox, "");
104         newtTextboxSetText(usesDataTextbox, "");
105         newtTextboxSetText(conflictsDataTextbox, "");
106         newtTextboxSetText(supportLevelDataTextbox, "");
107         newtRefresh();
108 }
109
110 static void display_member_info(struct member *mem)
111 {
112         char buffer[128] = { 0 };
113
114         struct reference *dep;
115         struct reference *con;
116         struct reference *uses;
117
118         reset_display();
119
120         if (mem->displayname) {
121                 newtTextboxSetText(memberNameTextbox, mem->displayname);
122         }
123
124         if (AST_LIST_EMPTY(&mem->deps)) {
125                 if (mem->is_separator) {
126                         newtTextboxSetText(dependsDataTextbox, "");
127                 } else {
128                         newtTextboxSetText(dependsDataTextbox, "N/A");
129                 }
130         } else {
131                 strcpy(buffer, "");
132                 AST_LIST_TRAVERSE(&mem->deps, dep, list) {
133                         strncat(buffer, dep->displayname, sizeof(buffer) - strlen(buffer) - 1);
134                         strncat(buffer, dep->member ? "(M)" : "(E)", sizeof(buffer) - strlen(buffer) - 1);
135                         if (AST_LIST_NEXT(dep, list))
136                                 strncat(buffer, ", ", sizeof(buffer) - strlen(buffer) - 1);
137                 }
138                 newtTextboxSetText(dependsDataTextbox, buffer);
139         }
140
141         if (AST_LIST_EMPTY(&mem->uses)) {
142                 if (mem->is_separator) {
143                         newtTextboxSetText(usesDataTextbox, "");
144                 } else {
145                         newtTextboxSetText(usesDataTextbox, "N/A");
146                 }
147         } else {
148                 strcpy(buffer, "");
149                 AST_LIST_TRAVERSE(&mem->uses, uses, list) {
150                         strncat(buffer, uses->displayname, sizeof(buffer) - strlen(buffer) - 1);
151                         strncat(buffer, uses->member ? "(M)" : "(E)", sizeof(buffer) - strlen(buffer) - 1);
152                         if (AST_LIST_NEXT(uses, list))
153                                 strncat(buffer, ", ", sizeof(buffer) - strlen(buffer) - 1);
154                 }
155                 newtTextboxSetText(usesDataTextbox, buffer);
156         }
157
158         if (AST_LIST_EMPTY(&mem->conflicts)) {
159                 if (!mem->is_separator) {
160                         newtTextboxSetText(conflictsDataTextbox, "N/A");
161                 } else {
162                         newtTextboxSetText(conflictsDataTextbox, "");
163                 }
164         } else {
165                 strcpy(buffer, "");
166                 AST_LIST_TRAVERSE(&mem->conflicts, con, list) {
167                         strncat(buffer, con->displayname, sizeof(buffer) - strlen(buffer) - 1);
168                         strncat(buffer, con->member ? "(M)" : "(E)", sizeof(buffer) - strlen(buffer) - 1);
169                         if (AST_LIST_NEXT(con, list))
170                                 strncat(buffer, ", ", sizeof(buffer) - strlen(buffer) - 1);
171                 }
172                 newtTextboxSetText(conflictsDataTextbox, buffer);
173         }
174
175         { /* Support Level */
176                 snprintf(buffer, sizeof(buffer), "%s", mem->support_level);
177                 if (mem->replacement && *mem->replacement) {
178                         char buf2[64];
179                         snprintf(buf2, sizeof(buf2), ", Replaced by: %s", mem->replacement);
180                         strncat(buffer, buf2, sizeof(buffer) - strlen(buffer) - 1);
181                 }
182                 if (mem->is_separator) {
183                         newtTextboxSetText(supportLevelDataTextbox, "");
184                 } else {
185                         newtTextboxSetText(supportLevelDataTextbox, buffer);
186                 }
187         }
188 }
189
190 static void build_members_menu(int overlay)
191 {
192         struct category *cat;
193         struct member *mem;
194         char buf[64];
195         int i = 0;
196
197         if (!overlay) {
198                 reset_display();
199                 newtListboxClear(subOptions);
200         }
201
202         cat = newtListboxGetCurrent(rootOptions);
203
204         AST_LIST_TRAVERSE(&cat->members, mem, list) {
205
206                 if ((mem->depsfailed == HARD_FAILURE) || (mem->conflictsfailed == HARD_FAILURE)) {
207                         snprintf(buf, sizeof(buf), "XXX %s", mem->name);
208                 } else if (mem->is_separator) {
209                         snprintf(buf, sizeof(buf), "    --- %s ---", mem->name);
210                 } else if (mem->depsfailed == SOFT_FAILURE) {
211                         snprintf(buf, sizeof(buf), "<%s> %s", mem->enabled ? "*" : " ", mem->name);
212                 } else if (mem->conflictsfailed == SOFT_FAILURE) {
213                         snprintf(buf, sizeof(buf), "(%s) %s", mem->enabled ? "*" : " ", mem->name);
214                 } else {
215                         snprintf(buf, sizeof(buf), "[%s] %s", mem->enabled ? "*" : " ", mem->name);
216                 }
217
218                 if (overlay) {
219                         newtListboxSetEntry(subOptions, i, buf);
220                 } else {
221                         newtListboxAppendEntry(subOptions, buf, mem);
222                 }
223
224                 i++;
225         }
226
227         if (!overlay) {
228                 display_member_info(AST_LIST_FIRST(&cat->members));
229         }
230
231         return;
232 }
233
234 static void build_main_menu()
235 {
236         struct category *cat;
237         char buf[64];
238         int i = 1;
239
240         newtListboxClear(rootOptions);
241
242         AST_LIST_TRAVERSE(&categories, cat, list) {
243                 if (!strlen_zero(cat->displayname))
244                         snprintf(buf, sizeof(buf), " %s ", cat->displayname);
245                 else
246                         snprintf(buf, sizeof(buf), " %s ", cat->name);
247
248                 newtListboxAppendEntry(rootOptions, buf, cat);
249
250                 i++;
251         }
252 }
253
254 static void category_menu_callback(newtComponent component, void *data)
255 {
256         display_member_info(newtListboxGetCurrent(subOptions));
257 }
258
259 static void root_menu_callback(newtComponent component, void *data)
260 {
261         build_members_menu(0);
262 }
263
264 int run_confirmation_dialog(int *result)
265 {
266         int res = newtWinTernary("Are You Sure?", "Discard changes & Exit", "Save & Exit", "Cancel",
267                                    "It appears you have made some changes, and you have opted to Quit "
268                                    "without saving these changes.  Please choose \"Discard changes & Exit\" to exit "
269                                    "without saving; Choose \"Cancel\" to cancel your decision to quit, and keep "
270                                    "working in menuselect, or choose \"Save & Exit\" to save your changes, and exit.");
271
272         switch (res) {
273         case 1:
274                 /* Discard and exit */
275                 *result = -1;
276                 return 1;
277         case 2:
278                 /* Save and exit */
279                 *result = 0;
280                 return 1;
281         case 3:
282                 /* They either chose "No" or they hit F12 */
283         default:
284                 *result = -1;
285                 return 0;
286         }
287 }
288
289 int run_menu(void)
290 {
291         struct newtExitStruct es;
292         newtComponent form;
293         int x = 0, y = 0, res = 0;
294
295         newtInit();
296         newtCls();
297         newtGetScreenSize(&x, &y);
298
299         if (x < MIN_X || y < MIN_Y) {
300                 newtFinished();
301                 fprintf(stderr, "Terminal must be at least %d x %d.\n", MIN_X, MIN_Y);
302                 return -1;
303         }
304
305         newtPushHelpLine("  <ENTER> toggles selection | <F12> saves & exits | <ESC> exits without save");
306         newtRefresh();
307
308         newtCenteredWindow(x - 8, y - 7, menu_name);
309         form = newtForm(NULL, NULL, 0);
310
311         /* F8 for select all */
312         newtFormAddHotKey(form, NEWT_KEY_F8);
313
314         /* F7 for deselect all */
315         newtFormAddHotKey(form, NEWT_KEY_F7);
316
317         newtFormSetTimer(form, 200);
318
319         rootOptions = newtListbox(2, 1, y - 15, 0);
320         newtListboxSetWidth(rootOptions, 34);
321         newtFormAddComponent(form, rootOptions);
322         newtComponentAddCallback(rootOptions, root_menu_callback, NULL);
323
324         subOptions = newtListbox(38, 1, y - 15, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
325         newtListboxSetWidth(subOptions, x - 47);
326         newtFormAddComponent(form, subOptions);
327         newtComponentAddCallback(subOptions, category_menu_callback, NULL);
328
329         memberNameTextbox       = newtTextbox(2, y - 13, x - 10, 2, NEWT_FLAG_WRAP);
330         dependsLabel            = newtLabel(2, y - 11, "    Depends on:");
331         usesLabel               = newtLabel(2, y - 10, "       Can use:");
332         conflictsLabel          = newtLabel(2, y - 9,  "Conflicts with:");
333         supportLevelLabel       = newtLabel(2, y - 8,  " Support Level:");
334         dependsDataTextbox      = newtTextbox(18, y - 11, x - 27, 1, 0);
335         usesDataTextbox         = newtTextbox(18, y - 10, x - 27, 1, 0);
336         conflictsDataTextbox    = newtTextbox(18, y - 9, x - 27, 1, 0);
337         supportLevelDataTextbox = newtTextbox(18, y - 8, x - 27, 1, 0);
338
339         exitButton = newtButton(x - 23, y - 11, "  Exit  ");
340         saveAndExitButton = newtButton(x - 43, y - 11, " Save & Exit ");
341
342         newtFormAddComponents(
343                 form,
344                 memberNameTextbox,
345                 dependsLabel,
346                 dependsDataTextbox,
347                 usesLabel,
348                 usesDataTextbox,
349                 conflictsLabel,
350                 conflictsDataTextbox,
351                 supportLevelLabel,
352                 supportLevelDataTextbox,
353                 saveAndExitButton,
354                 exitButton,
355                 NULL);
356
357         build_main_menu();
358
359         root_menu_callback(rootOptions, AST_LIST_FIRST(&categories));
360
361         for (;;) {
362                 do {
363                         newtFormRun(form, &es);
364                 } while (es.reason == NEWT_EXIT_TIMER);
365
366                 if (es.reason == NEWT_EXIT_HOTKEY) {
367                         int done = 1;
368
369                         switch (es.u.key) {
370                         case NEWT_KEY_F12:
371                                 res = 0;
372                                 break;
373                         case NEWT_KEY_F7:
374                                 toggle_all_options(0);
375                                 done = 0;
376                                 break;
377                         case NEWT_KEY_F8:
378                                 toggle_all_options(1);
379                                 done = 0;
380                                 break;
381                         case NEWT_KEY_ESCAPE:
382                                 if (changes_made) {
383                                         done = run_confirmation_dialog(&res);
384                                 } else {
385                                         res = -1;
386                                 }
387                                 break;
388                         default:
389                                 done = 0;
390                                 break;
391                         }
392
393                         if (done) {
394                                 break;
395                         }
396                 } else if (es.reason == NEWT_EXIT_COMPONENT) {
397                         if (es.u.co == saveAndExitButton) {
398                                 res = 0;
399                                 break;
400                         } else if (es.u.co == exitButton) {
401                                 int done = 1;
402
403                                 if (changes_made) {
404                                         done = run_confirmation_dialog(&res);
405                                 } else {
406                                         res = -1;
407                                 }
408
409                                 if (done) {
410                                         break;
411                                 }
412                         } else if (es.u.co == subOptions) {
413                                 toggle_selected_option();
414                         }
415                 }
416         }
417
418         /* Cleanup */
419         reset_display();
420         newtFormDestroy(form);
421         newtPopWindow();
422         newtPopHelpLine();
423         newtCls();
424         newtFinished();
425
426         return res;
427 }