Files
TeslaRel410/sda4/BRIEF/MACROS/BUFFERS.CB
T
CydandClaude Fable 5 db7745fcd0 sda4: commit the Glaze developer hard-drive dump
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>
2026-07-04 19:41:15 -05:00

991 lines
22 KiB
Plaintext

/*
** BRIEF -- Basic Reconfigurable Interactive Editing Facility
**
** Written by Dave Nanian and Michael Strickman.
*/
#include "dialog.h"
#include "win_ctrl.h"
/*
** buffers.cb:
**
** This file contains all of the standard BRIEF macros for buffer
** manipulation.
*/
/*
** buf_list:
**
** This macro provides the user with a list of buffers that can be
** manipulated and scrolled through. It is of interest because it
** simulates an array of buffer ids using a system buffer. Macro
** programmers interested in using arrays should examine this code
** carefully before implementing an array system of their own.
*/
#define SYSTEM 1 // The value to use for system buffers.
#define NEW_FILE 1 // The value to use for new file attachments.
#define NUM_ENTRIES_DISPLAYED 6 // The number of non-expert entries displayed
void display_file_name ();
int _buf_write ();
string _bookmark_menu ();
void mouse_buf_list();
void _buf_position( int );
void buf_list (~int)
{
global int _buf_list, // Buffer that contains visible list.
_buf_array, // Buffer that simulates an array.
_end_buf, // The buffer to be attached on exit.
_expert; // Are we in expert mode?
int num_bufs, // The number of buffers in the list.
start_buf, // The buffer we started on.
curr_buf, // The buffer we're on (in the loop).
modified; // Is the current buffer modified?
string file_name, // The file name of the buffer.
buffer_name; // The buffer name.
if (get_parm (0, _expert))
_expert = !!_expert;
else
_expert = 0;
/*
** First, we create the array and list buffers, making sure that they
** have the "system" attributes. We use non-file buffers because this is
** temporary information.
**
** The "_buf_list" buffer contains a textual list of all of the non
** system buffers currently in memory. "_buf_array" contains a list of the
** corresponding buffer pointers. Note that the buffer pointers are not
** inserted into the buffer as is -- they are converted to string integers
** first. This prevents inserting bad characters like tab, return and EOF.
*/
message ("Creating buffer list...");
/* First, we get the ID of the current buffer -- we have to
** restore it at the end of the macro. After that, we create the
** array buffer and put it aside for the moment. Note that the
** array buffer is a non-file buffer -- this prevents disk accesses
** since the file is held completely in memory.
*/
start_buf = _end_buf = inq_buffer ();
/* Make sure we start off with a non-system buffer
*/
if (inq_system(start_buf))
start_buf = _end_buf = next_buffer ();
if (inq_system(start_buf))
{
error ("No buffers found.");
}
_buf_array = create_buffer ("Buffer Array", NULL, SYSTEM);
/* Now, we create the buffer that the user will actually see on
** the screen, set it to be the current buffer, and set the tabs to
** the values we want (tabs default to every column).
*/
set_buffer (_buf_list = create_buffer ("Buffer List", NULL, SYSTEM));
tabs (5);
/* This loop creates both buffer lists: the non-system buffers
** are looped through and information about them are culled and added
** to the list.
*/
while (start_buf != curr_buf)
{
if (!curr_buf)
curr_buf = start_buf;
else
{
set_buffer (_buf_list);
insert ("\n");
set_buffer (_buf_array);
insert ("\n");
}
++num_bufs;
message ("Creating buffer list [#%d]...", num_bufs);
set_buffer (curr_buf);
inq_names (file_name, NULL, buffer_name);
modified = inq_modified ();
set_buffer (_buf_list);
if (!_expert)
insert ("%d)\tBuffer \"%s\" has %sbeen modified.\n\tFile: ", num_bufs, buffer_name, modified ? "" : "not ");
else
insert ("%d)\t", num_bufs);
insert (file_name + (modified ? "*" : ""));
set_buffer (_buf_array);
insert ("%d", curr_buf);
set_buffer (curr_buf);
curr_buf = next_buffer ();
}
message ("List created.");
/*
** At this point, the array buffer and list buffer have been created
** and filled in. We create a window to display the list in, initialize
** the marked area, set up a keymap, and call process. Process handles
** the mainline loop -- we need only provide action routines.
*/
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 (5, 4+NUM_ENTRIES_DISPLAYED*2+1, 74, 4,
" or  to select, E to edit, D to delete, W to write, ESC to exit.");
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 (_buf_list);
keyboard_push ();
assign_to_key ("<Down>", "_buf_down");
assign_to_key ("<Up>", "_buf_up");
assign_to_key ("<PgUp>", "_buf_pgup");
assign_to_key ("<PgDn>", "_buf_pgdn");
assign_to_key ("<Home>", "_buf_home");
assign_to_key ("<End>", "_buf_end");
assign_to_key ("<Ctrl-PgUp>", "_buf_home");
assign_to_key ("<Ctrl-PgDn>", "_buf_end");
assign_to_key ("d", "_buf_delete");
assign_to_key ("D", "_buf_delete");
assign_to_key ("<Ctrl-minus>", "_buf_delete");
assign_to_key ("e", "_buf_edit");
assign_to_key ("E", "_buf_edit");
assign_to_key ("<Alt-e>", "_buf_edit");
assign_to_key ("W", "_buf_write");
assign_to_key ("w", "_buf_write");
assign_to_key ("<Alt-w>", "_buf_write");
assign_to_key ("<Enter>", "_buf_edit");
assign_to_key ("<Esc>", "exit");
/*
** specify the function to handle mouse events and save the
** previous mouse handler to allow for sub-classing of events
*/
set_mouse_action( "mouse_buf_list" );
move_abs (2 - _expert, 100);
drop_anchor (3);
move_abs (1, 1);
set_buffer (_buf_array);
move_abs (1, 1);
set_buffer (_buf_list);
refresh ();
process ();
/* Now that we're back from the processing, we pop the keymap that
** we created, raise the assorted anchors, and delete the temporary
** window and the buffers.
*/
keyboard_pop ();
raise_anchor ();
delete_window ();
delete_buffer (_buf_list);
delete_buffer (_buf_array);
/* If we end with a different buffer than we started with, we
** attach it to the current window and display its file name.
** Otherwise, we set the current buffer back, and call NEW_FILE
** to make sure its defaults are reset.
*/
set_buffer (_end_buf);
inq_names (file_name);
edit_file (file_name);
}
/*
** _buf_down:
**
** This routine is called whenever the user presses a down arrow.
** It moves the array buffer and list buffer's current lines, ensuring
** the user does not go past the end of the buffer.
*/
int _buf_down ()
{
int line;
inq_position (line);
if (!_expert && line % 2 == 0)
{
swap_anchor();
refresh();
}
move_rel (3 - _expert * 2, 0);
if (inq_position ())
{
move_rel (-3 + _expert * 2, 0);
return (0);
}
else
{
raise_anchor ();
drop_anchor (3);
move_rel (-1 + _expert, 0);
set_buffer (_buf_array);
down ();
set_buffer (_buf_list);
returns (1);
}
}
/*
** _buf_up:
**
** This macro is called whenever the user presses the up arrow. It
** moves up in the list and array buffers, not going past the top of the
** buffer.
*/
int _buf_up ()
{
int line;
inq_position (line);
if (!_expert && line % 2 == 0)
{
swap_anchor();
refresh();
}
if (!up ())
return (0);
else
{
raise_anchor ();
drop_anchor (3);
move_rel (-1 + _expert, 0);
set_buffer (_buf_array);
move_rel (-1, 0);
set_buffer (_buf_list);
returns (1);
}
}
/*
** _buf_pgup:
**
** This macro is called whenever the user presses PgUp. It moves up
** one screen in the list and array buffers, not going past the top of the
** buffer.
*/
void _buf_pgup ()
{
int num_lines = NUM_ENTRIES_DISPLAYED * (_expert + 1);
while (num_lines--)
_buf_up ();
}
void _buf_home ()
{
while (_buf_up ());
}
/*
** _buf_pgdn:
**
** This macro is called whenever the user presses PgDn. It moves
** down one page/screen in the buffer list and the array.
*/
void _buf_pgdn ()
{
int num_lines = NUM_ENTRIES_DISPLAYED * (_expert + 1);
while (num_lines--)
_buf_down ();
}
void _buf_end ()
{
while (_buf_down ());
}
/*
** _buf_delete:
**
** This routine is called when the user wants to delete a buffer.
** It makes sure the buffer is not in a window, and prompts the user
** if the buffer has been modified.
*/
void _buf_delete ()
{
int buf_to_delete;
string misc_str = "y";
set_buffer (_buf_array);
buf_to_delete = atoi (read ());
set_buffer (buf_to_delete);
if (!inq_views ())
{
if (inq_modified ())
{
keyboard_flush ();
if (!get_parm (NULL, misc_str, "This buffer has not been saved. Delete [ynw]? ", 1))
misc_str = "n";
}
if (index ("yY", misc_str) || index ("wW", misc_str) && _buf_write () > 0)
{
int line;
set_buffer (_buf_list);
inq_position (line);
if (!_expert && line % 2 == 0)
{
swap_anchor();
refresh();
}
delete_line ();
if (!_expert)
delete_line ();
set_buffer (_buf_array);
delete_line ();
delete_buffer (buf_to_delete);
set_buffer (_buf_list);
if (inq_position ())
_buf_up ();
else
{
raise_anchor ();
move_rel (1 - _expert, 0);
drop_anchor (3);
move_rel (-1 + _expert, 0);
}
}
else if (!index ("wW", misc_str))
message ("Buffer not deleted.");
}
else
error ("You can't delete a viewed buffer.");
set_buffer (_buf_list);
}
/* _buf_edit:
**
** This routine is called when the user is on a buffer that he wants
** to edit. It sets the global "_end_buf" variable to the current
** line's buffer, and calls exit so no further processing takes place.
*/
void _buf_edit ()
{
set_buffer (_buf_array);
_end_buf = atoi (read ());
set_buffer (_buf_list);
exit ();
}
/*
** _buf_write:
**
** This routine is called when the user wants to write a modified
** buffer. It makes sure the buffer is modified -- if so, it's written
** and the information in the window is updated.
*/
int _buf_write ()
{
int old_msg_level,
ret_code;
set_buffer (_buf_array);
set_buffer (atoi (read ()));
if (inq_modified ())
{
old_msg_level = inq_msg_level ();
set_msg_level (0);
if ((ret_code = write_buffer ()) > 0)
{
set_msg_level (old_msg_level);
set_buffer (_buf_list);
if (!_expert)
{
search_fwd ("has \\c");
insert ("not ");
down ();
}
end_of_line ();
backspace ();
move_rel (-1 + _expert, -100);
}
else
set_msg_level (old_msg_level);
}
else
error ("Buffer not modified.");
set_buffer (_buf_list);
returns (ret_code);
}
/*
** edit_file:
**
** This macro replaces the built-in edit_file function: it displays
** the file name of the edited file if the edit operation was successful.
*/
replacement int edit_file (~string)
{
int ret_code,
old_msg_level;
old_msg_level = inq_msg_level ();
if (inq_called () == "")
set_msg_level (0);
ret_code = edit_file ();
set_msg_level (old_msg_level);
if (ret_code == 1)
display_file_name ();
returns (ret_code);
}
/*
** _multifile_edit_file:
**
** This macro is called by the file completion functions when more then
** one file is selected from the completion menu.
*/
void _multifile_edit_file (int completion_buf_id, string path)
{
int old_buf_id = set_buffer (completion_buf_id);
string file_name;
top_of_buffer ();
while (!inq_position () && (file_name = trim (ltrim (read ()))) != "")
{
edit_file (path + file_name);
set_buffer (completion_buf_id);
down ();
}
set_buffer (old_buf_id);
}
/*
** edit_next_buffer:
**
** Edits the next buffer in the buffer list in the current window. If
** there are no other buffers, an error message is displayed.
*/
void edit_next_buffer ()
{
string file_name;
int new_buffer = next_buffer ();
if (new_buffer != inq_buffer ())
{
set_buffer (new_buffer);
inq_names (file_name);
edit_file (file_name);
}
else
error ("No other buffers.");
}
/*
** edit_prev_buffer:
**
** Edits the previous buffer in the buffer list.
*/
void edit_prev_buffer ()
{
string file_name;
int old_buffer = inq_buffer ();
while (next_buffer () != old_buffer)
set_buffer (next_buffer ());
if (inq_buffer () != old_buffer)
{
inq_names (file_name);
edit_file (file_name);
}
else
error ("No other buffers.");
}
/*
** delete_curr_buffer:
**
** This function deletes the current buffer, if it is unmodified,
** there is another buffer in the list to replace it, and it is only
** visible in one window.
**
** If the buffer is modified, the user is asked if he really wants to
** delete the buffer. If he answers yes, the deletion is performed.
**
** If there are no other buffers, or the buffer is in an overlapping
** window and any other window, the deletion is not performed.
*/
int delete_curr_buffer ()
{
int old_buf_id = inq_buffer (),
new_buf_id = next_buffer (),
window_buf_id,
orig_window_id,
curr_window_id;
string reply,
file_name;
if (old_buf_id == new_buf_id)
{
error ("Can't delete: no other buffers.");
return (0);
}
orig_window_id = inq_window ();
if (inq_window_info () == 1)
{
curr_window_id = next_window ();
while (orig_window_id != curr_window_id)
{
inq_window_info (curr_window_id, window_buf_id);
if (window_buf_id == old_buf_id)
{
error ("Can't delete: buffer's windows overlap.");
return (0);
}
curr_window_id = next_window (curr_window_id);
}
}
if (inq_modified ())
{
keyboard_flush ();
if (!get_parm (NULL, reply, "This buffer has not been saved. Delete [ynw]? ", 1))
return (0);
else if (!strlen (reply) || !index ("yYwW", reply))
{
message ("Buffer not deleted.");
return (0);
}
if (index ("wW", reply))
{
int old_msg_level = inq_msg_level (),
ret_code;
set_msg_level (0);
ret_code = write_buffer ();
set_msg_level (old_msg_level);
if (ret_code <= 0)
return (0);
}
}
set_buffer (new_buf_id);
inq_names (file_name, NULL);
set_buffer (old_buf_id);
edit_file (file_name);
if (inq_views (old_buf_id) != 0)
{
curr_window_id = next_window ();
while (orig_window_id != curr_window_id)
{
inq_window_info (curr_window_id, window_buf_id);
if (old_buf_id == window_buf_id)
{
set_window (curr_window_id);
edit_file (file_name);
}
curr_window_id = next_window (curr_window_id);
}
if (inq_window () != orig_window_id)
set_window (orig_window_id);
}
delete_buffer (old_buf_id);
returns (1);
}
/*
** _bad_key:
**
** This routine adds menus to some prompts.
*/
replacement _bad_key ()
{
int key_pressed = read_char ();
if (inq_command () == "goto_bookmark" && key_pressed == key_to_int ("<Tab>"))
return (_bookmark_menu ());
push_back (key_pressed);
return (_bad_key ());
}
/*
** _bookmark_menu:
**
** This routine actually handles the "invalid keystroke" event
** when in the bookmark prompt.
*/
string _bookmark_menu ()
{
global int _bookmark;
int menu_buf,
old_buf,
curr_buf,
line,
col,
i,
num_bookmarks;
string bookmark,
file_name;
while (i < 10)
{
if (goto_bookmark (i, curr_buf, line, col))
++num_bookmarks;
++i;
}
if (num_bookmarks == 0)
beep ();
else
{
int num_lines,
num_cols,
lx,
by,
rx,
ty;
old_buf = inq_buffer ();
sprintf (bookmark, "%d bookmark%s", num_bookmarks, num_bookmarks == 1 ? "" : "s");
set_buffer (menu_buf = create_buffer (bookmark, NULL, SYSTEM));
num_bookmarks = 0;
i = 1;
tabs (2, 13, 19, 25, 80);
while (i <= 10)
{
if (goto_bookmark (i, curr_buf, line, col))
{
if (++num_bookmarks == 1)
insert ("\n\tBookmark\tLine\tCol\tFile\n\t--------\t----\t---\t----");
insert ("\n");
set_buffer (curr_buf);
inq_names (file_name);
set_buffer (menu_buf);
insert ("\t%d\t%d\t%d\t%s\t;%d", i, line, col, file_name, i);
}
++i;
}
set_buffer (old_buf);
_bookmark = -1;
inq_screen_size (num_lines, num_cols);
num_lines /= 2;
num_cols /= 2;
lx = num_cols - 36;
rx = num_cols + 36;
ty = num_lines - (4 + (num_bookmarks + 4) / 2);
by = ty + (num_bookmarks + 5);
_process_menu (lx, by, rx, ty, NULL, " or  to move, <Enter> to select, <Esc> to exit", NULL, menu_buf, "_bookmark_action", TRUE);
if (_bookmark >= 0)
{
sprintf (bookmark, "%d", _bookmark);
push_back (key_to_int ("<Enter>"));
return (bookmark);
}
}
returns (inq_cmd_line ());
}
/*
** _bookmark_action:
**
** This is the action routine for the dialog manager.
*/
int _bookmark_action (int event_type, ~string)
{
string button_text;
switch (event_type)
{
case DIALOG_MOVE_MENU:
{
get_parm (2, button_text);
if (index (button_text, ";"))
returns (TRUE);
else
returns (FALSE);
}
case DIALOG_PICK_MENU:
case DIALOG_F10:
{
get_parm (2, button_text);
_bookmark = atoi (substr (button_text, rindex (button_text, ";") + 1));
_dialog_esc ();
returns (TRUE);
}
}
}
/*
** mouse_buf_list
**
** Handle all the mouse events of interest for the buffer list
**
** Mouse assignments:
** btn1 down, up, click - position to an entry in the list
** btn1 dblclk - edit the file
** btn2 click - write the file
** btn2 click + ctrl - delete the file
** btn1 click outside the list - close the list
** btn1 click on close button - close the list
*/
void mouse_buf_list (int event, // the event code
int modifier, // modifier keys
int parm2, // line or scroll bar code
int parm3 ) // column or thumb position
{
/* handle the events of interest */
switch ( event ){
case BTN2_CLICK: // delete / write the file
case BTN1_DOWN: // position to a file
case BTN1_UP: // position to a file
case BTN1_MOVE: // position to a file
case BTN1_CLICK: // position to a file
case BTN1_DBLCLK:{ // edit the file
int lines;
save_position(); // get number of lines in buffer
end_of_buffer();
inq_position( lines );
restore_position();
if ( 0 < parm2 && parm2 <= lines ) {
/* if two lines per entry and an even line clicked on
switch to corresponding odd line */
if ( !_expert && !(parm2%2) ) parm2--;
_buf_position( parm2 ); // goto selected position
switch ( event ){
case BTN1_DBLCLK: // edit the file
_buf_edit();
case BTN2_CLICK:
switch ( modifier ){
case 0: // write the file
_buf_write();
case KB_CTRL: // delete the file
_buf_delete();
}
}
}
}
case SET_WIN: // click outside list closes it
if ( parm2 != inq_window() ) exit();
case CLOSE_WIN:
exit(); // close the buffer list
case VSCROLL: // vertical scroll bar event
switch ( parm2 ){
case SB_BOTTOM: // end of the list
_buf_end();
case SB_TOP: // beginning of the list
_buf_home();
case SB_PAGEDOWN: // page down request
_buf_pgdn();
case SB_PAGEUP: // page up request
_buf_pgup();
case SB_LINEDOWN: // line down request
_buf_down();
case SB_LINEUP: // line up request
_buf_up();
case SB_THUMBTRACK:{ // scroll while tracking the thumb
int new_line;
save_position();
/* Move the thumb to the desired position. We do this
** to find out what the target line is.
*/
set_ctrl_state(VERT_THUMB, parm3);
/* Get the target line
*/
inq_position(new_line);
restore_position();
/* Now let _buf_position really move to the new
** selection. This is done so that the buffer containing
** buffer info is updated correctly.
*/
_buf_position( new_line ); // goto the entry
}
}
}
}
/*
** _buf_position
**
** Position to an entry in the list and highlite the entry.
**
*/
void _buf_position(int new_line) // target line to goto
{
int curr_line,
top_left,
line,
moved_up = 0,
extra;
/* If we're not in expert mode, we may need to position the cursor
** on the second line of an entry to get the thumb to position
** correctly.
*/
if (!_expert && new_line % 2 == 0)
extra = 1;
else
extra = 0;
inq_position( line ); // get current position
/* If we are currently on the second line of an entry,
** reposition by swapping the anchor.
*/
if (!_expert && line % 2 == 0)
{
swap_anchor();
inq_position( line ); // get current position
}
/* target line is below current line */
if ( line < new_line )
{
while ( inq_position(line) == 0 && line < new_line)
{
if (extra && line + 1 == new_line)
{
swap_anchor();
move_abs(0, 1);
break;
}
if (!_buf_down())
break;
}
}
/* target line is above current line */
else if ( line > new_line )
{
moved_up = 1;
while (line + extra > new_line)
{
_buf_up();
inq_position( line );
if (extra && (line + 1 == new_line))
{
swap_anchor();
break;
}
}
}
refresh();
/* Now make sure an entry is not split by the window.
*/
inq_position(curr_line);
inq_top_left(top_left);
if (top_left % 2 == 0)
{
if (moved_up)
set_top_left(top_left - 1, 1);
else
set_top_left(top_left + 1, 1);
}
}