ncurses
–The Programming InterfaceThis chapter describes some aspects of the internals of the browse table handling. The relevant objects are action functions that implement the individual navigation steps (see Section 5.1), modes that describe the sets of available navigation steps in given situations (see Section 5.2), and browse applications that are given by the combination of several modes (see Section 5.3). Most of the related data is stored in the global variable BrowseData (5.4-1). For more details, one should look directly at the code in the file lib/browse.gi of the Browse package.
Navigating in a browse table means that after entering visual mode by calling NCurses.BrowseGeneric (4.3-1), the user hits one or several keys, or uses a mouse button, and if this input is in a given set of admissible inputs then a corresponding function is executed with argument the browse table (plus additional information in the case of mouse events). The function call then may change components in this table (recommended: components in its dynamic component), such that the appearance in the window may be different afterwards, and also the admissible inputs and their effects may have changed.
The relation between the admissible inputs and the corresponding functions is application dependent. However, it is recommended to associate the same input to the same function in different situations; for example, the ? key and the F1 key should belong to a function that shows a help window (see Section 5.4-4), the q key and the Esc key should belong to a function that exits the current mode (Note that the Esc key may be recognized as input only after a delay of about a second.), the Q key should belong to a function that exits the browse application (see Section 5.4-6), the F2 key should belong to a function that saves the current window contents in a global variable (see Section 5.4-5), and the E key should belong to a function that enters a break loop (see Section 5.4-7). The Enter and Return keys should belong to a click
on a selected table entry, and if a category row is selected then they should expand/collapse this category. The M key should toggle enabling and disabling mouse events. Mouse events on a cell or on a category row of a browse table should move the selected entry to this position; it is recommended that no functionality is lost if no mouse events are used, although the number of steps might be reduced when the mouse is used.
Each such function is wrapped into a record with the components action (the function itself) and helplines (a list of attribute lines that describes what the function does). The help lines are used by the help feature of NCurses.BrowseGeneric, see Section 5.4-4.
The action functions need not return anything. Whenever the shown screen shall be recomputed after the function call, the component dynamic.changed of the browse table must be set to true by the action functions.
After entering the first characters of an admissible input that consists of more characters, the last line of the window with the browse table shows these characters behind the prefix partial input:
. One can delete the last entered character of a partial input via the Delete and Backspace keys. It is not possible to make these keys part of an admissible input. When a partial input is given, only those user inputs have an effect that extend the partial input to (a prefix of) an admissible input. For example, asking for help by hitting the ? key will in general not work if a partial input had been entered before.
In different situations, different inputs may be admissible for the same browse table, and different functions may belong to the same input. For example, the meaning of moving down
can be different depending on whether a cell is selected or not.
The set of admissible user inputs and corresponding functions for a particular situation is collected in a mode of the browse table. (There should be no danger to mix up this notion of mode with the visual mode
introduced in Section 1.1.) A mode is represented by a record with the components name (a string used to associate the mode with the components of header, headerLength, footer, footerLength, Click, and for the help screen), flag (a string that describes properties of the mode but that can be equal for different modes), actions (a list of records describing the navigation steps that are admissible in the mode, see Section 5.1), and ShowTables (the function used to eventually print the current window contents, the default is BrowseData.ShowTables). Due to the requirement that each admissible user input uniquely determines a corresponding function, no admissible user input can be a prefix of another admissible input, for the same mode.
Navigation steps (see Section 5.1) can change the current mode or keep the mode. It is recommended that each mode has an action to leave this mode; also an action to leave the browse table application is advisable.
In a browse table, all available modes are stored in the component work.availableModes, whose value is a list of mode records. The value of the component dynamic.activeModes is a list of mode records that is used as a stack: The current mode is the last entry in this list, changing the current mode is achieved by unbinding the last entry (so one returns to the mode from which the current mode had been entered by adding it to the list), by adding a new mode record (so one can later return to the current mode), or by replacing the last entry by another mode record. As soon as the dynamic.activeModes list becomes empty, the browse table application is left. (In this situation, if the browse table had been entered from the GAP prompt then visual mode is left, and one returns to the GAP prompt.)
The following modes are predefined by the Browse package. Each of these modes admits the user inputs ?, F1, q, Esc, Q, F2, E, and M that have been mentioned in Section 5.1.
This mode admits scrolling of the browse table by a cell or by a screen, searching for a string, selecting a row, a column, or an entry, and expanding or collapsing all category rows.
This mode is entered by calling BrowseData.ShowHelpTable; it shows a help window concerning the actions available in the mode from which the help mode was entered. The help mode admits scrolling in the help table by a cell or by a screen. See Section 5.4-4 for details.
In this mode, one table cell is regarded as selected; this cell is highlighted using the attribute in the component work.startSelect as a prefix of each attribute line, see the remark in Section 2.2-3. The mode admits moving the selection by one cell in the four directions, searching for a string and for further occurrences of this string, expanding or collapsing the current category row or all category rows, and executing the click
function of this mode, provided that the component work.Click.( "select_entry" ) of the browse table is bound.
This is like the select_entry mode, except that a whole row of the browse table is highlighted. Searching is restricted to the selected row, and click
refers to the function work.Click.( "select_row" ).
This is a combination of the select_entry mode and the select_row mode.
This is like the select_row mode, just a column is selected not a row.
This is like the select_row_and_entry mode, just a column is selected not a row.
The data in a browse table together with the set of its available modes and the stack of active modes forms a browse application. So the part of or all functionality of the Browse package can be available (standard application
), or additional functionality can be provided by extending available modes or adding new modes.
When NCurses.BrowseGeneric (4.3-1) has been called with the browse table t, say, the following loop is executed.
If the list t.dynamic.activeModes is empty then exit the browse table, and if the component t.dynamic.Return is bound then return its value. Otherwise proceed with step 2.
If t.dynamic.changed is true then call the ShowTables function of the current mode; this causes a redraw of the window that shows the browse table. Then go to step 3.
Get one character of user input. If then the current user input string is the name of an action of the current mode then call the corresponding action function and go to step 1; if the current user input string is just a prefix of the name of some actions of the current mode then go to step 3; if the current user input string is not a prefix of any name of an action of the current mode then discard the last read character and go to step 3.
When one designs a new application, it may be not obvious whether some functionality shall be implemented via one mode or via several modes. As a rule of thumb, introducing a new mode is recommended when one needs a new set of admissible actions in a given situation, and also if one wants to allow the user to perform some actions and then to return to the previous status.
‣ BrowseData | ( global variable ) |
This is the record that contains the global data used by the function NCurses.BrowseGeneric (4.3-1). The components are actions, defaults, and several capitalized names for which the values are functions.
BrowseData.actions is a record containing the action records that are provided by the package, see Section 5.1. These actions are used in standard applications of NCurses.BrowseGeneric (4.3-1). Of course there is no problem with using actions that are not stored in BrowseData.actions.
BrowseData.defaults is a record that contains the defaults for the browse table used as the first argument of NCurses.BrowseGeneric (4.3-1). Important components have been described above, see BrowseData.IsBrowseTable (4.2-3), in the sense that these components provide default values of work components in browse tables. Here is a list of further interesting components.
The following components are provided in BrowseData.defaults.work.
windowParametersis a list of four nonnegative integers, denoting the arguments of NCurses.newwin for the window in which the browse table shall be shown. The default is [ 0, 0, 0, 0 ], i. e., the window for the browse table is the full screen.
minyxis a list of length two, the entries must be either nonnegative integers, denoting the minimal number of rows and columns that are required by the browse table, or unary functions that return these values when they are applied to the browse table; this is interesting for applications that do not support scrolling, or for applications that may have large row or column labels tables. The default is a list with two functions, the return value of the first function is the sum of the heights of the table header, the column labels table, the first table row, and the table footer, and the return value of the second function is the sum of widths of the row labels table and the width of the first column. (If the header/footer is given by a function then this part of the table is ignored in the minyx default.) Note that the conditions are checked only when NCurses.BrowseGeneric (4.3-1) is called, not after later changes of the screen size in a running browse table application.
alignis a substring of "bclt", which describes the alignment of the browse table in the window. The meaning and the default are the same as for BrowseData.IsBrowseTableCellData (4.2-1). (Of course this is relevant only if the table is smaller than the window.)
headerLengthdescribes the lengths of the headers in the modes for which header functions are provided. The value is a record whose component names are names of modes and the corresponding components are nonnegative integers. This component is ignored if the header component is unbound or bound to a list, missing values are computed by calls to the corresponding header function as soon as they are needed.
footerLengthcorresponds to footer in the same way as headerLength to header.
Mainif bound to a function then this function can be used to compute missing values for the component main; this way one can avoid computing/storing all main values at the same time. The access to the entries of the main matrix is defined as follows: If mainFormatted[i][j] is bound then take it, if main[i][j] is bound then take it and compute the formatted version, if Main is a function then call it with arguments the browse table, i, and j, and compute the formatted version, otherwise compute the formatted version of work.emptyCell. (For the condition whether entries in mainFormatted can be bound, see below in the description of the component cacheEntries.)
cacheEntriesdescribes whether formatted values of the entries in the matrices given by the components corner, labelsCol, labelsRow, main, and of the corresponding row and column separators shall be stored in the components cornerFormatted, labelsColFormatted, labelsRowFormatted, and mainFormatted. The value must be a Boolean, the default is false; it should be set to true only if the tables are reasonably small.
cornerFormattedis a list of lists of formatted entries corresponding to the corner component. Each entry is either an attribute line or a list of attribute lines (with the same number of displayed characters), the values can be computed from the input format with BrowseData.FormattedEntry. The entries are stored in this component only if the component cacheEntries has the value true. The default is an empty list.
labelsColFormattedcorresponds to labelsCol in the same way as cornerFormatted to corner.
labelsRowFormattedcorresponds to labelsRow in the same way as cornerFormatted to corner.
mainFormattedcorresponds to main in the same way as cornerFormatted to corner.
m0is the maximal number of rows in the column labels table. If this value is not bound then it is computed from the components corner and labelsCol.
n0is the maximal number of columns in corner and labelsRow.
mis the maximal number of rows in labelsRow and main. This value must be set in advance if the values of main are computed using a Main function, and if the number of rows in main is larger than that in labelsRow.
nis the maximal number of columns in labelsCol and main. This value must be set in advance if the values of main are computed using a Main function, and if the number of columns in main is larger than that in labelsCol.
heightLabelsColis a list of 2 m0+ 1 nonnegative integers, the entry at position i is the maximal height of the entries in the i-th row of cornerFormatted and labelsColFormatted. Values that are not bound are computed on demand from the table entries, with the function BrowseData.HeightLabelsCol. (So if one knows the needed heights in advance, it is advisable to set the values, in order to avoid that formatted table entries are computed just for computing their size.) The default is an empty list.
widthLabelsRowis the corresponding list of 2 n0+ 1 maximal widths of entries in cornerFormatted and labelsRowFormatted.
heightRowis the corresponding list of 2 m+ 1 maximal heights of entries in labelsRowFormatted and mainFormatted.
widthColis the corresponding list of 2 n+ 1 maximal widths of entries in labelsColFormatted and mainFormatted.
emptyCellis a table cell data object to be used as the default for unbound positions in the four matrices. The default is the empty list.
sepCategoriesis an attribute line to be used repeatedly as a separator below expanded category rows. The default is the string