Display Classes for Data

1. The Array Display Class

	1a. Preparing to Show an Object

			Attribute:	realize

	1b. Controlling What is Shown

		1b(i). What Rows and Columns are Shown

			Attributes:	cols

		1b(ii). Selected and Referred Rows

			Attributes:	col

	1c. Changing the Value

		1c(i). Editing

			Attributes:	edit

		1c(ii). Insertion and Deletion

			Attributes:	delete

		1c(iii). Representing Missing Values and Characters

			Attributes	blank

		1c(iv). Evaluation

			Attributes:	active

	1d. Appearance

		1d(i). Separators

			Attributes:	colsep

		1d(ii). Size

			Attributes:	dynamic

		1d(iii). Color

			Attributes:	colors

	1e. Documentation

			Attribute:	doc

2. The Label Display Class

3. The View Display Class

	3a. Accessing the Primary Selection Buffer

			Attributes:	clear

4. The Page Display Class

			Attributes:	blink

	4a. User Input

			Attributes:	cursor

5. The Matrix Display Class

			Attributes:	collabelrows

	5a. Selection

			Attributes:	colindex

	5b. Colors

			Attributes:	colindexbg

6. The Slot Display Class


1. The Array Display Class

Any A+ scalar, vector, or matrix can be displayed as an object of class array.
For character arrays, each vector or row of a matrix is put in one cell.  For
all other arrays, each element is put in its own cell.  Examine these six
examples to see how various data types are displayed and check the action of
the scrollbars.  It is a bug, scheduled to be fixed in Version 3, that s has
to be jogged by naturalsize into obeying respace:

     $load s
     scrs.SCREEN-34 12
     br{w;m}:{w has (`yx;scr-m+`yxs of w);}
     ar10 10; `ar has (`class;`array; `respace;1; `show;1); br{`ar;0}
     ar(1 2;3 4 5;6;'abc';`def;7 8;9 10)
     ar6 5'Row 1Row 2Row 3Row 4Row 5Row 6'
     ar'This is a character vector'
     `ar has `naturalsize; br{`ar;0}
     ar2 2("Perhaps";"not";"what's";"wanted")
     `ar has (`space;12;`cols;2); br{`ar;0}
     _ex free `ar

1a. Preparing to Show an Object

	Attribute:	realize

Sometimes, when there are lengthy computations or file accesses, objects may
be placed on the screen in a halting, ragged way unless you take steps to make
the presentation smoother.  Try this contrived example, where sys.sleep is a
stand-in for a meaningful lengthy operation and b and c are specified
initially to speed the start-up:

     ar14 17
     b:{sys.sleep 5;ar}
     c:{sys.sleep 5;ar}
     show `ar is `array; br{`ar;0}
     `b has (`class;`array; `show;1); br{`b;0 250}
     `c has (`class;`array; `show;1); br{`c;0 500}
     hide `ar

Now give ar a "new" value to mark the b and c values invalid.  When they are
shown again the display is set up in a halting, ragged way:

     ar14 17
     show `ar

Now we will hide these objects and respecify ar.  But this time we will use
the "realize" attribute before showing the objects.  Setting realize to 1
causes the objects to be calculated for showing but does not actually show
them.  Thus the delay and unevenness is not displayed on the screen, and when
the show function is executed the objects jump right up:

     hide `ar
     ar14 17
     `ar`b`c has `realize; show `ar;

Get rid of the other objects:

     _ex free `b`c

1b. Controlling What is Shown

There are a number of attributes that control what elements of an array object
are shown.  Some determine the set directly; others single out individual
elements for inclusion somewhere in the set.

1b(i). What Rows and Columns are Shown

	Attributes:	cols

The "rows" and "cols" attributes control how many rows and columns are shown.
The default has been used for ar, but you can change how much is shown:

     >`rows`cols of `ar
     `ar has (`rows`cols;(8;4)); br{`ar;0}

The "firstrow" and "firstcol" attributes are the indices of the first row and
first column that are shown, and thus control what portion of the array
appears on the screen:

     `ar has (`firstrow`firstcol;(6;13))

The bottom right portion of the array is shown.  Now press twice on the up
button of the vertical scrollbar, moving up two rows, and once on the left
band of the horizontal scrollbar, moving left three columns (the four that are
shown minus one for overlap).  The new position is 4, 10:

     `firstrow`firstcol of `ar
     `ar has (`firstrow`firstcol;(13;16))
     >`firstrow`firstcol of `ar

The specification was taken as a suggestion (without comment) and honored as
far as possible while still showing the same number of cells.

The "naturalsize" attribute was introduced in the button section of the
Buttons tutorial.  It is an action attribute; it cannot be queried.  Setting
naturalsize returns the array to the number of rows and columns it had when
mapped, taking into account the current text and data values and feature
attributes, but setting firstrow and firstcol to 0:

     `ar has `naturalsize

Fractional rows may be shown when the viewer changes the size of an object --
try dragging the bottom right corner down and to the right when you have a
target for a pointer -- or when a size is assigned to the object in an A+
statement.  These fractional rows show no data and are of no use.  The "size"
attributes trims them off.  When you have a 200 by 300 pixel space available
and want to use as much as possible of it, but want a good-looking display,
you can use the size attribute.  You should see 6+ rows and 3+ columns and
then an even 6 by 3 when you execute these statements:

     `ar has (`yxs;200 300)
     `ar has `size

You can combine these statements, if you list the attributes in the correct
(left to right) order.  The first line below specifies size too early; the
second is OK:

     `ar has (`naturalsize`size`yxs;(;;200 300))
     `ar has (`naturalsize`yxs`size;(;200 300;)); br{`ar;0}

1b(ii). Selecting and Choosing Rows

	Attributes:	col

A cell can be selected in an array object.  Selecting and choosing are
discussed here because a cell is normally shown when it is selected, and so
they are another way of determining what portion of an array is shown.  The
"row" and "col" attributes contain the row and column indices of the selected
cell.  They are -1 if no cell is selected.  The "selected" attribute,
discussed in the Buttons tutorial, is just the concatenation of the row and
col attributes.  Execute these statements:

     `ar has (`firstrow`firstcol;(6;13))
     >`row`col of `ar
     `ar has (`row`col;(0;0))
     `ar has (`row`col;(0;1))
     `ar has (`row`col;(2;2))
     `ar has (`row`col;(;))
     >`row`col of `ar

Notice that Null is accepted in place of -1.  As you have just seen, a
selected cell is shown raised, and a selected row (except for the selected
cell) is shown in a different color.  Now place the mouse pointer in any cell
of ar and click the left mouse button.  That cell becomes selected.

With the pointer in the array display, the selection can be moved using the
arrow keys, Tab, Shift-Tab, Page Down, Page Up, End, and Home.  Each key is
effective until its limit is reached.  When no cell is selected, Right Arrow,
Down Arrow, Tab, and Home select cell 0 0, Page Down selects the first cell of
the last row shown and makes it the top row shown, and End selects the first
cell of the last row.  Try them.

Whenever a cell is selected, a select event occurs.  The "select" attribute
allows you to specify a function that will be called at each select event, and
optionally to specify an argument for that function.  The default selection
action still occurs.  For example, execute:

     f{s;c;v}:{acv; a has (`firstrow `firstcol;
               ġ(`row `col of a)-s1+`rows`cols of a);}
     `ar has (`select `cols;((f;.5);3))

Now use the mouse and the keyboard to select various cells in ar and see how
the select callback function f causes the selected cell to appear in the
middle of the display -- or, when it is near the edges, to appear as close to
the middle as possible.  Notice that if you scroll the display leaving the
selected cell in view and click on that cell, no select event occurs, as
evidenced by the fact that the cell does not move.  Now execute

     f{s;c;v}:>`row`col of cv
     `ar has (`select;f)
     `ar has (`row`col;(0;0))
     `ar has (`row`col;(2;3))
     `ar has (`row`col;(3;4))
     `ar has (`row`col;(4;4))
     `ar has (`selected;<1 2)
     `ar has (`selected;<1 1)

and notice that:
(1) When selection takes place by an A+ statement, using row and col
attributes, a select event can occur for each of them, in the order shown by
those attributes.

(2) The "selected" attribute is implemented as if the col and row attributes
had been specified, in that order.

(3) No select event occurs when the row or column selected is the same as the
one that was selected or is -1.  The automatic setting to 0 mentioned in the
second paragraph after this one does not trigger a select event, so setting
both attributes from -1 to 0 triggers only one event.

Now use the mouse and the keyboard to select cells and notice that at most one
select event occurs each time.

The row and col attributes are independent, except that (1) if one is set to
-1, the other is automatically set to -1 also and (2) if they are each -1 and
one is set to something else, the other is set to 0:

     `ar has (`firstcol`firstrow`selected;(0;0;))
     `ar has (`col;1)
     `row of `ar
     `ar has (`selected;)
     `ar has (`row;1)
     `col of `ar
     `ar has (`row;)
     `selected of `ar
     `ar has (`select;)

