vty-ui-1.3: doc/ch4/FormattedText.tex
\section{Text}
\label{sec:text}
The \fw{Text} module provides a widget for rendering text strings in
user interfaces. The text widget type, \fw{Widget FormattedText}, can
be used to render simple strings or more complex text arrangements.
A \fw{FormattedText} widget can be created from a \fw{String} with the
\fw{plainText} function and can be laid out in the usual way:
\begin{haskellcode}
t1 <- plainText "blue" >>= withNormalAttribute (fgColor blue)
t2 <- plainText "green" >>= withNormalAttribute (fgColor green)
ui <- (return t1) <++> (return t2)
\end{haskellcode}
\subsection{Updating Text Widgets}
\label{sec:updatingText}
The contents of a text widget can be set in one of three ways:
\begin{itemize}
\item Initially, as a parameter to \fw{plainText} and \fw{textWidget}
\item As a \fw{String} parameter to \fw{setText}
\item As a list parameter of \fw{(String, Attr)} with
\fw{setTextWithAttrs}
\end{itemize}
All text widget update functions \textit{tokenize} their inputs,
finding contiguous sequences of whitespace and non-whitespace
characters and newlines, and store the list of tokens in the widget.
Each token is assigned a default attribute of \fw{def\_attr}, which
defaults to the ``normal'' attribute of the widget (see Section
\ref{sec:attributes} for more information on attributes).
The \fw{setText} function merely takes a \fw{String}, tokenizes it,
and assigns the default attribute to all tokens.
The \fw{setTextWithAttrs} function provides finer control over the
initial attribute assignment to the text because it lets you specify
the initial contents of the widget with your own attribute
assignments. This can be done instead of (or in addition to) the use
of formatters for maximum control over the final visual representation
of the text.
In the following example, we create a text widget and then assign it a
string with different attributes for each of the words:
\begin{haskellcode}
t <- plainText ""
setTextWithAttrs t [ ("foo", fgColor green)
, (" ", def_attr)
, ("bar", fgColor yellow)
, (" ", def_attr)
, ("baz", red `on` blue)
]
\end{haskellcode}
\subsection{Formatters}
In addition to rendering plain text strings, we can use ``formatters''
to change the arrangement and attributes of text. Formatters can
manipulate structure and attributes to change the text layout and
appearance.
To use a formatter with a text widget, we must use a different
constructor function, \fw{text\-Widget}:
\begin{haskellcode}
t <- textWidget wrap "foobar"
\end{haskellcode}
In addition, the formatter for a text widget can be set at any time
with \fw{setTextFormatter}:
\begin{haskellcode}
setTextFormatter t wrap
\end{haskellcode}
When a text widget's contents are updated, the text is automatically
broken up into tokens (see Section \ref{sec:updatingText}). It is
these tokens on which formatters operate.
The \fw{Text} module provides two formatters: \fw{wrap} and
\fw{highlight}. \fw{wrap} wraps the text to fit into the
\fw{DisplayRegion} available at rendering time, so this will end up
doing the right thing depending on the parent widget of the
\fw{FormattedText} widget. \fw{highlight} accepts a regular
expression\footnote{Any instance of \fw{RegexLike} is acceptable.} to
match text for highlighting. To construct a highlighting formatter,
we must provide the regular expression used to match strings as well
as the attribute that should be applied to the matches:\footnote{Since
formatters operate on individual tokens, the \fw{highlight}
formatter applies its regular expression to each token individually,
so it will only ever match sequences of characters in each token
rather than matching more than one token. You can certainly write
your own formatter that considers more than one token at a time,
though.}
Here is an example using \fw{highlight} with the \fw{Regex} type from
the \fw{regex-pcre} package:
\begin{haskellcode}
let doHighlight sz t = do
Right r <- compile compUngreedy execBlank "<.*>"
highlight r (fgColor bright_green) sz t
t <- textWidget doHighlight "foo <bar> baz"
\end{haskellcode}
Formatters can be composed with the \fw{\&.\&} operator. This
operator constructs a new formatter which will apply the operand
formatters in the specified order. We can use this operator to
compose the built-in formatters on a single \fw{FormattedText} widget:
\begin{haskellcode}
t <- textWidget (doHighlight &.& wrap) "Foo <bar> baz"
\end{haskellcode}
For detailed information on the token types on which the formatters
operate, see the \fw{Text.Trans.Tokenize} module.
\subsubsection{Growth Policy}
\fw{FormattedText} widgets do not grow horizontally or vertically.