Un-ignored: the dev drive is the ground truth the restoration and emulator work constantly reference (DPL3/LIBDPL + VRENDER i860 renderer source, BT/RP live+dev game trees, VGL_LABS pod boot, scene/audio content). Kept in-repo for the pod-owner community. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1452 lines
36 KiB
Plaintext
1452 lines
36 KiB
Plaintext
/*
|
|
** BRIEF -- Basic Reconfigurable Interactive Editing Facility
|
|
**
|
|
**
|
|
** dialog.cb:
|
|
**
|
|
** This file contains all of the standard BRIEF macros for the
|
|
** dialog and menu manager.
|
|
*/
|
|
|
|
#define DIALOG_MAIN
|
|
#include "dialog.h"
|
|
#include "dlg.h"
|
|
#include "win_ctrl.h"
|
|
|
|
/*
|
|
** Dialog Manager Package: Note to Macro Programmers
|
|
**
|
|
** Input to an interactive macro must ultimately come from the
|
|
** keyboard. In addition to the primitive calls for keyboard
|
|
** handling (assign_to_key, get_parm, read_char, etc.) we have
|
|
** provided two high-level calls which provide a simple, consistent,
|
|
** and attractive user interface. We strongly recommend that you
|
|
** use the built-in dialog manager calls in your macros instead of
|
|
** writing your own user interface.
|
|
*/
|
|
|
|
|
|
/*
|
|
** Global variables.
|
|
*/
|
|
|
|
int _dialog_level,
|
|
_dialog_type,
|
|
_dialog_row,
|
|
_dialog_col,
|
|
_dialog_field_keymap,
|
|
_dialog_list_keymap,
|
|
_dialog_menu_keymap,
|
|
_dialog_button_keymap,
|
|
_dialog_size,
|
|
_dialog_data_buf,
|
|
_dialog_disp_buf,
|
|
_dialog_radio_buf,
|
|
_dialog_mouse_buf,
|
|
_dialog_mode,
|
|
_dialog_menu_time,
|
|
_dialog_picked,
|
|
_dialog_pb_state;
|
|
|
|
string _dialog_action_func,
|
|
_dialog_dir,
|
|
_dialog_menu_prefix,
|
|
_dialog_default_pb;
|
|
|
|
|
|
/*
|
|
** init:
|
|
**
|
|
** Initialize the dialog manager package. This must always be
|
|
** the first call to the dialog manager; it is run whenever the
|
|
** file is loaded.
|
|
*/
|
|
|
|
void _init ()
|
|
{
|
|
if (first_time ())
|
|
{
|
|
|
|
/*
|
|
** First we get the name of the directory in which the
|
|
** menu files and help files are kept.
|
|
*/
|
|
|
|
if (!strlen (_dialog_dir = inq_environment ("BHELP")))
|
|
_dialog_dir = "/brief/help";
|
|
|
|
/*
|
|
** We now create 3 keymaps; the only assignments they have
|
|
** in common are the grey - and the Esc key.
|
|
**
|
|
** Here we create a keymap for use with menus. Note that
|
|
** at every level you can use the INIT and TERM hooks to
|
|
** add your own key assignments to this keymap; just
|
|
** remember to restore the old assignments, or your keys
|
|
** will be wrong when you return to a lower-level menu.
|
|
*/
|
|
|
|
keyboard_push ();
|
|
assign_to_key ("<Down>", "_dialog_menu_down");
|
|
assign_to_key ("<Space>", "_dialog_menu_down");
|
|
assign_to_key ("<Up>", "_dialog_menu_up");
|
|
assign_to_key ("<Backspace>", "_dialog_menu_up");
|
|
assign_to_key ("<Enter>", "_dialog_menu_pick");
|
|
assign_to_key ("<Keypad-Enter>", "_dialog_menu_pick");
|
|
assign_to_key ("<Esc>", "_dialog_esc");
|
|
assign_to_key ("<Keypad minus>", "_dialog_grey_minus");
|
|
assign_to_key ("<Home>", "_dialog_menu_home");
|
|
assign_to_key ("<Ctrl-Home>", "_dialog_menu_home");
|
|
assign_to_key ("<End>", "_dialog_menu_end");
|
|
assign_to_key ("<Ctrl-End>", "_dialog_menu_end");
|
|
assign_to_key ("<PgUp>", "_dialog_menu_pgup");
|
|
assign_to_key ("<PgDn>", "_dialog_menu_pgdn");
|
|
_dialog_menu_keymap = inq_keyboard ();
|
|
keyboard_pop (TRUE);
|
|
|
|
/*
|
|
** Here we create a keymap for use with lists. It also
|
|
** contains the general field-to-field key assignments.
|
|
*/
|
|
|
|
keyboard_push ();
|
|
assign_to_key ("<F10>", "_dialog_f10");
|
|
assign_to_key ("<Enter>", "_dialog_next_and_save");
|
|
assign_to_key ("<Keypad-Enter>", "_dialog_next_and_save");
|
|
assign_to_key ("<Esc>", "_dialog_esc");
|
|
assign_to_key ("<Keypad minus>", "_dialog_grey_minus");
|
|
assign_to_key ("<Tab>", "_dialog_next");
|
|
assign_to_key ("<Down>", "_dialog_next");
|
|
assign_to_key ("<Shift-Tab>", "_dialog_prev");
|
|
assign_to_key ("<Up>", "_dialog_prev");
|
|
assign_to_key ("<Ctrl-Home>", "_dialog_home");
|
|
assign_to_key ("<Ctrl-End>", "_dialog_end");
|
|
assign_to_key ("<Backspace>", "_list_prev");
|
|
assign_to_key ("<Left>", "_list_prev");
|
|
assign_to_key ("<Space>", "_list_next");
|
|
assign_to_key ("<Right>", "_list_next");
|
|
assign_to_key ("<Home>", "_list_home");
|
|
assign_to_key ("<End>", "_list_end");
|
|
_dialog_list_keymap = inq_keyboard ();
|
|
keyboard_pop (TRUE);
|
|
|
|
|
|
/*
|
|
** Create a keymap for use with buttons.
|
|
*/
|
|
|
|
keyboard_push ();
|
|
assign_to_key ("<Space>", "_dlg_pick_btn");
|
|
assign_to_key ("<Backspace>", "_dlg_beep");
|
|
assign_to_key ("<Home>", "_dlg_beep");
|
|
assign_to_key ("<End>", "_dlg_beep");
|
|
assign_to_key ("<Left>", "_dlg_btn_prev");
|
|
assign_to_key ("<Up>", "_dlg_btn_prev");
|
|
assign_to_key ("<Right>", "_dlg_btn_next");
|
|
assign_to_key ("<Down>", "_dlg_btn_next");
|
|
assign_to_key ("<Tab>", "_dlg_btn_tab_next");
|
|
assign_to_key ("<Shift-Tab>", "_dlg_btn_tab_prev");
|
|
_dialog_button_keymap = inq_keyboard ();
|
|
keyboard_pop (TRUE);
|
|
|
|
/*
|
|
** Here we create a keymap for use with typed fields.
|
|
** When we're done, we restore the previous keymap.
|
|
*/
|
|
|
|
keyboard_push ();
|
|
assign_to_key ("<Backspace>", "_field_bksp");
|
|
assign_to_key ("<Space>", "_field_insert 32");
|
|
assign_to_key ("<Left>", "_field_left");
|
|
assign_to_key ("<Right>", "_field_right");
|
|
assign_to_key ("<Del>", "_field_del");
|
|
assign_to_key ("<Home>", "_field_home");
|
|
assign_to_key ("<End>", "_field_end");
|
|
assign_to_key ("<Alt-k>", "_field_delete_to_eol");
|
|
assign_to_key ("<Alt-d>", "_field_del_line");
|
|
assign_to_key ("<Ins>", "insert_mode");
|
|
assign_to_key ("<Alt-i>", "insert_mode");
|
|
_dialog_field_keymap = inq_keyboard ();
|
|
keyboard_pop (TRUE);
|
|
|
|
/*
|
|
** Autoload the list, field, menu and button functions.
|
|
*/
|
|
|
|
autoload ("dlg_list", "_list_next", "_list_prev", "_list_highlight",
|
|
"_list_home", "_list_end", "_list_go", "_list_button",
|
|
"_is_list");
|
|
|
|
autoload ("dlg_fld", "_field_insert", "_field_bksp", "_field_left",
|
|
"_field_right", "_field_del", "_field_end", "_field_home",
|
|
"_field_del_line", "_field_delete_to_eol",
|
|
"_dialog_validate", "is_filename", "at_eol",
|
|
"_field_contents");
|
|
|
|
autoload ("dlg_menu", "_menu_highlight", "_dialog_menu_home",
|
|
"_dialog_menu_end", "_dialog_menu_pgup",
|
|
"_dialog_menu_pgdn", "_dialog_menu_down",
|
|
"_dialog_menu_up", "_menu_go", "_dialog_menu_pick",
|
|
"_menu_button", "mouse_menu");
|
|
|
|
autoload ("dlg_butn", "_dialog_check_button", "_dialog_is_checked",
|
|
"_dialog_check_radio", "_dialog_radio_checked",
|
|
"_dlg_goto_btn", "_dlg_check_btn", "_dlg_push_btn",
|
|
"_dlg_radio_btn", "_dlg_radio_grp", "_dlg_pick_btn",
|
|
"_dlg_select_push", "_dlg_btn_tab_next",
|
|
"_dlg_btn_tab_prev", "_dlg_btn_next", "_dlg_btn_prev",
|
|
"_is_push_button");
|
|
|
|
autoload ( "dlg_mous", "mouse_dialog" );
|
|
|
|
}
|
|
}
|
|
|
|
/*
|
|
** _remove_dialog_manager:
|
|
**
|
|
** You should call this macro whenever you are finished using the
|
|
** dialog manager. It frees the keymaps created when we load.
|
|
** It would be nice to have this function unload the macro file, but
|
|
** that's for a future release.
|
|
**
|
|
** Don't call this macro if you plan to use the dialog manager
|
|
** again in the same session.
|
|
*/
|
|
|
|
void _remove_dialog_manager (void)
|
|
{
|
|
if (first_time ())
|
|
{
|
|
keyboard_push (_dialog_menu_keymap);
|
|
keyboard_push (_dialog_list_keymap);
|
|
keyboard_push (_dialog_field_keymap);
|
|
keyboard_push (_dialog_button_keymap);
|
|
keyboard_pop ();
|
|
keyboard_pop ();
|
|
keyboard_pop ();
|
|
keyboard_pop ();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** _dialog_f10, _dialog_esc, _dialog_grey_minus:
|
|
**
|
|
** Call the action function with an appropriate code and exit
|
|
** from the dialog box, menu, or entire dialog manager.
|
|
*/
|
|
|
|
void _dialog_f10 (void)
|
|
{
|
|
/*
|
|
** When the F10 key is pressed, we have to verify the
|
|
** current field before we can exit. This function is
|
|
** only used in DIALOG_DBOX_MODE.
|
|
*/
|
|
|
|
if (_dialog_exit () && execute_macro (_dialog_action_func, DIALOG_F10))
|
|
_exit ();
|
|
}
|
|
|
|
void _dialog_esc (void)
|
|
{
|
|
int curr_level;
|
|
|
|
execute_macro (_dialog_action_func, DIALOG_ESCAPE);
|
|
curr_level = _dialog_level;
|
|
|
|
while (curr_level--)
|
|
_exit ();
|
|
}
|
|
|
|
void _dialog_grey_minus (void)
|
|
{
|
|
/*
|
|
** When the grey - key is pressed, we immediately exit one level.
|
|
*/
|
|
|
|
execute_macro (_dialog_action_func, DIALOG_GREY_MINUS);
|
|
_exit ();
|
|
}
|
|
|
|
/*
|
|
** _format_dialog:
|
|
**
|
|
** Parses the information buffer and formats the display buffer,
|
|
** leaving the display buffer current.
|
|
*/
|
|
|
|
void _format_dialog ()
|
|
{
|
|
int pos,
|
|
open_paren,
|
|
default_btn,
|
|
in_group,
|
|
first_in_group;
|
|
|
|
string line,
|
|
group;
|
|
|
|
_dialog_default_pb = "";
|
|
default_btn = 1;
|
|
_dialog_pb_state = TRUE; // no need to draw pb
|
|
|
|
set_buffer (_dialog_disp_buf);
|
|
tabs (2);
|
|
set_buffer (_dialog_data_buf);
|
|
inq_names (NULL, NULL, line);
|
|
execute_macro (_dialog_action_func, DIALOG_CREATE_DBOX, NULL, line);
|
|
top_of_buffer ();
|
|
|
|
/*
|
|
** Display all fields. We allow white space before the
|
|
** format commands in the buffer.
|
|
*/
|
|
|
|
while (search_fwd (in_group ? FIND_RADIO : FIND_ANY, TRUE, FALSE))
|
|
{
|
|
pos = index (line = _dialog_set_globals (), "\"") + 1;
|
|
line = substr (line, pos, rindex (line, "\"") - pos);
|
|
next_char ();
|
|
|
|
/*
|
|
** Move this up here when I can explain why...
|
|
*/
|
|
|
|
open_paren = TRUE;
|
|
|
|
switch (_dialog_type)
|
|
{
|
|
case LIST:
|
|
{
|
|
/*
|
|
** If we are formatting a list, we first make sure there's
|
|
** a current item. If there isn't, we must skip over the
|
|
** field since it could create serious errors later. If
|
|
** there is a current item but it's not the first item,
|
|
** we prepend a tab to the list so we'll be able to find
|
|
** the first button. We also stick a tab at the end of the
|
|
** list so we can find the end of the last item.
|
|
*/
|
|
|
|
if (_dialog_type == LIST)
|
|
{
|
|
if (open_paren = index (line, "("))
|
|
{
|
|
if (open_paren > 1)
|
|
line = "\t" + line;
|
|
|
|
_dialog_col--;
|
|
line += "\t";
|
|
}
|
|
}
|
|
}
|
|
|
|
case GROUP:
|
|
{
|
|
|
|
/*
|
|
** Disallow 'nested' groups.
|
|
*/
|
|
|
|
if (in_group)
|
|
{
|
|
delete_line ();
|
|
beginning_of_line ();
|
|
error ("Extra 'GROUP' label ignored.");
|
|
}
|
|
else
|
|
{
|
|
group = line;
|
|
in_group++;
|
|
first_in_group = TRUE;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
case ENDGROUP:
|
|
{
|
|
|
|
/*
|
|
** Can't have one of these w/o a preceeding 'Group' label.
|
|
*/
|
|
|
|
if (!in_group)
|
|
{
|
|
delete_line ();
|
|
beginning_of_line ();
|
|
error ("Extra 'ENDGROUP' ignored.");
|
|
}
|
|
else
|
|
{
|
|
//set_buffer (_dialog_radio_buf);
|
|
//insert ("[EndGroup:%s]\n", group);
|
|
group = "";
|
|
in_group--;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
case RADIO:
|
|
{
|
|
int radio_char;
|
|
|
|
/*
|
|
** If we are not in a 'Group' section, toss this line.
|
|
*/
|
|
|
|
if (!in_group)
|
|
{
|
|
delete_line ();
|
|
beginning_of_line ();
|
|
error ("Missing 'GROUP' label -- Radio button ignored.");
|
|
continue;
|
|
}
|
|
|
|
/*
|
|
** For each radio button, store the button's group, label,
|
|
** position, and status in _dialog_radio_buf. By default, the
|
|
** first radio button of each group is set to 'on' and all others
|
|
** in the same group are set to 'off'
|
|
*/
|
|
|
|
set_buffer (_dialog_radio_buf);
|
|
|
|
if (first_in_group)
|
|
{
|
|
radio_char = RADIO_ON;
|
|
first_in_group = FALSE;
|
|
}
|
|
else
|
|
radio_char = RADIO_OFF;
|
|
|
|
insert ("%s\"%s\"(%d,%d)%c\n", group, line, _dialog_row,
|
|
_dialog_col, radio_char);
|
|
|
|
set_buffer (_dialog_data_buf);
|
|
|
|
sprintf (line, RADIO_BTN, radio_char, line);
|
|
}
|
|
|
|
case PUSH:
|
|
{
|
|
/*
|
|
** If this pushbutton is the default, set _dialog_default_pb.
|
|
*/
|
|
|
|
if (search_string ("<[ \t]@P*([ \t0-9]+,[ \t0-9])[ \t]@DEFAULT", group))
|
|
_dialog_default_pb = line;
|
|
|
|
sprintf (line, PUSH_BUTTON, line);
|
|
}
|
|
|
|
case CHECK:
|
|
{
|
|
/*
|
|
** Build Checkbox button and label for insertion;
|
|
*/
|
|
|
|
line = CHECK_BOX + " " + line;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Likewise, if we encounter a field in the data buffer
|
|
** that is too long, we delete it and skip over it
|
|
** in the formatting process.
|
|
*/
|
|
|
|
pos = (_dialog_col + strlen (line)) - _dialog_size;
|
|
|
|
if (!open_paren || pos > 0)
|
|
{
|
|
if (open_paren)
|
|
error ("Field %d columns too wide for window.", pos);
|
|
else
|
|
error ("No current item in list.");
|
|
|
|
delete_line ();
|
|
beginning_of_line ();
|
|
}
|
|
else
|
|
{
|
|
set_buffer (_dialog_disp_buf);
|
|
move_abs (_dialog_row, _dialog_col);
|
|
|
|
/*
|
|
** This makes sure we're not already past end of line
|
|
** if a field is blank to begin with.
|
|
*/
|
|
|
|
if (strlen (line))
|
|
insert (line);
|
|
else
|
|
{
|
|
insert ("\t");
|
|
prev_char ();
|
|
delete_char ();
|
|
}
|
|
|
|
/*
|
|
** If this is not a static-text control, assign a mouse event to
|
|
** the control.
|
|
*/
|
|
|
|
if (_dialog_type != TEXT)
|
|
{
|
|
int width,
|
|
ctrl_width;
|
|
|
|
/* If the control is not a button, set the ctrl_width to the
|
|
** maximum width of the field.
|
|
*/
|
|
|
|
if (_dialog_type != CHECK && _dialog_type != PUSH &&
|
|
_dialog_type != RADIO && _dialog_type != LIST)
|
|
ctrl_width = _dialog_size - _dialog_col - 1;
|
|
else
|
|
ctrl_width = strlen (line);
|
|
|
|
width = ctrl_width;
|
|
|
|
/* set to the mouse buffer */
|
|
|
|
set_buffer(_dialog_mouse_buf);
|
|
|
|
/* Insert the type of control in the buffer. */
|
|
|
|
move_abs(_dialog_row, _dialog_col + (_dialog_type == LIST));
|
|
|
|
if (_dialog_type == LIST)
|
|
ctrl_width -= 3;
|
|
|
|
for ( ;ctrl_width > 0; ctrl_width --)
|
|
insert("%d", _dialog_type);
|
|
|
|
/* get rid of extra chars inserted */
|
|
|
|
delete_char(width);
|
|
}
|
|
|
|
set_buffer (_dialog_data_buf);
|
|
}
|
|
|
|
}
|
|
top_of_buffer ();
|
|
search_fwd (FIND_CONTROL, TRUE, FALSE);
|
|
_dialog_enter ();
|
|
}
|
|
|
|
/*
|
|
** _process_dialog_box:
|
|
**
|
|
** Creates a dialog box window on the screen and a display
|
|
** buffer to go in it. Makes sure an information buffer exists.
|
|
** Calls _format_dialog to prepare the display buffer. Then makes
|
|
** the first field in the dialog box current and highlights it.
|
|
** Enters interactive mode, calling the user's action function
|
|
** whenever "interesting" events occur.
|
|
**
|
|
** When the user exits, this function deletes the display buffer
|
|
** and dialog box window, deletes the data buffer as well if that
|
|
** buffer is a system buffer, pops the keymaps that were created,
|
|
** restores the editing mode and tab/space mode, etc.
|
|
*/
|
|
|
|
int _process_dialog_box (int lx, int by, int rx, int ty, string, string, ~string, ~int, string)
|
|
{
|
|
int old_buf_id,
|
|
created_buffer,
|
|
old_type,
|
|
old_row,
|
|
old_col,
|
|
old_size,
|
|
old_data_buf,
|
|
old_disp_buf,
|
|
old_radio_buf, // *SKY*
|
|
old_mode,
|
|
old_def_pb_state;
|
|
|
|
string pathname,
|
|
old_action_func,
|
|
old_def_pb;
|
|
|
|
/*
|
|
** Save the current value of the global variable _dialog_data_buf.
|
|
*/
|
|
|
|
old_data_buf = _dialog_data_buf;
|
|
|
|
/*
|
|
** If we are passed an existing buffer id, we use that buffer;
|
|
** if not, but we are passed the name of an existing file,
|
|
** we create the buffer. If we get neither parameter, we
|
|
** fail.
|
|
*/
|
|
|
|
if (!get_parm (7, _dialog_data_buf) && get_parm (6, pathname))
|
|
{
|
|
/*
|
|
** If the file name is absolute (which we determine by
|
|
** the presence of special characters) we don't look for
|
|
** it in the BHELP directory.
|
|
*/
|
|
|
|
if (!search_string ("[:/\\\\]", pathname, NULL, TRUE))
|
|
pathname = search_path (_dialog_dir, pathname);
|
|
|
|
/*
|
|
** If the file exists and is not already a buffer in BRIEF, put it
|
|
** in a buffer. Otherwise, use the file's buffer ID.
|
|
*/
|
|
|
|
if (exist (pathname) && !(_dialog_data_buf = inq_buffer (pathname)))
|
|
{
|
|
_dialog_data_buf = create_buffer ("Information", pathname, TRUE);
|
|
created_buffer = TRUE;
|
|
}
|
|
}
|
|
/*
|
|
** Make sure that we have a valid buffer id at this point (we
|
|
** don't care if both the pathname and buffer id were specified;
|
|
** we just want to have something to display).
|
|
*/
|
|
|
|
if (!_dialog_data_buf)
|
|
{
|
|
error ("Can't create dialog box.");
|
|
_dialog_data_buf = old_data_buf;
|
|
return (FALSE);
|
|
}
|
|
message ("Creating dialog box...");
|
|
|
|
/*
|
|
** Here we save the old value of _dialog_action_func
|
|
** and increment the _dialog_level counter so recursive
|
|
** invocations will know about this one. We also save
|
|
** the values of all the other global variables.
|
|
*/
|
|
|
|
_dialog_level++;
|
|
old_action_func = _dialog_action_func;
|
|
old_type = _dialog_type;
|
|
old_row = _dialog_row;
|
|
old_col = _dialog_col;
|
|
old_size = _dialog_size;
|
|
old_disp_buf = _dialog_disp_buf;
|
|
old_radio_buf = _dialog_radio_buf;
|
|
old_mode = _dialog_mode;
|
|
old_def_pb_state = _dialog_pb_state;
|
|
old_def_pb = _dialog_default_pb;
|
|
|
|
_dialog_mode = DIALOG_DBOX_MODE;
|
|
|
|
old_buf_id = inq_buffer ();
|
|
|
|
/*
|
|
** Here we create a non-file system buffer which we
|
|
** can display in the new window. This buffer will be
|
|
** formatted by the information in _dialog_data_buf.
|
|
** At this point, the pathname is no longer needed, so we
|
|
** put the string to new uses (getting the buffer name
|
|
** and later the window-bottom message).
|
|
*/
|
|
|
|
get_parm (4, pathname);
|
|
_dialog_disp_buf = create_buffer (pathname, NULL, TRUE);
|
|
|
|
get_parm (5, pathname);
|
|
get_parm (8, _dialog_action_func);
|
|
_dialog_size = (rx - lx) - 1;
|
|
keyboard_push (_dialog_list_keymap);
|
|
|
|
/*
|
|
** Create a non-file system buffer for managing radio buttons.
|
|
*/
|
|
|
|
_dialog_radio_buf = create_buffer ("RadioButtons", NULL, TRUE); // *SKY*
|
|
|
|
/*
|
|
** Create a non-file system buffer for managing mouse info.
|
|
*/
|
|
|
|
_dialog_mouse_buf = create_buffer ("MouseInfo", NULL, TRUE);
|
|
|
|
/*
|
|
** Now we call _format_dialog to design the display buffer
|
|
** and we create a window to put it in. We postpone
|
|
** refreshing the display.
|
|
*/
|
|
|
|
_format_dialog ();
|
|
set_ctrl_state( ZOOM_BTN, HIDE_CTRL); // hide the zoom button for this window
|
|
set_ctrl_state( HORZ_SCROLL, HIDE_CTRL); // hide the horz scroll bar for this window
|
|
set_ctrl_state( VERT_SCROLL, HIDE_CTRL); // hide the vertical scroll bar for this window
|
|
create_window (lx, by, rx, ty, pathname);
|
|
attach_buffer (_dialog_disp_buf);
|
|
set_ctrl_state( ZOOM_BTN, SHOW_CTRL); // show the zoom button
|
|
set_ctrl_state( HORZ_SCROLL, SHOW_CTRL); // show the horz scroll bar
|
|
set_ctrl_state( VERT_SCROLL, SHOW_CTRL); // show the vertical scroll bar for this window
|
|
|
|
/*
|
|
** We save the old value of Use Tab Characters in the
|
|
** pathname variable, and the old Editing Mode in lx.
|
|
*/
|
|
|
|
lx = inq_mode ();
|
|
pathname = use_tab_char ("n");
|
|
|
|
/* assign a mouse handler for the dialog box */
|
|
set_mouse_action( "mouse_dialog" );
|
|
|
|
/*
|
|
** Call the action function to indicate we are done initializing.
|
|
** This is a good place for you to put your own keys into the
|
|
** keymap; by default, your key assignments will go into the
|
|
** global keymap for both lists and typed fields, but you may
|
|
** select one of the local keymaps and put assignments into it
|
|
** as long as you change back. A typical use of this feature
|
|
** would be to install a help function by assigning it to Alt-h.
|
|
** Don't try to change the basic functioning of either the
|
|
** lists or the fields, however.
|
|
*/
|
|
|
|
message ("Dialog box created.");
|
|
execute_macro (_dialog_action_func, DIALOG_INIT);
|
|
refresh ();
|
|
process ();
|
|
|
|
execute_macro (_dialog_action_func, DIALOG_TERM);
|
|
|
|
/*
|
|
** When we get here (after the user presses one of the three
|
|
** keys F10, Esc, and Grey -) we start cleaning up. First
|
|
** we unassociate any current local keymap and pop the
|
|
** list keymap. We preserve both keymaps for future use.
|
|
*/
|
|
|
|
use_local_keyboard (0);
|
|
|
|
keyboard_pop (TRUE);
|
|
|
|
/*
|
|
** Now we restore some modes.
|
|
*/
|
|
|
|
if (lx != inq_mode ())
|
|
insert_mode ();
|
|
|
|
use_tab_char (pathname);
|
|
|
|
/*
|
|
** After processing the dialog box, we restore the
|
|
** previous state and return TRUE. We only delete the
|
|
** information buffer if we created it and if it is
|
|
** not visible in any windows. We delete the display
|
|
** buffer regardless.
|
|
*/
|
|
|
|
delete_window ();
|
|
set_buffer (_dialog_data_buf);
|
|
|
|
if (created_buffer && !inq_views ())
|
|
delete_buffer (_dialog_data_buf);
|
|
|
|
delete_buffer (_dialog_disp_buf);
|
|
delete_buffer (_dialog_radio_buf); // *SKY*
|
|
|
|
delete_buffer (_dialog_mouse_buf);
|
|
set_buffer (old_buf_id);
|
|
|
|
/*
|
|
** Decrement the dialog level and restore the values of the
|
|
** globals. If the level becomes zero, we're leaving the
|
|
** dialog manager for good, so we re-run the new file
|
|
** macros and clear the message line.
|
|
*/
|
|
|
|
if (!--_dialog_level)
|
|
{
|
|
call_registered_macro (1);
|
|
message ("");
|
|
}
|
|
_dialog_action_func = old_action_func;
|
|
_dialog_type = old_type;
|
|
_dialog_row = old_row;
|
|
_dialog_col = old_col;
|
|
_dialog_size = old_size;
|
|
_dialog_disp_buf = old_disp_buf;
|
|
_dialog_data_buf = old_data_buf;
|
|
_dialog_radio_buf = old_radio_buf; // *SKY*
|
|
_dialog_mode = old_mode;
|
|
_dialog_pb_state = old_def_pb_state;
|
|
_dialog_default_pb = old_def_pb;
|
|
returns (TRUE);
|
|
}
|
|
|
|
/*
|
|
** _dialog_next_and_save:
|
|
**
|
|
** Acts just like _dialog_next, but when invoked on the last field
|
|
** in the dialog manager, simulates a press of F10.
|
|
*/
|
|
|
|
void _dialog_next_and_save ()
|
|
{
|
|
/*
|
|
** If we can leave the current field (the input is valid),
|
|
** we look for another field to enter. If there is none,
|
|
** we pretend F10 was pressed, and we signal to save the screen.
|
|
*/
|
|
|
|
if (_dialog_exit ())
|
|
{
|
|
set_buffer (_dialog_data_buf);
|
|
end_of_line ();
|
|
|
|
/*
|
|
** If we have no other field to go to, we pretend F10 was
|
|
** pressed; if it's OK to exit, we exit one process level.
|
|
** If we can't exit, we reenter the same field. (If we
|
|
** have another field to begin with, we enter it.)
|
|
*/
|
|
|
|
if (!search_fwd (FIND_CONTROL, TRUE, FALSE))
|
|
if (execute_macro (_dialog_action_func, DIALOG_F10))
|
|
{
|
|
_exit ();
|
|
return;
|
|
}
|
|
else
|
|
beginning_of_line ();
|
|
|
|
_dialog_enter ();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** _dialog_next, _dialog_prev, _dialog_home, _dialog_end:
|
|
**
|
|
** These four macros move the highlight to another field and set
|
|
** all the global variables for that field. There is some redundant
|
|
** code, because performance is fairly important.
|
|
*/
|
|
|
|
void _dialog_next ()
|
|
{
|
|
if (_dialog_exit ())
|
|
{
|
|
set_buffer (_dialog_data_buf);
|
|
|
|
/*
|
|
** Find the line on which the desired field is defined.
|
|
*/
|
|
|
|
end_of_line ();
|
|
|
|
if (!search_fwd (FIND_CONTROL, TRUE, FALSE))
|
|
beginning_of_line ();
|
|
|
|
_dialog_enter ();
|
|
}
|
|
}
|
|
|
|
void _dialog_prev ()
|
|
{
|
|
if (_dialog_exit ())
|
|
{
|
|
set_buffer (_dialog_data_buf);
|
|
|
|
if (!(up () && search_back (FIND_CONTROL, TRUE, FALSE)))
|
|
{
|
|
top_of_buffer ();
|
|
search_fwd (FIND_CONTROL, TRUE, FALSE);
|
|
}
|
|
|
|
_dialog_enter ();
|
|
}
|
|
}
|
|
|
|
void _dialog_home ()
|
|
{
|
|
if (_dialog_exit ())
|
|
{
|
|
set_buffer (_dialog_data_buf);
|
|
top_of_buffer ();
|
|
search_fwd (FIND_CONTROL, TRUE, FALSE);
|
|
_dialog_enter ();
|
|
}
|
|
}
|
|
|
|
void _dialog_end ()
|
|
{
|
|
if (_dialog_exit ())
|
|
{
|
|
set_buffer (_dialog_data_buf);
|
|
end_of_buffer ();
|
|
search_back (FIND_CONTROL, TRUE, FALSE);
|
|
_dialog_enter ();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** _dialog_set_globals:
|
|
**
|
|
** This macro sets the global variables _dialog_type, _dialog_row,
|
|
** and _dialog_col by reading information from the data buffer. It
|
|
** returns the line read.
|
|
*/
|
|
|
|
string _dialog_set_globals ()
|
|
{
|
|
string line;
|
|
|
|
/*
|
|
** We require that the row and column numbers follow
|
|
** the first ( and , in the string, respectively,
|
|
** although there may be whitespace in between. The
|
|
** only two double quotes in the string must surround
|
|
** the text of the field.
|
|
*/
|
|
|
|
_dialog_type = index (CONTROL_TYPES, upper (substr (ltrim (line = read ()), 1, 1)));
|
|
_dialog_row = atoi (substr (line, index (line, "(") + 1));
|
|
_dialog_col = atoi (substr (line, index (line, ",") + 1));
|
|
returns (line);
|
|
}
|
|
|
|
/*
|
|
** _dialog_enter:
|
|
**
|
|
** Sets up to enter a list or a field based on the data buffer
|
|
** and global variables.
|
|
*/
|
|
|
|
void _dialog_enter ()
|
|
{
|
|
int offset,
|
|
len;
|
|
string field;
|
|
|
|
_dialog_set_globals ();
|
|
set_buffer (_dialog_disp_buf);
|
|
move_abs (_dialog_row, _dialog_col);
|
|
|
|
if (_dialog_type == PUSH && _dialog_pb_state)
|
|
_dlg_select_push (_dialog_default_pb, 0);
|
|
else if (!_dialog_pb_state && _dialog_type != PUSH)
|
|
_dlg_select_push (_dialog_default_pb, 1); /* show defaul pb if it exists */
|
|
|
|
/*
|
|
** Perform the appropriate initializations and highlighting based on
|
|
** the control type.
|
|
*/
|
|
|
|
switch (_dialog_type)
|
|
{
|
|
case LIST:
|
|
{
|
|
|
|
/*
|
|
** Adjust _dialog_col to compensate for a possible initial tab.
|
|
*/
|
|
|
|
insert_mode (TRUE);
|
|
_dialog_col--;
|
|
prev_char ();
|
|
field = read ();
|
|
len = (index (field, ")") - (offset = index (field, "("))) - 1;
|
|
move_rel (0, offset - 1);
|
|
delete_char ();
|
|
insert ("\t");
|
|
move_rel (0, len);
|
|
delete_char ();
|
|
insert ("\t");
|
|
move_rel (0, -2);
|
|
drop_anchor ();
|
|
move_rel (0, 1 - len);
|
|
execute_macro (_dialog_action_func, DIALOG_ENTER_LIST, _dialog_row, substr (field, ++offset, len));
|
|
}
|
|
|
|
case CHECK:
|
|
case PUSH:
|
|
case RADIO:
|
|
{
|
|
/*
|
|
** Position the cursor in the check box or button.
|
|
*/
|
|
|
|
use_local_keyboard (_dialog_button_keymap);
|
|
|
|
_dialog_col++;
|
|
next_char ();
|
|
|
|
if (_dialog_type == CHECK)
|
|
execute_macro (_dialog_action_func, DIALOG_ENTER_CHECK, _dialog_row, _dlg_check_btn ());
|
|
else if (_dialog_type == PUSH)
|
|
execute_macro (_dialog_action_func, DIALOG_ENTER_PUSH, _dialog_row, _dlg_push_btn ());
|
|
else
|
|
execute_macro (_dialog_action_func, DIALOG_ENTER_RADIO, _dialog_row, _dlg_radio_btn ());
|
|
}
|
|
|
|
default:
|
|
{
|
|
|
|
/*
|
|
** Highlight the field and call the action function.
|
|
*/
|
|
|
|
use_local_keyboard (_dialog_field_keymap);
|
|
|
|
end_of_line ();
|
|
drop_anchor ();
|
|
move_abs (0, _dialog_col);
|
|
execute_macro (_dialog_action_func, DIALOG_ENTER_FIELD, _dialog_row, _field_contents ());
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** _dialog_exit:
|
|
**
|
|
** This routine is called whenever the user is leaving a field or
|
|
** a list. First, if the user is leaving a typed field, it calls the
|
|
** built-in data validation routine for that type. If the data is
|
|
** invalid, it prints an error message and returns FALSE. If the data
|
|
** is valid, it calls the action function with either the list or field
|
|
** parameter and the value of the list or field. If the action function
|
|
** returns TRUE (i.e. the field's contents were still valid), it
|
|
** removes the highlight (if any), and unassociates the current local
|
|
** keymap. Returns what the action function returned.
|
|
*/
|
|
|
|
int _dialog_exit ()
|
|
{
|
|
int retval;
|
|
|
|
switch (_dialog_type)
|
|
{
|
|
case LIST:
|
|
{
|
|
/*
|
|
** Note that in the execute_macro call below, if the action
|
|
** function never gets its last parameter, _list_button
|
|
** never gets called.
|
|
*/
|
|
|
|
if (retval = execute_macro (_dialog_action_func, DIALOG_EXIT_LIST, _dialog_row, _list_button ()))
|
|
{
|
|
/*
|
|
** Change the highlight back to parens.
|
|
*/
|
|
|
|
raise_anchor ();
|
|
prev_char ();
|
|
translate ("\\t{*}\\t", "(\\0)", FALSE, TRUE);
|
|
}
|
|
}
|
|
|
|
case CHECK:
|
|
{
|
|
if (retval = execute_macro (_dialog_action_func, DIALOG_EXIT_CHECK, _dialog_row, _dlg_check_btn ()))
|
|
use_local_keyboard (0);
|
|
}
|
|
|
|
case PUSH:
|
|
{
|
|
if (retval = execute_macro (_dialog_action_func, DIALOG_EXIT_PUSH, _dialog_row, _dlg_push_btn ()))
|
|
use_local_keyboard (0);
|
|
}
|
|
|
|
case RADIO:
|
|
{
|
|
if (retval = execute_macro (_dialog_action_func, DIALOG_EXIT_RADIO, _dialog_row, _dlg_radio_btn ()))
|
|
use_local_keyboard (0);
|
|
}
|
|
|
|
default:
|
|
{
|
|
string value = _field_contents ();
|
|
|
|
if (retval = _dialog_validate (value) && execute_macro (_dialog_action_func, DIALOG_EXIT_FIELD, _dialog_row, value))
|
|
{
|
|
raise_anchor ();
|
|
use_local_keyboard (0);
|
|
|
|
message ("");
|
|
}
|
|
}
|
|
}
|
|
returns (retval);
|
|
}
|
|
|
|
/*
|
|
** _invalid_key:
|
|
**
|
|
** For dialog boxes, if we are in a list, calls _list_go. Otherwise,
|
|
** calls _field_insert. For menus, calls _menu_go. For other cases,
|
|
** does nothing.
|
|
*/
|
|
|
|
replacement void _invalid_key ()
|
|
{
|
|
int key = read_char ();
|
|
|
|
if ((key & 0xff) && (key & 0xff) < 128
|
|
&& _dialog_mode
|
|
&& (_dialog_data_buf == inq_buffer () || _dialog_disp_buf == inq_buffer ()))
|
|
{
|
|
if (_dialog_mode == DIALOG_MENU_MODE)
|
|
_menu_go (key);
|
|
else if (_dialog_type == LIST)
|
|
_list_go (key);
|
|
else if (_dialog_type == CHECK || _dialog_type == PUSH || _dialog_type == RADIO)
|
|
beep ();
|
|
else
|
|
_field_insert (key);
|
|
|
|
refresh ();
|
|
}
|
|
else
|
|
{
|
|
push_back (key);
|
|
_invalid_key ();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** _format_menu:
|
|
**
|
|
** Automatically centers each line of the menu buffer in the
|
|
** window, and moves the rest of the line out of sight. Normally not
|
|
** done, since it's faster if you format your own menus.
|
|
*/
|
|
|
|
void _format_menu ()
|
|
{
|
|
int button_offset,
|
|
button_length;
|
|
|
|
string button,
|
|
text;
|
|
|
|
top_of_buffer ();
|
|
|
|
while (!inq_position ())
|
|
{
|
|
button = _menu_button ();
|
|
button_offset = index (button, ";");
|
|
text = ltrim (substr (button, button_offset + 1));
|
|
button = trim (substr (button, 1, button_offset - 1));
|
|
button_length = strlen (button);
|
|
button_offset = (_dialog_size - button_length) / 2 + 1;
|
|
|
|
delete_to_eol ();
|
|
move_abs (0, button_offset);
|
|
insert (button);
|
|
move_abs (0, _dialog_size + 1);
|
|
insert (";" + text);
|
|
beginning_of_line ();
|
|
down ();
|
|
}
|
|
}
|
|
|
|
/*
|
|
** _process_menu:
|
|
**
|
|
** Creates and processes a menu, calling the user when interesting
|
|
** events occur.
|
|
*/
|
|
|
|
int _process_menu (int lx, int by, int rx, int ty, string, string, ~string, ~int, string, ~int, ~int, ~string)
|
|
{
|
|
int old_buf_id,
|
|
old_data_buf_id,
|
|
old_size,
|
|
old_mode,
|
|
menu_buf_id,
|
|
created_buffer,
|
|
fast_mode,
|
|
screen_x,
|
|
screen_y,
|
|
retval;
|
|
|
|
string pathname,
|
|
old_action_func;
|
|
|
|
|
|
extern void mouse_menu();
|
|
|
|
/*
|
|
** If we are passed an existing buffer id, we use that buffer;
|
|
** if not, but we are passed the name of an existing file,
|
|
** we create the buffer. If we get neither parameter, we
|
|
** fail.
|
|
*/
|
|
|
|
if (!get_parm (7, menu_buf_id) && get_parm (6, pathname))
|
|
{
|
|
/*
|
|
** If the file name is absolute (which we determine by
|
|
** the presence of special characters) we don't look for
|
|
** it in the BHELP directory.
|
|
*/
|
|
|
|
if (!search_string ("[:/\\\\]", pathname, NULL, TRUE))
|
|
pathname = search_path (_dialog_dir, pathname);
|
|
|
|
/*
|
|
** If the file exists already, we put it in a buffer.
|
|
** Note that we use a spare string variable, old_
|
|
** action_func, to get the buffer name parameter.
|
|
*/
|
|
|
|
if (exist (pathname))
|
|
{
|
|
get_parm (4, old_action_func);
|
|
menu_buf_id = create_buffer (old_action_func, pathname, TRUE);
|
|
created_buffer = TRUE;
|
|
}
|
|
}
|
|
/*
|
|
** We have a menu buffer ID if we got one as a parameter or if
|
|
** create_buffer above succeeded. If we have one, we can create
|
|
** the menu. If not, we return immediately so that the
|
|
** ensuing code does not have to be part of the if statement;
|
|
** this saves precious stack space, allowing for more nesting.
|
|
*/
|
|
|
|
if (!menu_buf_id)
|
|
{
|
|
error ("Can't create menu.");
|
|
return (FALSE);
|
|
}
|
|
old_buf_id = inq_buffer ();
|
|
message ("Creating menu...");
|
|
|
|
/*
|
|
** Here we save the old value of _dialog_action_func
|
|
** and increment the _dialog_level counter so recursive
|
|
** invocations will know about this one.
|
|
*/
|
|
|
|
_dialog_level++;
|
|
_dialog_menu_prefix = "";
|
|
old_action_func = _dialog_action_func;
|
|
old_mode = _dialog_mode;
|
|
old_data_buf_id = _dialog_data_buf;
|
|
_dialog_mode = DIALOG_MENU_MODE;
|
|
|
|
/*
|
|
** Now that we've created the menu buffer, we call the
|
|
** menu creation event in case we want to do any raw
|
|
** processing on the menu (like adding our own buttons).
|
|
** For this event, the menu buffer is guaranteed current.
|
|
** We pass the buffer name to the action function, reusing
|
|
** a string variable again.
|
|
*/
|
|
|
|
get_parm (8, _dialog_action_func);
|
|
set_buffer (_dialog_data_buf = menu_buf_id);
|
|
inq_names (NULL, NULL, pathname);
|
|
execute_macro (_dialog_action_func, DIALOG_CREATE_MENU, NULL, pathname);
|
|
|
|
/*
|
|
** We reuse pathname to hold the bottom line message.
|
|
** Note that if lx == rx or by == ty, we have to calculate
|
|
** rx (width) and by (height) automatically.
|
|
*/
|
|
|
|
get_parm (5, pathname);
|
|
|
|
/*
|
|
** If either window dimension is zero, we size the window
|
|
** automatically. It has to be at least 1 line x 14 cols
|
|
** (larger if a long bottom line message is to be displayed).
|
|
*/
|
|
|
|
if (lx == rx || ty == by)
|
|
{
|
|
top_of_buffer ();
|
|
|
|
/*
|
|
** Use the first semicolon, if any, and the number
|
|
** of lines to get the optimum size. (No semicolon:
|
|
** use a 14-column window.)
|
|
*/
|
|
|
|
if (search_fwd (";", FALSE))
|
|
inq_position (NULL, rx);
|
|
else
|
|
rx = 15;
|
|
|
|
rx += lx;
|
|
end_of_buffer ();
|
|
inq_position (by);
|
|
by += ty + 1;
|
|
top_of_buffer ();
|
|
|
|
/*
|
|
** Make sure the window will fit on the screen;
|
|
** if it won't, shrink it. Leave room for the
|
|
** "shadows".
|
|
*/
|
|
|
|
inq_screen_size (screen_y, screen_x);
|
|
screen_y -= 4;
|
|
screen_x -= 3;
|
|
|
|
if (screen_y < by)
|
|
by = screen_y;
|
|
|
|
if (screen_x < rx)
|
|
rx = screen_x;
|
|
}
|
|
/*
|
|
** If either dimension is too small, display an error
|
|
** message and not the window. Note that we duplicate
|
|
** all the "cleanup" code here so we can return
|
|
** immediately. That's because the code size is less
|
|
** crucial than the maximum nesting depth here, since
|
|
** the macro is intended to be called recursively and
|
|
** nesting in macros consumes a ton of stack space.
|
|
*/
|
|
|
|
screen_x = strlen (pathname) + 2;
|
|
screen_y = rx - lx;
|
|
|
|
if ((by - ty <= 1 || screen_y <= 14) || screen_y <= screen_x)
|
|
{
|
|
error ("Window would be too small.");
|
|
|
|
if (created_buffer && !inq_views ())
|
|
delete_buffer (menu_buf_id);
|
|
|
|
set_buffer (old_buf_id);
|
|
|
|
if (!--_dialog_level)
|
|
{
|
|
call_registered_macro (1);
|
|
message ("");
|
|
}
|
|
_dialog_action_func = old_action_func;
|
|
_dialog_mode = old_mode;
|
|
_dialog_data_buf = old_data_buf_id;
|
|
return (FALSE);
|
|
}
|
|
_dialog_picked = 0;
|
|
old_size = _dialog_size;
|
|
_dialog_size = (rx - lx) - 1;
|
|
keyboard_push (_dialog_menu_keymap);
|
|
|
|
/*
|
|
** If we were passed a tenth parameter, and it was TRUE,
|
|
** we change to "fast" mode (meaning the window is already
|
|
** formatted--centered, if desired, and no visible semicolons).
|
|
*/
|
|
|
|
if (!(get_parm (9, fast_mode) && fast_mode))
|
|
_format_menu ();
|
|
|
|
/*
|
|
** Now we display the menu window, but we postpone refreshing
|
|
** the display until we highlight the first button.
|
|
*/
|
|
|
|
set_ctrl_state( ZOOM_BTN, HIDE_CTRL); // hide the zoom button for this window
|
|
set_ctrl_state( HORZ_SCROLL, HIDE_CTRL); // hide the horz scroll bar for this window
|
|
create_window (lx, by, rx, ty, pathname);
|
|
set_ctrl_state( ZOOM_BTN, SHOW_CTRL); // show the zoom button
|
|
set_ctrl_state( HORZ_SCROLL, SHOW_CTRL); // show the horz scroll bar
|
|
attach_buffer (menu_buf_id);
|
|
message ("Menu created.");
|
|
|
|
/*
|
|
** Establish an action routine for menu mouse events.
|
|
** Note: the mouse action routine is set BEFORE the
|
|
** DIALOG_INIT action function is called to allow the default
|
|
** mouse event handler to be sub-classed when processing
|
|
** the DIALOG_INIT message.
|
|
*/
|
|
set_mouse_action( "mouse_menu" );
|
|
|
|
/*
|
|
** Go to the top of the buffer, call the init event,
|
|
** highlight the first selectable line, redraw the screen,
|
|
** and go into interactive mode.
|
|
*/
|
|
|
|
top_of_buffer ();
|
|
execute_macro (_dialog_action_func, DIALOG_INIT);
|
|
_dialog_menu_home ();
|
|
refresh ();
|
|
|
|
process ();
|
|
|
|
/*
|
|
** Remove the highlight, then the keyboard, then the window.
|
|
*/
|
|
|
|
raise_anchor ();
|
|
execute_macro (_dialog_action_func, DIALOG_TERM);
|
|
keyboard_pop (TRUE);
|
|
delete_window ();
|
|
|
|
/*
|
|
** Here we set parameter 10 to indicate the button number picked,
|
|
** set parameter 11 to the text of the picked button, and clear
|
|
** clear _dialog_picked so that nested menus work properly.
|
|
**
|
|
** A zero value for parameter 10 indicates the user pressed <Esc>
|
|
** or <Keypad minus> to abort the menu.
|
|
**
|
|
** A nonzero value indicates the user pressed <Enter> to select
|
|
** a button, and the button number becomes the parameter value.
|
|
** The button text is in parameter 11.
|
|
*/
|
|
|
|
put_parm (10, _dialog_picked);
|
|
put_parm (11, _dialog_picked ? _menu_button () : "");
|
|
_dialog_picked = 0;
|
|
|
|
/*
|
|
** Restore the old current buffer and delete the menu
|
|
** buffer, if we created the buffer ourselves and
|
|
** it's not visible in any window.
|
|
*/
|
|
|
|
if (created_buffer && !inq_views ())
|
|
delete_buffer (menu_buf_id);
|
|
|
|
set_buffer (old_buf_id);
|
|
|
|
/*
|
|
** Decrement the menu level. If it is zero,
|
|
** we're leaving the menu package for good--so re-run the
|
|
** new file macros, and clear the message line.
|
|
*/
|
|
|
|
if (!--_dialog_level)
|
|
{
|
|
call_registered_macro (1);
|
|
message ("");
|
|
}
|
|
_dialog_action_func = old_action_func;
|
|
_dialog_mode = old_mode;
|
|
_dialog_size = old_size;
|
|
_dialog_data_buf = old_data_buf_id;
|
|
returns (TRUE);
|
|
}
|
|
|
|
/*
|
|
** For invalid keys.
|
|
*/
|
|
|
|
void _dlg_beep (void)
|
|
{
|
|
beep ();
|
|
}
|
|
|