Skip to content
Snippets Groups Projects
Select Git revision
  • 16.10.0
  • devel default
  • wenpeng-hot-fix
  • wenpeng-0905-mem
  • lk_debug_dialogs
  • asterisk_rdkb
  • lk_forking_revert
  • lk_em_update_new_design
  • wenpeng-jul8
  • gyang-devel
  • gyang-devel1
  • wenpeng-jul9
  • asterisk_rdkb_ipv6
  • 16916_rdkb_merge
  • lk_disable_registrar
  • wenpeng-100rel-ippbx
  • fix_multiple_dns_lookup
  • dev_fxs_no_wb
  • fix_fallback
  • 14666_fxs_no_wideband_codec
  • fix_srv_records
  • fix_deadlock_in_bridge_peer_functions
  • 22.0.0-pre1
  • 21.4.2
  • 20.9.2
  • 18.24.2
  • certified-20.7-cert2
  • certified-18.9-cert11
  • 21.4.1
  • 20.9.1
  • 18.24.1
  • 21.4.0
  • 20.9.0
  • 18.24.0
  • certified-20.7-cert1
  • certified-18.9-cert10
  • 21.4.0-rc1
  • 20.9.0-rc1
  • 18.24.0-rc1
  • 21.3.1
  • 20.8.1
  • 18.23.1
42 results

menuselect_newt.c

  • user avatar
    George Joseph authored
    * Add 'external' as a support level.
    * Add ability for module directories to add entries to the menu
      by adding members to the <module_prefix>/<module_prefix>.xml file.
    * Expand the description field to 3 lines in the ncurses implementation.
    * Allow the description field to wrap in the newt implementation.
    * Add description field to the gtk implementation.
    
    Change-Id: I7f9600a1984a42ce0696db574c1051bc9ad7c808
    b4c5dcad
    History
    menuselect_newt.c 10.44 KiB
    /*
     * 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, 2, NEWT_FLAG_WRAP);
    	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;
    }