menuselect_newt.c 10 KB

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