a885b2c253
Menuselect was originally included in the DAHDI-Tools repository with an svn external. Since git does not handle externals so well, menuselect is being brought into the tree directly. This allows menuselect to be present for all the commits on the 2.4, 2.5, and 2.6 releases. The command is: $ svn export http://svn.asterisk.org/svn/menuselect/trunk menuselect Signed-off-by: Shaun Ruffell <sruffell@digium.com>
428 lines
10 KiB
C
428 lines
10 KiB
C
/*
|
|
* Asterisk -- An open source telephony toolkit.
|
|
*
|
|
* Copyright (C) 2008 Sean Bright
|
|
*
|
|
* Sean Bright <sean.bright@gmail.com>
|
|
*
|
|
* See http://www.asterisk.org for more information about
|
|
* the Asterisk project. Please do not directly contact
|
|
* any of the maintainers of this project for assistance;
|
|
* the project provides a web site, mailing lists and IRC
|
|
* channels for your use.
|
|
*
|
|
* This program is free software, distributed under the terms of
|
|
* the GNU General Public License Version 2. See the LICENSE file
|
|
* at the top of the source tree.
|
|
*/
|
|
|
|
/*
|
|
* \file
|
|
*
|
|
* \author Sean Bright <sean.bright@gmail.com>
|
|
*
|
|
* \brief newt frontend for selection maintenance
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <newt.h>
|
|
|
|
#include "menuselect.h"
|
|
|
|
#define MIN_X 80
|
|
#define MIN_Y 21
|
|
|
|
#define MIN(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); ((__a > __b) ? __b : __a);})
|
|
#define MAX(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); ((__a < __b) ? __b : __a);})
|
|
|
|
extern int changes_made;
|
|
|
|
static newtComponent rootOptions;
|
|
static newtComponent subOptions;
|
|
|
|
static newtComponent memberNameTextbox;
|
|
static newtComponent dependsLabel;
|
|
static newtComponent usesLabel;
|
|
static newtComponent conflictsLabel;
|
|
static newtComponent supportLevelLabel;
|
|
static newtComponent dependsDataTextbox;
|
|
static newtComponent usesDataTextbox;
|
|
static newtComponent conflictsDataTextbox;
|
|
static newtComponent supportLevelDataTextbox;
|
|
|
|
static newtComponent exitButton;
|
|
static newtComponent saveAndExitButton;
|
|
|
|
static void build_members_menu(int overlay);
|
|
static void root_menu_callback(newtComponent component, void *data);
|
|
|
|
static void toggle_all_options(int select)
|
|
{
|
|
struct category *cat = newtListboxGetCurrent(rootOptions);
|
|
|
|
set_all(cat, select);
|
|
|
|
/* Redraw */
|
|
build_members_menu(1);
|
|
|
|
return;
|
|
}
|
|
|
|
static void toggle_selected_option()
|
|
{
|
|
int i;
|
|
struct member *mem = newtListboxGetCurrent(subOptions);
|
|
|
|
toggle_enabled(mem);
|
|
|
|
/* Redraw */
|
|
build_members_menu(1);
|
|
|
|
/* Select the next item in the list */
|
|
for (i = 0; i < newtListboxItemCount(subOptions); i++) {
|
|
struct member *cur;
|
|
|
|
newtListboxGetEntry(subOptions, i, NULL, (void **) &cur);
|
|
|
|
if (cur == mem) {
|
|
i = MIN(i + 1, newtListboxItemCount(subOptions) - 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
newtListboxSetCurrent(subOptions, i);
|
|
|
|
return;
|
|
}
|
|
|
|
static void reset_display()
|
|
{
|
|
newtTextboxSetText(memberNameTextbox, "");
|
|
newtTextboxSetText(dependsDataTextbox, "");
|
|
newtTextboxSetText(usesDataTextbox, "");
|
|
newtTextboxSetText(conflictsDataTextbox, "");
|
|
newtTextboxSetText(supportLevelDataTextbox, "");
|
|
newtRefresh();
|
|
}
|
|
|
|
static void display_member_info(struct member *mem)
|
|
{
|
|
char buffer[128] = { 0 };
|
|
|
|
struct reference *dep;
|
|
struct reference *con;
|
|
struct reference *uses;
|
|
|
|
reset_display();
|
|
|
|
if (mem->displayname) {
|
|
newtTextboxSetText(memberNameTextbox, mem->displayname);
|
|
}
|
|
|
|
if (AST_LIST_EMPTY(&mem->deps)) {
|
|
if (mem->is_separator) {
|
|
newtTextboxSetText(dependsDataTextbox, "");
|
|
} else {
|
|
newtTextboxSetText(dependsDataTextbox, "N/A");
|
|
}
|
|
} else {
|
|
strcpy(buffer, "");
|
|
AST_LIST_TRAVERSE(&mem->deps, dep, list) {
|
|
strncat(buffer, dep->displayname, sizeof(buffer) - strlen(buffer) - 1);
|
|
strncat(buffer, dep->member ? "(M)" : "(E)", sizeof(buffer) - strlen(buffer) - 1);
|
|
if (AST_LIST_NEXT(dep, list))
|
|
strncat(buffer, ", ", sizeof(buffer) - strlen(buffer) - 1);
|
|
}
|
|
newtTextboxSetText(dependsDataTextbox, buffer);
|
|
}
|
|
|
|
if (AST_LIST_EMPTY(&mem->uses)) {
|
|
if (mem->is_separator) {
|
|
newtTextboxSetText(usesDataTextbox, "");
|
|
} else {
|
|
newtTextboxSetText(usesDataTextbox, "N/A");
|
|
}
|
|
} else {
|
|
strcpy(buffer, "");
|
|
AST_LIST_TRAVERSE(&mem->uses, uses, list) {
|
|
strncat(buffer, uses->displayname, sizeof(buffer) - strlen(buffer) - 1);
|
|
strncat(buffer, uses->member ? "(M)" : "(E)", sizeof(buffer) - strlen(buffer) - 1);
|
|
if (AST_LIST_NEXT(uses, list))
|
|
strncat(buffer, ", ", sizeof(buffer) - strlen(buffer) - 1);
|
|
}
|
|
newtTextboxSetText(usesDataTextbox, buffer);
|
|
}
|
|
|
|
if (AST_LIST_EMPTY(&mem->conflicts)) {
|
|
if (!mem->is_separator) {
|
|
newtTextboxSetText(conflictsDataTextbox, "N/A");
|
|
} else {
|
|
newtTextboxSetText(conflictsDataTextbox, "");
|
|
}
|
|
} else {
|
|
strcpy(buffer, "");
|
|
AST_LIST_TRAVERSE(&mem->conflicts, con, list) {
|
|
strncat(buffer, con->displayname, sizeof(buffer) - strlen(buffer) - 1);
|
|
strncat(buffer, con->member ? "(M)" : "(E)", sizeof(buffer) - strlen(buffer) - 1);
|
|
if (AST_LIST_NEXT(con, list))
|
|
strncat(buffer, ", ", sizeof(buffer) - strlen(buffer) - 1);
|
|
}
|
|
newtTextboxSetText(conflictsDataTextbox, buffer);
|
|
}
|
|
|
|
{ /* Support Level */
|
|
snprintf(buffer, sizeof(buffer), "%s", mem->support_level);
|
|
if (mem->replacement && *mem->replacement) {
|
|
char buf2[64];
|
|
snprintf(buf2, sizeof(buf2), ", Replaced by: %s", mem->replacement);
|
|
strncat(buffer, buf2, sizeof(buffer) - strlen(buffer) - 1);
|
|
}
|
|
if (mem->is_separator) {
|
|
newtTextboxSetText(supportLevelDataTextbox, "");
|
|
} else {
|
|
newtTextboxSetText(supportLevelDataTextbox, buffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void build_members_menu(int overlay)
|
|
{
|
|
struct category *cat;
|
|
struct member *mem;
|
|
char buf[64];
|
|
int i = 0;
|
|
|
|
if (!overlay) {
|
|
reset_display();
|
|
newtListboxClear(subOptions);
|
|
}
|
|
|
|
cat = newtListboxGetCurrent(rootOptions);
|
|
|
|
AST_LIST_TRAVERSE(&cat->members, mem, list) {
|
|
|
|
if ((mem->depsfailed == HARD_FAILURE) || (mem->conflictsfailed == HARD_FAILURE)) {
|
|
snprintf(buf, sizeof(buf), "XXX %s", mem->name);
|
|
} else if (mem->is_separator) {
|
|
snprintf(buf, sizeof(buf), " --- %s ---", mem->name);
|
|
} else if (mem->depsfailed == SOFT_FAILURE) {
|
|
snprintf(buf, sizeof(buf), "<%s> %s", mem->enabled ? "*" : " ", mem->name);
|
|
} else if (mem->conflictsfailed == SOFT_FAILURE) {
|
|
snprintf(buf, sizeof(buf), "(%s) %s", mem->enabled ? "*" : " ", mem->name);
|
|
} else {
|
|
snprintf(buf, sizeof(buf), "[%s] %s", mem->enabled ? "*" : " ", mem->name);
|
|
}
|
|
|
|
if (overlay) {
|
|
newtListboxSetEntry(subOptions, i, buf);
|
|
} else {
|
|
newtListboxAppendEntry(subOptions, buf, mem);
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
if (!overlay) {
|
|
display_member_info(AST_LIST_FIRST(&cat->members));
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void build_main_menu()
|
|
{
|
|
struct category *cat;
|
|
char buf[64];
|
|
int i = 1;
|
|
|
|
newtListboxClear(rootOptions);
|
|
|
|
AST_LIST_TRAVERSE(&categories, cat, list) {
|
|
if (!strlen_zero(cat->displayname))
|
|
snprintf(buf, sizeof(buf), " %s ", cat->displayname);
|
|
else
|
|
snprintf(buf, sizeof(buf), " %s ", cat->name);
|
|
|
|
newtListboxAppendEntry(rootOptions, buf, cat);
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
static void category_menu_callback(newtComponent component, void *data)
|
|
{
|
|
display_member_info(newtListboxGetCurrent(subOptions));
|
|
}
|
|
|
|
static void root_menu_callback(newtComponent component, void *data)
|
|
{
|
|
build_members_menu(0);
|
|
}
|
|
|
|
int run_confirmation_dialog(int *result)
|
|
{
|
|
int res = newtWinTernary("Are You Sure?", "Discard changes & Exit", "Save & Exit", "Cancel",
|
|
"It appears you have made some changes, and you have opted to Quit "
|
|
"without saving these changes. Please choose \"Discard changes & Exit\" to exit "
|
|
"without saving; Choose \"Cancel\" to cancel your decision to quit, and keep "
|
|
"working in menuselect, or choose \"Save & Exit\" to save your changes, and exit.");
|
|
|
|
switch (res) {
|
|
case 1:
|
|
/* Discard and exit */
|
|
*result = -1;
|
|
return 1;
|
|
case 2:
|
|
/* Save and exit */
|
|
*result = 0;
|
|
return 1;
|
|
case 3:
|
|
/* They either chose "No" or they hit F12 */
|
|
default:
|
|
*result = -1;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
int run_menu(void)
|
|
{
|
|
struct newtExitStruct es;
|
|
newtComponent form;
|
|
int x = 0, y = 0, res = 0;
|
|
|
|
newtInit();
|
|
newtCls();
|
|
newtGetScreenSize(&x, &y);
|
|
|
|
if (x < MIN_X || y < MIN_Y) {
|
|
newtFinished();
|
|
fprintf(stderr, "Terminal must be at least %d x %d.\n", MIN_X, MIN_Y);
|
|
return -1;
|
|
}
|
|
|
|
newtPushHelpLine(" <ENTER> toggles selection | <F12> saves & exits | <ESC> exits without save");
|
|
newtRefresh();
|
|
|
|
newtCenteredWindow(x - 8, y - 7, menu_name);
|
|
form = newtForm(NULL, NULL, 0);
|
|
|
|
/* F8 for select all */
|
|
newtFormAddHotKey(form, NEWT_KEY_F8);
|
|
|
|
/* F7 for deselect all */
|
|
newtFormAddHotKey(form, NEWT_KEY_F7);
|
|
|
|
newtFormSetTimer(form, 200);
|
|
|
|
rootOptions = newtListbox(2, 1, y - 15, 0);
|
|
newtListboxSetWidth(rootOptions, 34);
|
|
newtFormAddComponent(form, rootOptions);
|
|
newtComponentAddCallback(rootOptions, root_menu_callback, NULL);
|
|
|
|
subOptions = newtListbox(38, 1, y - 15, NEWT_FLAG_SCROLL | NEWT_FLAG_RETURNEXIT);
|
|
newtListboxSetWidth(subOptions, x - 47);
|
|
newtFormAddComponent(form, subOptions);
|
|
newtComponentAddCallback(subOptions, category_menu_callback, NULL);
|
|
|
|
memberNameTextbox = newtTextbox(2, y - 13, x - 10, 1, 0);
|
|
dependsLabel = newtLabel(2, y - 11, " Depends on:");
|
|
usesLabel = newtLabel(2, y - 10, " Can use:");
|
|
conflictsLabel = newtLabel(2, y - 9, "Conflicts with:");
|
|
supportLevelLabel = newtLabel(2, y - 8, " Support Level:");
|
|
dependsDataTextbox = newtTextbox(18, y - 11, x - 27, 1, 0);
|
|
usesDataTextbox = newtTextbox(18, y - 10, x - 27, 1, 0);
|
|
conflictsDataTextbox = newtTextbox(18, y - 9, x - 27, 1, 0);
|
|
supportLevelDataTextbox = newtTextbox(18, y - 8, x - 27, 1, 0);
|
|
|
|
exitButton = newtButton(x - 23, y - 11, " Exit ");
|
|
saveAndExitButton = newtButton(x - 43, y - 11, " Save & Exit ");
|
|
|
|
newtFormAddComponents(
|
|
form,
|
|
memberNameTextbox,
|
|
dependsLabel,
|
|
dependsDataTextbox,
|
|
usesLabel,
|
|
usesDataTextbox,
|
|
conflictsLabel,
|
|
conflictsDataTextbox,
|
|
supportLevelLabel,
|
|
supportLevelDataTextbox,
|
|
saveAndExitButton,
|
|
exitButton,
|
|
NULL);
|
|
|
|
build_main_menu();
|
|
|
|
root_menu_callback(rootOptions, AST_LIST_FIRST(&categories));
|
|
|
|
for (;;) {
|
|
do {
|
|
newtFormRun(form, &es);
|
|
} while (es.reason == NEWT_EXIT_TIMER);
|
|
|
|
if (es.reason == NEWT_EXIT_HOTKEY) {
|
|
int done = 1;
|
|
|
|
switch (es.u.key) {
|
|
case NEWT_KEY_F12:
|
|
res = 0;
|
|
break;
|
|
case NEWT_KEY_F7:
|
|
toggle_all_options(0);
|
|
done = 0;
|
|
break;
|
|
case NEWT_KEY_F8:
|
|
toggle_all_options(1);
|
|
done = 0;
|
|
break;
|
|
case NEWT_KEY_ESCAPE:
|
|
if (changes_made) {
|
|
done = run_confirmation_dialog(&res);
|
|
} else {
|
|
res = -1;
|
|
}
|
|
break;
|
|
default:
|
|
done = 0;
|
|
break;
|
|
}
|
|
|
|
if (done) {
|
|
break;
|
|
}
|
|
} else if (es.reason == NEWT_EXIT_COMPONENT) {
|
|
if (es.u.co == saveAndExitButton) {
|
|
res = 0;
|
|
break;
|
|
} else if (es.u.co == exitButton) {
|
|
int done = 1;
|
|
|
|
if (changes_made) {
|
|
done = run_confirmation_dialog(&res);
|
|
} else {
|
|
res = -1;
|
|
}
|
|
|
|
if (done) {
|
|
break;
|
|
}
|
|
} else if (es.u.co == subOptions) {
|
|
toggle_selected_option();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Cleanup */
|
|
reset_display();
|
|
newtFormDestroy(form);
|
|
newtPopWindow();
|
|
newtPopHelpLine();
|
|
newtCls();
|
|
newtFinished();
|
|
|
|
return res;
|
|
}
|