The "refer" attribute allows the viewer to choose a set of rows. When it is
zero, no choosing can take place. When it is nonzero, however, clicking the
left mouse button with the pointer on a cell that is selected but not chosen
causes its row to be chosen, and then clicking on it again causes the row to
be no longer chosen. Since clicking on an unselected cell causes it to be
selected, clicking twice on any unselected cell causes the chosen status of
its row to be toggled.  Pressing Enter while the pointer is in the window and
there is a selected cell has the same effect as clicking on the selected cell.

The default for refer is 0.

     `refer of `ar
     `ar has (`refer;1)
     `index of `ar

The "index" attribute is a sorted list of the indices of the chosen rows.
Choose some rows, using the left button and the Enter key; notice the change
in the color of these rows.  Remove the choice from some of them, again using
both button and key, but leaving several chosen.

     `index of `ar

If there are chosen rows and refer is set to zero, then they are remain chosen
rows and you cannot remove the choice from them:

     `ar has (`refer;0)

Now try pressing Enter with the pointer in the array window or clicking on the
selected cell.  And now remove the choice from all the chosen lines:

     `ar has (`index;)

Like a number of other attributes, refer can have one of three values: 0 for
no choosing; 1 for choosing with the default action; or a function, and,
optionally, an argument, for a callback.  If a callback function is specified,
s does nothing but call that function when a refer event occurs and
appropriately color the rows listed in index after the callback.  It is up to
the callback function to update and sort the index attribute.  Define a
function that mimics the default action and displays its argument and the new
value of index, and set refer to it and a static-data argument:

     f{s;c;v}:{acv; (r;i)`row`index of a;
               a has (`index;i);(s;c;v;i);}
     `ar has (`refer;(f;'stat data'))

Now choose some rows and remove the choice from some of the chosen ones,
leaving others.

     `index of `ar
     `ar has (`refer`index;(0;))

1c. Changing the Value

Aside from reassignment to the underlying variable, there are several ways the
value shown on the screen can be changed.

1c(i). Editing

	Attributes:	edit

The value in an individual cell can be edited.  To prepare for editing, a cell
must be selected, in one of the ways just demonstrated.  There are two modes
and several ways to enter them, one of which involves deletion of the entire
previous contents.  Try them, pressing Escape after each:


   With the pointer in the cell, click the middle mouse button.  The
replacement text cursor will appear on the character the tip of the pointer is
nearest to.


   With the pointer in the cell, click the right mouse button.  The insertion
text cursor will appear between characters, as near as possible to the tip of
the mouse pointer.
   With the pointer in the window, press the Insert key.  The insertion text
cursor will appear at the end of the original contents.
   With the pointer in the window, press Backspace or any character key.  The
entire cell contents will be deleted and the character will appear, unless you
pressed Backspace, followed by the insertion text cursor.

The mode, insertion or replacement, can be toggled by pressing the Insert key
or reset by using the middle or right mouse button.  The cursor can be moved
with the left and right arrow keys or by clicking at a new location in the
cell: the left button leaves the mode unchanged, the middle button forces
replacement mode, and the right button forces insertion mode.  The editor is
Emacs style.

To abort the editing of a cell and return to its original contents, press the
Escape key.  To end the editing of a cell and cause the edited contents to be
inserted in the underlying variable, press Enter or select another cell using
Tab, the up or down arrow keys, etc., or, with the pointer in another cell, a
mouse button.

Since the edited contents of a cell are inserted in the underlying variable
using Selective Specification, you must avoid illicit values, such as 34.5
when the array is integer or 34 5 when the array is simple.  When you press
Enter or try to select another cell with an illicit value in the current cell,
a message appears in the session log and editing of the cell remains open.
Remember, you can escape from an error situation by pressing the Escape key.

Try editing the ar display.

Editing can also be begun and ended from A+ code.  Assigning any nonzero value
to the "edit" attribute is like pressing the Insert key.  (If no cell is
selected, neither of these actions causes edit mode to be entered.)  Assigning
a zero value to the edit attribute is like pressing Enter in edit mode.

     `ar has (`selected `edit;(1 1;))

Now edit the cell, but leave it in input mode.  The edited contents are
accepted (assuming the value is permitted) by this statement:

     `ar has (`edit;0)

You can restrict editing to certain cells, using the "protect" attribute.  A 1
prevents editing in a column and a 0 allows it.  You can give an array
argument that will be used repetitively, in the manner of Reshape, or a
function.  The first statement allows editing of only the first and third
columns; try editing ar after you have executed it:

     `ar has (`protect;0 1 0,141)
     `protect of `ar
     `ar has (`protect;(f;'attempt to edit'))

Now only odd values can be edited; try it.  You will see in the A+ session log
the arguments that are passed to f.

     `ar has (`protect;0)

1c(ii). Insertion and Deletion

	Attributes:	delete

Insertion and deletion can be controlled in a manner like editing and
choosing.  You can allow a viewer to insert or delete rows in an array,
prevent a viewer from doing so, or provide functions to handle insertion or
deletion requests.  These requests are made by selecting a row and pressing a
key combination; the combinations and the corresponding attributes are
Meta-Delete ("delete"), Meta-Insert ("insertbelow"), and Meta-Shift-Insert
("insertabove").  On IBM keyboards, the corresponding key combinations are
Alt-Delete, Alt-Insert, and Alt-Shift-Insert.  The pointer must be in the
window when the keys are pressed.

Setting any of these attributes to 0 causes requests for its action to be
ignored.  Setting it to 1 causes the default action, deletion or insertion, to
be taken upon request.  Setting it to a function, or a function and an
argument, causes that function to be called when the request is made and
causes s to omit the default action.  Consider deletion first.  Try to delete
a row after each of the first two statements:

     `ar has (`delete;1)
     `ar has (`delete;0)
     f{s;c;v}:{if ((c%s)=r`row of cv){(c%s)1;(c%v)(rc%v),(r+1)c%v}
               else (c%s)r;}
     `ar has (`delete;(f;`arr))

Now in order to delete a row you must press Meta-Delete (or, on an IBM
keyboard, Alt-Delete) twice on a selected row.  Try selecting various rows and
pressing once on each and then twice consecutively on the last.

Now consider insertion.  After the second and third statements, try each kind
of insertion at the first line:

     ar14 17; `ar has (`firstrow`firstcol `row`col;(0;0;0;0))
     `ar has (`insertabove`insertbelow;(0;1))
     `ar has (`insertabove`insertbelow;(1;0))
     f{s;c;v}:(c%v)((1+#c%v)s+>`row of cv)\c%v
     `ar has (`insertabove`insertbelow;((f;0);(f;1)))

Now insert a row below and one above the current third line.  The next section
explains the difference between the insertions performed by f and the default

     `ar has (`delete`insertabove`insertbelow;(;;)); br{`ar;0}

1c(iii). Representing Missing Values or Characters

	Attributes	blank

To insert a row, the function f in the last section employed Expand, which
uses zero as the fill character for a numeric array.  Insertion by s, however,
is more flexible than by Expand.  The fill character is the value of the "na"

     `na of `ar

This number is the default for both integer and floating-point arrays.  It is
intended to represent an improbable, if not preposterous, value.  You can set
na to any value you want.  You should generally choose a value that does not
occur in actual data, so that it will always mean missing or unavailable, and
one that will be as simple as possible to handle in your computations.  Just
to see it in action, change na to -1 and go back to the default insertion:

     `ar has (`na;1;`insertabove;1;`insertbelow;1)

Now insert a row below the second one.

You don't have to use a fill character when inserting rows.  A copy of a row
is the most convenient insertion for a viewer when only a few fields need to
be changed in the new row, most fields being the same in both rows.  To insert
a copy of the selected row rather than a row of fill elements, change the
"copy" attribute from its default value of 0 to 1:

     `ar has (`copy;1)

Now insert a row above or below the second row.

You can control how na values appear in displays.  The display for any element
that is equal to the (current) value of na is determined by the "blank"
attribute.  The default value of the blank attribute is Null:

     ()`blank of `ar  br{`ar;0}

meaning show the actual value that is in the array.  The blank attribute can
be set to any character value; watch the display of ar change when you change

     `ar has (`blank;'N/A')
     `ar has (`blank;' ')
     `ar has (`blank;'missing')
     `ar has (`blank;'Fill in')

When you change na, the display of ar will also change, but only when the
displays of the relevant cells must be recalculated, for example by a
specifying of refresh:

     `ar has (`na;0; `refresh;)

You saw stars displayed in the first rows you entered.  You know that the
value of those elements in the underlying variable was -999999999, the then na
value.  What were the stars doing there?

When there is not enough room to display a formatted value in a cell, either
the cell is filled with stars or the value is shown truncated.  The latter
alternative might be preferable for a character string or a number which would
lose only digits following the decimal point.  This choice is governed by the
"stars" attribute:

     `stars of `ar
     `ar has (`blank;; `na;999999999; `space;7);
     `ar has (`stars;0)

Now let's freshen ar up a little:

     `ar has (`stars`blank`naturalsize;(;;))  ar14 17; br{`ar;0}

1c(iv). Evaluation

	Attributes:	active

This section is concerned with conversions between displayed values and the
value of the underlying variable, and the timing of these conversions and
associated computations.

There is an attribute in s that corresponds to the dependency definition
function and command, _def and $def, namely "def".  It is a persistent
attribute, and a variable need never have been bound to have a value for that

     `def of `j

When a dependency is being displayed, the dependency is evaluated and the
display updated whenever the dependency is marked invalid.  If it is not being
displayed, there is no need to evaluate it.  (It is not being displayed if the
show attribute is 0 for it or for some object in which it is contained.)  The
"active" attribute, which is for reference only, tells you whether the object
will be updated automatically or not:

     `active of `ar
     hide `ar
     `active of `ar
     show `ar

The "evaluate" attribute says whether the underlying variable (dependency or
not) is to be evaluated in order to determine the proper attribute values for
displaying it.  If you set evaluate to zero, it is up to you to set the
attributes for a proper display of the variable.  Use it with great caution.
Like def, it is persistent.

     `evaluate of `ar
     `evaluate of `j
     `evaluate of `no_such_variable

The "execute" attribute controls whether or not input will be executed to
obtain a value:

     `execute of `ar

Edit a cell, enter an A+ expression with a singleton result, such as +/10,
and see the result.

     `ar has (`execute;0);

Again edit a cell; enter an A+ expression such as +/10 or 7 and you should
get an error message like "ar: domain - edit value" in the A+ session log.
Try expressions like 7, 1e2, -7, and +7 and you should find that they are
accepted.  (Although the latter two look like functions applied to numbers,
actually the minus sign is converted to high minus and the plus sign is
dropped, so the input is just formatted, not executed.)

The "in" attribute is used to parse values as they are entered on the screen,
which is always as character vectors.  The default is in{x}:x if the type of
the underlying variable is character, and in{x}:x otherwise.  You can specify
a function to be used instead of this default, like one that will accept
commas as thousands separators or one that will accept a comma as a decimal
point.  Try entering some appropriate expressions after each of the following
specifications of in.  _scfi accepts commas as thousands separators and
parentheses as minus; e.g., _scfi"(1,234)" is -1234.  With the arguments given
here, g changes a comma to a period -- e.g., 34,5 to 34.5 -- to convert
decimal points from the European system.

     f{s;d}:_scfi d
     `ar has (`in;f);
     g{s;d}:d  ((d=s[0])/d)s[1]
     `ar has (`in;(g;',.'))  ar1.014 17;

You can specify a character matrix for the in attribute, to encode input.
Then when a character vector is entered, it is padded with trailing blanks as
necessary and then sought as a row of the matrix.  If a match is found, the
row index in the matrix is entered in the variable.  If the vector is not
found there, the value of the na attribute is entered instead:

     `ar has (`in;2 3'no yes');

Now enter "no", "yes", and "maybe" in different cells; 0, 1, and stars (for
-999999999) should be shown for them.

The "out" attribute specifies the format in which data appears in the display.
The defaults are 1x for numeric, x for character, and s.box{x} for other

You can specify a character matrix for the out attribute, just as you can for
the in attribute, so that the variable will contain numbers while words or
phrases appear on the screen:

     `ar has (`out;2 3'no yes');

When the out format is changed, the display is immediately updated.  Notice
the blank cells.  When out is a character matrix, all invalid indices are
treated as na's, and the default blank attribute is the one for character
arrays, namely a vector consisting of a single blank.

     `ar has (`blank;'N/A');
     `ar has (`blank;);
     `ar has (`in;);

You can specify a function for the out attribute -- for example, a conversion
from radians to degrees:

     `ar has (`out;(f;3602));

Other possible values for the out attribute are valid left arguments to dyadic
Format or _sfmt, or one of the formats listed in Table 22-3 of the A+
Reference Manual:

     `ar has (`out;5.1);
     `ar has (`out;'e 7.2');
     `ar has (`out;`minsec);
     `ar has (`out;);

If you are trying to coordinate several things, you may need to perform some
action when the screen entry and refresh cycle has been completed.  The "done"
attribute allows you to specify a callback function for that purpose:

     `done of `ar
     `ar has (`done;(f;'done'));

Edit some cells and observe the session log.  Now clean up and prepare for the
next section:

     `ar has (`done`naturalsize`col`space`cols;(;;;7;3))  ar14 17; br{`ar;0}

1d. Appearance

1d(i). Separators

	Attributes:	colsep

In the display of ar, there are lines separating the rows and the columns.
These lines are controlled by the "colsep" and "rowsep" attributes, whose
default values are 1.  The value 0 means no separators:

     `ar has (`colsep`rowsep;(0;0));
     `ar has (`colsep`rowsep;(2;3));
     `ar has (`colsep`rowsep;(1;1));

1d(ii). Size

	Attributes:	dynamic

The "space" attribute determines the width of the cells:

     `space of `ar
     `ar has (`space;3);
     `ar has (`space;);

The "respace" attribute controls the automatic increasing of the space
attribute.  The space attribute is increased if necessary to accommodate the
formatted values in all cells when either (1) the respace attribute is 1 and
the value of the variable is changed or (2a) respace is reset to 1 or (2b) the
out attribute is respecified.  The respecification of ar after the
illustration of case (2a) is required to fix a known bug in the updating of
the display:

     `ar has (`respace;1;`space;5);
     `ar has (`respace;0);
     `ar has (`space;5);
     `ar has (`respace;1); arar;
     `ar has (`respace;0);
     `ar has (`space;5);
     `ar has (`out;);

Now clean up.

     `ar has (`space;7)  ar[0;0]0; br{`ar;0}

If you change font or text you may want either to keep the display the same
size or to keep the same cells displayed.  The "dynamic" attribute lets you
make this choice.  If it is 1, a font change may cause a change in the size of
the display, whereas if it is 0, the display will remain the same size:

     `dynamic of `ar
     `ar has (`font;'times-24');
     `ar has (`font;'kaplgallant-19');
     `ar has (`dynamic;1);
     `ar has (`font;'times-24'); br{`ar;0}
     `ar has (`font;'kaplgallant-19'); br{`ar;0}

When the "editspace" attribute is 0, the space available for editing a cell is
the cell itself.  When editspace is 1, the space available is determined by
s.EDITSPACE, which has a default value of 256; scrolling in this space is
provided automatically.  After the first of the following statements, enter
enough characters to overflow the cell and then press Escape.  Do the same
after the second statement, but before pressing Escape use the left and right
arrow keys to see the scrolling.

     `ar has (`editspace;0);
     `ar has (`editspace;1);

The width of the scrollbars can be controlled by three attributes;
"vscrollsize" determines the width of the vertical scrollbar and "hscrollsize"
the width (height) of the horizontal.  The "scrollsize" attribute is
vscrollsize, hscrollsize:

     `scrollsize of `ar
     `ar has (`scrollsize;5 6);
     `ar has (`vscrollsize `hscrollsize;(25;28));
     `ar has (`scrollsize;15 17);

1d(iii). Color

	Attributes:	colors

You have already encountered some color controls in the Buttons tutorial.
Here are some more.  For the background of the scrollbars, there are the
"vscrollbg", "hscrollbg", and "scrollbg" (vscrollbg, hscrollbg) attributes.
The Null indicates that the value of an s global variable is to be used, as
discussed later in the S Global Variables tutorial:

     `ar has (`vscrollbg `hscrollbg;(`cyan;`yellow));
     `ar has (`scrollbg;`lightsteelblue);
     `ar has (`scrollbg;);

The backgrounds of the selected cell, the other cells in the selected row, and
the cells in the chosen rows (the rows listed in index) are controlled by the
"selectbg", "rowbg", and "indexbg" attributes, respectively:

     `ar has (`firstrow`firstcol`row`col`index;(0;0;0;0;1 2 3));
     `ar has (`selectbg;`mediumseagreen; `rowbg;`rosybrown; `indexbg;`tan);
     `ar has (`selectbg;`red; `rowbg;`cyan; `indexbg;`bisque);
     `ar has (`row;1);
     `ar has (`selectbg`rowbg`indexbg`index;(;;;));

Notice the combinations of colors when the selected row is one of the chosen

The "editbg" and "editfg" attributes control the colors in the cell that is
being edited:

     `ar has (`editbg`editfg`edit;(`white;`purple;1));
     `ar has (`editbg`editfg;(;));
     `ar has (`edit;0;`row;;`index;);

The "colors" and "cycle" attribute are used to signal a new value.  When an
indexed specification is made to the variable, the new value appears
successively in the colors indicated by the colors attribute.  Each of these
colors is shown for the number of milliseconds required by the cycle
attribute, a scalar.  (Changing a value on the screen by editing causes an
indexed specification.)

The colors attribute can be functional, in which case it is called once for
each changed cell, with the usual arguments: static data, value, index, path,
context, unqualified variable name.  For example, colors could be determined
by the sign of the new value and could be repeated, for a flashing effect, or
they could depend upon the column.

      `ar has (`colors;`red);
     ar[1;0 1]ar[1;0 1]
     `ar has (`colors;`red1 `red2 `red3 `red4);
     ar[1;0 1]ar[1;0 1]
     f{s;d}:{if (d<0) `red `yellow `red `yellow `red `yellow,4`red
            else `cyan `blue `cyan `blue `cyan `blue,4`cyan}
     `ar has (`colors;f);
     ar[1;0 1]ar[1;0],-ar[1;1]
     `cycle of `ar
     `ar has (`cycle;400);
     ar[1;0 1]ar[1;0 1]
     `ar has (`cycle;1000);
     f{s;d;i}:if (2|1i) `red `yellow `cyan `blue else `black
     `ar has (`colors;f);
     ar[1;](1 1,151)ar[1;]

Suppose an attribute uses a function to provide its value and that function
references a global variable.  Then a respecification of the global variable
will not cause a recalculation, although as elements are changed they will
reflect its new value.  If you want the entire array to reflect the new value,
you must force a recalculation, by means of the "refresh" attribute:

     `ar has (`fg;fgfn);
     `ar has `refresh;

This characteristic can be useful.  If ar were being continually updated from
a real-time feed, the first four lines above would initiate the color-coding
of updated numbers.  Whenever a viewer requests it, a new cycle could be begun
by color-coding all numbers as "old" and then setting FG to code updated
numbers as "new" again:

     FG`blue; `ar has `refresh; FG`red;

See the table section of the Containers tutorial for another example of the
use of refresh.

Incidentally, a functional value for fg can be used to color-code cells by
value, as in the first two statements below:

     `ar has (`fg;(fgfn;`red`black`blue));
     ar(1+?14 173)?14 17200
     `ar has (`colors `fg `refresh;(;;))  ar14 17;

1e. Documentation

	Attribute:	doc

This attribute, which has no assigned meaning and no restrictions in s,
provides a way of documenting objects (but not functions):

     `ar has (`doc;("Data tutorial: example";`class of `ar;ar;ar;ar));
     `doc of `ar
     `fgfn has (`doc;"Data tutorial: functional fg; use of refresh shown");
     `doc of `fgfn

The default value for doc is the value of s.AUTODOC, which is discussed in the
s-Context Variables tutorial.

     _ex `FG `prim_buf `clear_fn `f `fgfn `read_fn `j `arr `g;

2. The Label Display Class

The label class is for displaying text that is either a simple character
scalar, vector, or matrix or else a nested scalar or vector whose items are
simple character scalars or vectors.  Labels cannot be edited and never have
titles or scrollbars.  They typically appear inside containers, where they
have no corners or frames, and so blend in.  They can be used to give
information or instructions, label arrays and windows, display character
graphics (dingbats), and so on.

     lb('s tutorial';'data display classes')
     `lb has (`class;`label; `dynamic;1; `head;0);
     show `lb; _ex free `ar; br{`lb;0}

Here are two examples of the use of labels in layouts.  (Layouts are covered
in the Containers tutorial, but you don't really need to know anything about
them here; the details are almost all concealed in the auxiliary variables

     lb'Select Trigger Issue(s)'
     `lb has (`class;`label;`bg;`white);
     `ld_lo has (`class;`layout;`title;'';`shelltitle;'bsprdaddact._ACT');
     show `ld_lo; br{`ld_lo;0}

Incidentally, you probably observed that when ld_lo was bound to the layout
class lb vanished, since it is contained in ld_lo (by the value of ld_lo,
which we have not displayed) and ld_lo was not yet shown.

     free `ld_lo;
     `lb1 has (`class;`label;`font;'zapfdingbats-60';`bg;`gray90;`fg;`green3);
     t1' Average Life  ...'; t2'   . . .'; t3' Price variance  ...';
     lb2(20'FFIEC Tests';30'-';t1;t1;t1;t2;t3;t3;t3;t2)
     `lb2 has (`class;`label;`justify;'l';`bg;`gray90;`fg;`black,9`gray70);
     lo1 2`lb1`lb2
     `lo has (`class;`layout;`shelltitle;'FFIEC';`title;'';`bg;`gray90);
     show `lo; br{`lo;0}

Notice the fg attribute for lb2.  For a label, its value can be a vector,
which is used cyclically, with one element applying to each row.

     _ex `t1 `t2 `t3 `lb `lb1 `lb2, >free `lo;

3. The View Display Class

The view class is for simple character matrices that need scrollbars and so
are unsuitable for labels.  Only fixed-width, or monospace, fonts should be
used for horizontal scrolling.  View displays have problems with matrices
containing tabs, backspaces, linefeeds, etc.; these problems will not be fixed
soon, so avoid ASCII control-type characters in any array to be bound to the
view class.  Views cannot be edited.  Here is an example of an output area
with initial filler:

     v20 61'CMOPort '
     `v is `view;
     `v has (`shelltitle;'cmoPortfolioMgr'; `title;'Output area');
     show `v; `v has (`xs;766); br{`v;0}

     _ex free `v;

3a. Accessing the Primary Selection Buffer

	Attributes:	clear

Text clipped from an Emacs or XTerm window is written in the "primary
selection buffer", and text pasted in these windows is retrieved from this
buffer.  You can use this buffer from A+.

To write to the primary selection buffer, you give the "primary" attribute a
character value. (Other types of data are quietly ignored; the value of
primary remains unchanged.) Since there is only the one buffer, the value of
the attribute changes for all objects.

To read the buffer, you specify the "request" attribute for a bound object.
If primary has been given a proper value, a "notify" event occurs and the
buffer can be read by referencing the primary attribute.

If the buffer is overwritten by another process (not by an object in this A+
process), the A+ object, if any, whose specification of the primary
attribute was overwritten will undergo a clear event. Dragging the pointer
over text in an Emacs, Xterm, or FrameMaker window, for example, will cause
a clear event. The text that is highlighted can then be retrieved through
primary, but text that Emacs demarcated by bouncing the cursor back and
forth cannot -- but can, however, after you press the "copy 0 to PRIMARY"
button in an xcutsel window.

Adapting an example from Larry Rohrs, we first define a set of functions to
set primary and request and respond to notify and clear:

       s .has (`primary;(`row .of s)#%s);
       'Copy pressed; set `primary'}
       s .has `request;
       'Paste pressed; set `request'}
       row0`row .of cv;
       if (1=row) 'Nowhere to paste'
         (row#c%v)(1c%v)0`primary .of cv;
         '`notify event; got `primary'}}
     Clear{s}:'`clear event for ',s

Now define a function to set up a layout with a view and two buttons and to
set callbacks:

       sym .is `view;
       sym .has (`notify;GetPrimary);
       sym .has (`clear;(Clear;sym));
       (sym`CopyBtn)  .is `button  (sym%`CopyBtn) (SetPrimary;sym);
       (sym`PasteBtn) .is `button  (sym%`PasteBtn)(SetRequest;sym);
       (sym`Layout)   .is `layout;
       show sym`Layout;}

Specify two variables and have Define set them up and display them:

     Define `sample1  sample15 5
     Define `sample2  sample2105 5
     br{`sample2.Layout;0}; br{`sample1.Layout;0,10+>`xs of `sample2.Layout};

Click on a line in sample1 and press its Copy button.  Then click on a line
in sample2 and press its Paste button.  Click on another line in sample2,
press its Paste button, and see the same text entered on that line.  Select
some text in an Xterm or an Emacs session and notice that a clear event took
place for sample1.  Press either Paste button; if the selected text is
highlighted, it is put in the selected row; otherwise, request is set but
there is no notify event.  Try some other experiments with these objects and
see the results on the screen and in the A+ session log.

     _ex free `sample1.Layout `sample2.Layout;
     _ex `SetPrimary`SetRequest`GetPrimary`Clear`Define;

4. The Page Display Class

	Attributes:	blink

Character matrices can be bound to the page display class, which is designed
for displaying page-based information from data services.  There are no
scrollbars, and the firstrow, firstcol, rows, and cols attributes do not apply
to page objects.

First, here is a small sample page with the default display:

     show `ld_pg is `page; br{`ld_pg;0}

The "underline" attribute takes a boolean mask showing which characters are to
be underscored.  It is functional.  For page, a nonfunctional setting of any
functional attribute is treated as if it were reshaped to the shape of the
underlying character matrix.  A functional setting should always be a value
with the same shape as the underlying character matrix.

First, we define a function to produce a mask from a set of row index, column
index, extent triplets (the static data).  By making it mask out blanks, we
can underline the title by underlining the whole first row, so that no change
is needed in the attribute when we change the title:

             (,u)[((u)[1]0#s)+(1#s)+ɡ2#s]1; u^(c%v)' '}
     `ld_pg has (`underline;(msk;,<0 0 58));
     ld_pg[0;]58'     Mergers and Acquisitions'

The "line" attribute allows vertical and horizontal lines to be drawn.  The
vertical lines can be used, among other things, as column dividers, with or
without a box around them.  The line attribute takes an n by 4 integer matrix.
Each row contains index of first row, index of first column, number of rows,
number of columns.  For a horizontal line the third of these is zero and for a
vertical line the fourth is zero.  Settings are not cumulative; they erase
previous settings.  The commas here are of course not necessary; they just
make the expression easier to read:

     `ld_pg has (`line;4 4 6 20 0 18,12 17 2 0,12 29 2 0,12 41 2 0);

The "colormap" attribute takes a two-column matrix of color symbols.  Each row
represents a foreground, background pair.

The "color" attribute, which is functional, allows you to color each character
on the page individually.  It can be a matrix of indices into the colormap

The foreground and background colors are never set directly.  If color has not
been set, then the first pair of colors in colormap are used throughout the

     `colormap of `ld_pg
     `ld_pg has (`colormap;2 2`blue`white `brown`green);
     `ld_pg has (`colormap;2 2`black`gray `red`white; `color;(msk;,<3 0 6));

The "blink" attribute also takes a mask and is functional.  The "blinkrate"
attribute is a scalar integer that tells in milliseconds the rate at which the
designated characters are to blink:

     `ld_pg has (`blink;(msk;,<3 0 6));
     `blinkrate of `ld_pg
     `ld_pg has (`blinkrate;750);

Another attribute that is functional and uses a mask is "bold"; it governs
which characters appear in boldface:

     `ld_pg has (`bold;(msk;(3 7 7;3 38 14;8 4 14;9 4 17)));

Finally, you can draw a set of boxes on the page display using the "box"
attribute, whose value is an n by 4 matrix with rows containing row index,
column index, row extent, column extent.  You can choose the colors for these
boxes by means of the "boxcolor" attribute.  Its value is a vector; if there
are fewer elements in boxcolor than there are boxes, the colors of the excess
boxes remain unchanged.  Thus the second and third statements below are

     `ld_pg has (`box;2 4 8 0 3 58, 12 4 2 50);
     `ld_pg has (`boxcolor;<,`green);
     `ld_pg has (`boxcolor;<`green`black);

4a. User Input

	Attributes:	cursor

Page objects cannot be edited directly.  No cursor is shown for them, but
there is a "cursor" attribute, which is set to the row and column of the
pointer on the page when any mouse button is pressed.  Press various buttons
with the pointer at various locations on the page; after each button press,
press F2 with the cursor on the following statement, and see the values in the
A+ session log:

     `cursor of `ld_pg

You can simulate a cursor by means of the blink attribute.  It is up to you to
move this "cursor" based on the key press and mouse button events.  You can
use the "key" attribute to set a callback on key presses.

The "keysym" attribute is for reference only.  Its value is of the form (k;s),
where k is the ASCII code of the last character pressed, and s is a boolean
vector of eight integers indicating which modifier keys were pressed when the
key press event occurred.  The modifiers are:

  Shift, Caps Lock, Control, mod1, mod2, mod3, mod4, mod5

where mod1 is Meta, mod2 is NumLock and mod4 is Alt.

Set the key attribute, then press various key combinations (with the pointer
in the page window) and see the value of keysym in the A+ session log:

     f{}:`keysym of `ld_pg
     `ld_pg has (`key;f);

There are four attributes with callback for mouse-button presses: "3down",
"3up", "2down", and "2up".  Set the callbacks and then press and release the
middle and right mouse buttons (again, with the pointer on the page) and see
the callbacks recorded in the A+ session log:

     `ld_pg has (`2up`2down`3up`3down;((m;`2up);(m;`2dn);(m;`3up);(m;`3dn)));

You can draw a rubber-band box by placing the pointer anywhere in the page,
pressing and holding the left mouse button, moving the pointer anywhere in the
page that you want (even not moving it), and releasing the button.  A box is
shown continuously during this process, starting at the upper lefthand corner
of the character space on which you pressed the button.  When you release the
button, the row and column indices of the upper lefthand corner of the box and
the row and column extents are placed in the "rbandbox" attribute, displacing
any box specification that might have been there.  If you release it anywhere
in the same character row or column, the extent will be zero.  Try drawing
several boxes, pressing the F2 key on the following statement after each:

     `rbandbox of `ld_pg

What else happens depends when a box is drawn depends upon the "rband"
attribute, which has a default value, 0, and a default callback, specified by
the Null.  Execute the next two statements.  Then draw some more boxes, some
of them with zero area, executing the third statement after each box is drawn:

     `rband of `ld_pg
     `ld_pg has (`rband;);
     `rbandbox `box of `ld_pg

Notice that each box specification is placed in rbandbox and that the ones
that have non-zero extents in both directions are also appended to the box
attribute, reflecting the fact that these boxes remain on the page.  You can
define your own callback function for rband.  If you do so, the latest box
specification is still placed in rbandbox, but box is not automatically
changed (so the box does not remain automatically on the screen when the mouse
button is released).  As you have probably observed, there is a strong
similarity in this regard between the rband/box behavior and the refer/index

Let's define a callback function for rband to color the delineated area
differently.  First get rid of all but the original boxes, add a color pair to
colormap, and change the value of color from a function and its static data to
a boolean mask:

     `ld_pg has (`box;2`box of `ld_pg);
     `ld_pg has (`colormap;(`colormap of `ld_pg),`blue`lightgrey);
     `ld_pg has (`color;msk{<3 0 6;;;;`;`ld_pg});

Execute these statements to specify a callback function for rband:

     rb{}:{(b1;b2;b3;b4)`rbandbox of `ld_pg;(i1;i2)ɡld_pg;
           m((i1b1)^i18)/g)`; g8 8g;
     'abcdefgh '[`a`b`c`d`e`f`g`h` g]
     `sl has (`geometry;g);
     show `sl; br{`sl;0, 10+>`xs of `s}

Now clean up:

     _ex ld_names,`f`g`mreal`rlbl`clbl,s.reset{}; _ex `ld_names;