15 Extended Stream Output
CLIM provides a stream-oriented output layer that is implemented on top of the
sheet output architecture. The basic CLIM output stream protocol is based on
the character output stream protocol proposal submitted to the ANSI Common Lisp
committee by David Gray. This proposal was not approved by the committee, but
has been implemented by most Lisp vendors.
15.1 Basic Output Streams
CLIM provides an implementation of the basic output stream facilities (described
in more detail in Appendix Common Lisp Streams ), either by directly using the
underlying Lisp implementation, or by implementing the facilities itself.
| standard-output-stream | [Class] |
This class provides an implementation of the CLIM basic output stream protocol,
based on the CLIM output kernel.
Members of this class are mutable. | stream-write-char | stream character | [Generic function] |
Writes the character character to the output stream stream ,
and returns character as its value.
| stream-write-string | stream string &optional (start 0 ) end | [Generic function] |
Writes the string string to the output stream stream . If
start and end are supplied, they are integers that specify what part
of string to output. string is returned as the value.
| stream-terpri | stream | [Generic function] |
Writes an end of line character on the output stream stream , and
returns false .
| stream-fresh-line | stream | [Generic function] |
Writes an end of line character on the output stream stream only if
the stream is not at the beginning of the line.
| stream-finish-output | stream | [Generic function] |
Ensures that all the output sent to the output stream stream has
reached its destination, and only then return false .
| stream-force-output | stream | [Generic function] |
Like stream-finish-output , except that it may immediately return
false without waiting for the output to complete.
| stream-clear-output | stream | [Generic function] |
Aborts any outstanding output operation in progress on the output stream stream , and returns false .
| stream-line-column | stream | [Generic function] |
This function returns the column number where the next character will be written
on the output stream stream . The first column on a line is
numbered 0.
| stream-start-line-p | stream | [Generic function] |
Returns true if the output stream stream is positioned at
the beginning of a line (that is, column 0), otherwise returns false .
| stream-advance-to-column | stream column | [Generic function] |
Writes enough blank space on the output stream stream so that the
next character will be written at the position specified by column , which
is an integer.
15.2 Extended Output Streams
In addition to the basic output stream protocol, CLIM defines an extended output
stream protocol. This protocol extends the stream model to maintain the state
of a text cursor, margins, text styles, inter-line spacing, and so forth.
| extended-output-stream | [Protocol Class] |
The protocol class for CLIM extended output streams. This is a subclass of
output-stream .
If you want to create a new class that behaves like an extended output stream, it should be a subclass of extended-output-stream. Subclasses of extended-output-stream must obey the extended output stream protocol.| extended-output-stream-p | object | [Predicate] |
Returns true if object is a CLIM extended output stream ,
otherwise returns false .
| :vertical-spacing | [Init arg] |
| :end-of-line-action | [Init arg] |
| :end-of-page-action | [Init arg] |
All subclasses of extended-output-stream must handle these initargs, which
are used to specify, respectively, the medium foreground and background, default
text style, vertical spacing, default text margin, end of line and end of page
actions, and the default view for the stream.
:foreground , :background , and :text-style are handled via the
usual pane initialize options (see Section Pane Initialization Options ).
| standard-extended-output-stream | [Class] |
This class provides an implementation of the CLIM extended output stream
protocol, based on the CLIM output kernel.
Members of this class are mutable. 15.3 The Text Cursor
In the days when display devices displayed only two dimensional arrays of fixed
width characters, the text cursor was a simple thing. A discrete position was
selected in integer character units, and a character could go there and noplace
else. Even for variable width fonts, simply addressing a character by the pixel
position of one of its corners is sufficient. However, variable height fonts
with variable baselines on pixel-addressable displays upset this simple model.
The ``logical'' vertical reference point is the baseline, as it is in
typesetting. In typesetting, however, an entire line of text is created with
baselines aligned and padded to the maximum ascent and descent, then the entire
line is put below the previous line.
It is clearly desirable to have the characters on a line aligned with their
baselines, but when the line on the display is formed piece by piece, it is
impossible to pick in advance the proper baseline. The solution CLIM adopts is
to choose a baseline, but not commit to it.
The CLIM model says that text has at least 6 properties. With a reference point
of (0,0) at the upper left of the text, it has a bounding box consisting of
ascent, descent, left kerning, right extension, and a displacement to the next
reference point in both x and y. CLIM determines the position of the
reference point and draws the text relative to that, and then the cursor
position is adjusted by the displacement. In this way, text has width and
height, but the x and y displacements need not equal the width and height.
CLIM adopts the following approach to the actual rendering of a glyph. Textual
output using the stream functions (not the graphics functions) maintains
text on a ``line''. Note that a line is not an output record, but is rather a
collection of ``text so far'', a top (which is positioned at the bottom of the
previous line plus the stream's vertical spacing), a baseline, a bottom, and a
``cursor position''. The cursor position is defined to be at the top of the
line, not at the baseline. The reason for this is that the baseline can move,
but the top is relative to the previous line, which has been completed and
therefore doesn't move. If text is drawn on the current line whose ascent is
greater than the current ascent of the line, then the line is moved down to make
room. This can be done easily using the output records for the existing text on
the line. When there is enough room, the reference point for the text is the
x position of the cursor at the baseline, and the cursor position is adjusted
by the displacement.
The following figures show this in action before and after each of three
characters are drawn. In all three figure, the small circle is the ``cursor
position''. At first, there is nothing on the line. The first character
establishes the initial baseline, and is then drawn. The upper left corner of
the character is where the cursor was (as in the traditional model), but this
will not remain the case. Drawing the second character, which is larger than
the first, requires moving the first character down in order to get the
baselines to align; during this time, the top of the line remains the same.
Again, the upper left of the second character is where the cursor was, but that
is no longer the case for the first character (which has moved down). The third
character is smaller than the second, so no moving of characters needs to be
done. However, the character is drawn to align the baselines, which in this
case means the upper left is not where the cursor was. Nor is the cursor
at the upper right of the character as it was for the previous two characters.
It is, however, at the upper right of the collective line.
(w1+w2,y)\
\
(w1,y)\ (w1,y)\ \
\ \ \
(0,y)\ (0,y)\ \ (0,y)\ \ \
\ \ \ \ \ \
---- ------------ ----------------------
| | | |
| | --------| |
| | | | |
| | | | |
| | | | |
| small | | | |
| | | | |
| | | small | BIG |
| | | | |
---------- | | |
| | | | |
--------- --------------------
/ | | |
--------| |
/ | |
bl-small/ -----------
bl-BIG/
(w1+w2+w3,y)\
\
(w1+w2,y)\ \
\ \
(w1,y)\ \ \
\ \ \
(0,y)\ \ \ \
\ \ \ \
------------------------------
| |
--------| ---------
| | | |
| | | |
| | | |
| | | |
| | | |
| small | BIG | small |
| | | |
| | | |
| | | |
----------------------------
| | | |
--------| ---------
/ | |
-----------
bl-BIG/
Issue: DCPL
The above may be too simplistic. The displacement probably
wants to depend not only on language but language rendering mode. For example,
Japanese can apparently go either vertically or horizontally. It may be
necessary to have the bounding box and perhaps the reference point dispatch as
well. Similarly, ``newline'' could mean ``down one line, all the way to the
left'' for English, ``down one line, all the way to the right'' for Arabic, or
``to the left one line, all the way to the top.'' ``Home cursor'' is another
ditty to consider. We need to discuss this on a larger scale with people who
know multi-lingual rendering issues.
15.3.1 Text Cursor Protocol
Many streams that maintain a text cursor display some visible indication of the
text cursor. The object that represents this display is (somewhat confusingly)
also called a cursor.
An active cursor is one that is being actively maintained by its
owning sheet. A active cursor has a state that is either on or off.
An active cursor can also has a state that indicates the the owning sheet has
the input focus.
The protocol class that corresponds to cursors.
If you want to create a new class that behaves like a cursor, it should be a subclass of cursor. Subclasses of cursor must obey the cursor protocol.Members of this class are mutable. Returns true if object is a cursor , otherwise returns
false .
The :sheet initarg is used to specify the sheet with which the cursor is
associated.
| standard-text-cursor | [Class] |
The instantiable class that implements a text cursor. Typically, ports will
further specialize this class.
| cursor-sheet | cursor | [Generic function] |
Returns the sheet with which the cursor cursor is associated.
| cursor-position | cursor | [Generic function] |
Returns the x and y position of the cursor cursor as two
values. x and y are in the coordinate system of the cursor's sheet.
| (setf* cursor-position) | x y cursor | [Generic function] |
Sets the x and y position of the cursor cursor to the specified
position. x and y are in the coordinate system of the cursor's sheet.
For CLIM implementations that do not support setf* , the ``setter'' function
for this is cursor-set-position .
| cursor-active | cursor | [Generic function] |
| (setf cursor-active) | value cursor | [Generic function] |
Returns (or sets) the ``active'' attribute of the cursor. When true , the
cursor is active.
| cursor-state | cursor | [Generic function] |
| (setf cursor-state) | value cursor | [Generic function] |
Returns (or sets) the ``state'' attribute of the cursor. When true , the
cursor is visible. When false , the cursor is not visible.
| cursor-focus | cursor | [Generic function] |
Returns the ``focus'' attribute of the cursor. When true , the sheet
owning the cursor has the input focus.
| cursor-visibility | cursor | [Generic function] |
| (setf cursor-visibility) | visibility cursor | [Generic function] |
These are convenience functions that combine the functionality of
cursor-active and cursor-state . The visibility can be either :on (meaning that the cursor is active and visible at its current position),
:off (meaning that the cursor is active, but not visible at its current
position), or nil (meaning that the cursor is not activate).
15.3.2 Stream Text Cursor Protocol
The following generic functions comprise the stream text cursor protocol. Any
extended output stream class must implement methods for these generic functions.
| stream-text-cursor | stream | [Generic function] |
| (setf stream-text-cursor) | cursor stream | [Generic function] |
Returns (or sets) the text cursor object for the stream stream .
| stream-cursor-position | stream | [Generic function] |
Returns the current text cursor position for the extended output stream stream as two integer values, the x and y positions.
| (setf* stream-cursor-position) | x y stream | [Generic function] |
Sets the text cursor position of the extended output stream stream to x and y . x and y are in device units, and must be
integers.
For CLIM implementations that do not support setf* , the ``setter'' function
for this is stream-set-cursor-position .
| stream-increment-cursor-position | stream dx dy | [Generic function] |
Moves the text cursor position of the extended output stream stream relatively, adding dx to the x coordinate and dy to the y
coordinate. Either of dx or dy may be nil , meaning the the x
or y cursor position will be unaffected. Otherwise, dx and dy must be integers.
15.4 Text Protocol
The following generic functions comprise the text protocol. Any extended output
stream class must implement methods for these generic functions.
| stream-character-width | stream character &key text-style | [Generic function] |
Returns a rational number corresponding to the amount of horizontal motion of
the cursor position that would occur if the character character were
output to the extended output stream stream in the text
style text-style (which defaults to the current text style for the
stream). This ignores the stream's text margin.
| stream-string-width | stream character &key start end text-style | [Generic function] |
Computes how the cursor position would move horizontally if the string
string were output to the extended output stream stream in
the text style text-style (which defaults to the current text style
for the stream) starting at the left margin. This ignores the stream's text
margin.
The first returned value is the x coordinate that the cursor position would
move to. The second returned value is the maximum x coordinate the cursor
would visit during the output. (This is the same as the first value unless the
string contains a #\Newline character.)
start and end are integers, and default to 0 and the length of the
string, respectively.
| stream-text-margin | stream | [Generic function] |
| (setf stream-text-margin) | margin stream | [Generic function] |
The x coordinate at which text wraps around on the extended output
stream stream (see stream-end-of-line-action ). The default setting
is the width of the viewport, which is the right-hand edge of the viewport when
it is horizontally scrolled to the ``initial position''.
You can use setf with stream-text-margin to establish a new text
margin. If margin is nil , then the width of the viewport will be
used. If the width of the viewport is later changed, the text margin will
change, too.
| stream-line-height | stream &key text-style | [Generic function] |
Returns what the line height of a line on the extended output stream stream containing text in the text style text-style would be,
as a rational number. The height of the line is measured from the baseline of
the text style to its ascent. text-style defaults to the current text
style for the stream.
| stream-vertical-spacing | stream | [Generic function] |
Returns the current inter-line spacing (as a rational number) for the
extended output stream stream .
| stream-baseline | stream | [Generic function] |
Returns the current text baseline (as a rational number) for the extended
output stream stream .
15.4.1 Mixing Text and Graphics
The following macro provides a convenient way to mix text and graphics on the
same output stream.
| with-room-for-graphics | (&optional stream
&key (first-quadrant t ) height (move-cursor t )
record-type)
&body body | [Macro] |
Binds the dynamic environment to establish a local coordinate system for doing
graphics output onto the extended output stream designated by
stream . If first-quadrant is true (the default), a local
Cartesian coordinate system is established with the origin (0,0) of the local
coordinate system placed at the current cursor position; (0,0) is in the lower
left corner of the area created. If the boolean move-cursor is
true (the default), then after the graphic output is completed, the
cursor is positioned past (immediately below) this origin. The bottom of the
vertical block allocated is at this location (that is, just below point (0,0),
not necessarily at the bottom of the output done).
The stream argument is not evaluated, and must be a symbol that is bound
to a stream. If stream is t (the default), *standard-output* is
used. body may have zero or more declarations as its first forms.
If height is supplied, it must be a rational number that specifies the
amount of vertical space to allocate for the output, in device units. If it is
not supplied, the height is computed from the output.
record-type specifies the class of output record to create to hold the
graphical output. The default is standard-sequence-output-record .
15.4.2 Wrapping of Text Lines
| stream-end-of-line-action | stream | [Generic function] |
| (setf stream-end-of-line-action) | action stream | [Generic function] |
The end-of-line action controls what happens if the text cursor position moves
horizontally out of the viewport, or if text output reaches the text margin.
(By default the text margin is the width of the viewport, so these are usually
the same thing.)
stream-end-of-line-action returns the end-of-line action for the
extended output stream stream . It can be changed by using
setf on stream-end-of-line-action .
The end-of-line action is one of:
- :wrap ---when doing text output, wrap the text around (that is, break
the text line and start another line). When setting the cursor position, scroll
the window horizontally to keep the cursor position inside the viewport. This
is the default.
- :scroll ---scroll the window horizontally to keep the cursor
position inside the viewport, then keep doing the output.
- :allow ---ignore the text margin and do the output on the drawing
plane beyond the visible part of the viewport.
| with-end-of-line-action | (stream action) &body body | [Macro] |
Temporarily changes stream 's end-of-line action for the duration of
execution of body. action must be one of the actions described in
stream-end-of-line-action .
The stream argument is not evaluated, and must be a symbol that is bound
to a stream. If stream is t , *standard-output* is used.
body may have zero or more declarations as its first forms.
| stream-end-of-page-action | stream | [Generic function] |
| (setf stream-end-of-page-action) | action stream | [Generic function] |
The end-of-page action controls what happens if the text cursor position moves
vertically out of the viewport.
stream-end-of-page-action returns the end-of-page action for the
extended output stream stream . It can be changed by using
setf on stream-end-of-page-action .
The end-of-page action is one of:
- :scroll ---scroll the window vertically to keep the cursor position
inside the viewport, then keep doing output. This is the default.
- :allow ---ignore the viewport and do the output on the drawing plane
beyond the visible part of the viewport.
- :wrap ---when doing text output, wrap the text around (that is, go back
to the top of the viewport).
| with-end-of-page-action | (stream action) &body body | [Macro] |
Temporarily changes stream 's end-of-page action for the duration of
execution of body. action must be one of the actions described in
stream-end-of-page-action .
The stream argument is not evaluated, and must be a symbol that is bound
to a stream. If stream is t , *standard-output* is used.
body may have zero or more declarations as its first forms.
15.5 Attracting the User's Attention
| beep | &optional medium | [Generic function] |
Attracts the user's attention, usually with an audible sound.
15.6 Buffering of Output
Some mediums that support the output protocol may buffer output. When buffering
is enabled on a medium, the time at which output is actually done on the medium
is unpredictable. force-output or finish-output can be used to ensure
that all pending output gets completed. If the medium is a bidirectional
stream, a force-output is performed whenever any sort of input is requested
on the stream.
with-buffered-output provides a way to control when buffering is enabled on
a medium. By default, CLIM's interactive streams are buffered if the underlying
window system supports buffering.
| medium-buffering-output-p | medium | [Generic function] |
Returns true if the medium medium is currently buffering
output, otherwise returns false .
| (setf medium-buffering-output-p) | buffer-p medium | [Generic function] |
Sets medium-buffering-output-p of the medium medium to
buffer-p .
| with-output-buffered | (medium &optional (buffer-p t ))
&body body | [Macro] |
If buffer-p is true (the default), this causes the medium designated by medium to start buffering output, and evaluates body in that context. If buffer-p is false , force-output will be
called before body is evaluated. When body is exited (or aborted
from), force-output will be called if output buffering will be disabled
after with-output-buffered is exited.
The medium argument is not evaluated, and must be a symbol that is bound
to a medium. If medium is t , *standard-output* is used.
body may have zero or more declarations as its first forms.