packages feed

vty-ui-1.9: doc/ch4/List.tex

\section{Lists}
\label{sec:lists}

The \fw{List} module provides a rich interface for displaying,
navigating, and selecting from a list of elements.

\fw{List}s support the following key bindings:

\begin{itemize}
\item \fw{Up}, \fw{Down} -- changes the currently-selected element by
  one element in the respective direction.
\item \fw{PageUp}, \fw{PageDown} -- changes the currently-selected
  element by a page of elements, which depends on the number of
  elements currently shown in the list.
\item \fw{Enter} -- notifies event handlers that the
  currently-selected item has been ``activated.''
\end{itemize}

Lists are implemented with the type \fw{List a b}.  Its two type
parameters are as follows:

\begin{itemize}
\item \textit{internal item type}, \fw{a} -- This is the type of the
  application-specific value stored in each list item.  This is the
  data that is represented by the visual aspect of the list element
  and it will not necessarily have anything to do with the visual
  representation.
\item \textit{item widget type}, \fw{b} -- This is the type of the
  widget state of each element as it is represented in the interface.
  For example, a simple list of strings might use \fw{String} as its
  internal value type and \fw{Widget FormattedText} (Section
  \ref{sec:text}) as its widget type, resulting in a list of type
  \fw{List String FormattedText}.
\end{itemize}

Lists are created with the \fw{newList} function:

\begin{haskellcode}
 lst <- newList 1
\end{haskellcode}

\fw{newList} takes one parameter: the height, in rows, of each widget in the
list.  The \fw{List} uses its own focus attribute (Section
\ref{sec:attributes}) as the attribute of the currently-selected item when it
has the focus.  The widget type of the list (\fw{b} above) won't be chosen by
the type system until you actually add something to the list.

The \fw{List} widget uses the default focus attribute of the rendering context
to render the selected item when the list has the focus.  To control how the
selected item appears when the list has or lacks focus, use see
\fw{set\-Selected\-Focused\-Attr} and
\fw{set\-Se\-lec\-ted\-Un\-fo\-cused\-Attr}.

Items may be added to a \fw{List} with the \fw{addToList} function,
which takes an internal value (e.g., \fw{String}) and a widget of the
appropriate type:

\begin{haskellcode}
 let s = "foobar"
 addToList lst s =<< plainText s
\end{haskellcode}

In addition, items may be inserted into a \fw{List} at any position with
the \fw{insertIntoList} function.

When it comes to how \fw{List}s render item widgets, there are two behaviors to
know about:

\begin{itemize}
\item \textit{All widgets rendered by the list must have the same height}.
  This is because the list uses the item height to calculate how many
  items can be displayed, given the space available to the rendered \fw{List}.
  This is why the height of list items must be passed to \fw{newList}.
\item \textit{The item widgets will be height-restricted}.  This is because all
  \fw{List} item widgets must take up a fixed amount of vertical space so the
  \fw{List} can manage scrolling state.  Internally the \fw{List} widget uses
  \fw{vLimit} and \fw{vFixed} wrappers to render each item widget to guarantee
  that all items have the same height.
\end{itemize}

Items may be removed from \fw{List}s with the \fw{removeFromList}
function, which takes a \fw{Widget (List a b)} and an item position,
removes the item at the specified position, and returns the removed
item:

\begin{haskellcode}
 (val, w) <- removeFromList lst 0
\end{haskellcode}

If the position is invalid, a \fw{ListError} is thrown.
\fw{removeFromList} returns the internal value (\fw{val}) and the
corresponding widget (\fw{w}) of the removed list entry.

All of the items can be removed from a \fw{List} with the
\fw{clearList} function.  \fw{clearList} does \textit{not} invoke any
event handlers for the removed items.

In addition to \fw{addToList}, the \fw{List} API provides the
\fw{setSelected} function.  This function takes a \fw{List} widget and
an index and scrolls the list so that the item at the specified
position is selected.  If the position is out of bounds, the \fw{List}
is scrolled as much as possible.

\subsection{\fw{List} Inspection}

The \fw{List} module provides some functions to get information about
the state of a \fw{List}:

\begin{itemize}
\item \fw{getListSize} -- returns the number of elements in a
  \fw{List}.
\item \fw{getSelected} -- takes a \fw{Widget (List a b)} and returns
  \fw{Nothing} if the \fw{List} is empty or returns \fw{Just (pos,
    (val, widget))} corresponding to the list index, internal item
  value, and widget of the currently-selected list item.
\item \fw{getListItem} -- takes a \fw{Widget (List a b)} and an index
  and returns \fw{Nothing} if the \fw{List} has no item at the
  specified index item or returns \fw{Just (val, widget)}
  corresponding to the list index.
\end{itemize}

\subsection{Scrolling a \fw{List}}
\label{sec:list_scrolling}

Although the list key bindings are bound to the \fw{List}'s scrolling
behavior, the \fw{List} module exports the scrolling functions for
programmatic manipulation of \fw{List}s.  Note that in all cases, the
scrolling functions change the position of the currently-selected item
and, if necessary, scroll the list in the terminal to reveal the
newly-selected item.

\begin{itemize}
\item \fw{scrollUp} -- moves the selected item position toward the
  beginning of the \fw{List} by one position.
\item \fw{scrollDown} -- moves the selected item position toward the
  end of the \fw{List} by one position.
\item \fw{pageUp} -- moves the selected item position toward the
  beginning of the \fw{List} by one page; the size of a page depends
  on the height of the \fw{List}'s widgets and the amount of space
  available to the rendered \fw{List}.
\item \fw{pageDown} -- moves the selected item position toward the end
  of the \fw{List} by one page; the size of a page depends on the
  height of the \fw{List}'s widgets and the amount of space available
  to the rendered \fw{List}.
\item \fw{scrollBy} -- takes a number of positions and moves the
  selected item position in the specified direction.  If the number is
  negative, this scrolls toward the beginning of the \fw{List},
  otherwise, it scrolls toward the end.
\end{itemize}

\subsection{Handling Events}

The \fw{List} type produces a variety of events:

\begin{itemize}
\item \textit{scrolling events} -- events indicating that the position
  of the currently-selected item has changed.  Handlers are registered
  with \fw{onSelectionChange} and receive an event value of type
  \fw{SelectionEvent}.  A \fw{SelectionEvent} describes whether the
  selection has been turned ``off'', which happens when the last
  element in the \fw{List} is removed, or whether it is on and
  corresponds to an item.
\item \textit{item events} -- events indicating that an item has been
  added to or removed from the \fw{List}.  Handlers for added items
  are registered with \fw{onitemAdded} receive event values of type
  \fw{NewItemEvent}.  Handlers for removed items are registered with
  \fw{onItemRemoved} and receive event values of type
  \fw{RemoveItemEvent}.
\item \textit{item activation} -- events indicating that the
  currently-selected item was \textit{activated}, which occurs when
  the user presses \fw{Enter} on a focused \fw{List}.  Handlers for
  activation events are registered with \fw{onItemActivated} and
  receive event values of type \fw{ActivateItemEvent}.
\end{itemize}

Scrolling events are generated by the functions described in Section
\ref{sec:list_scrolling}.  Item activation may be triggered
programmatically with the \fw{activateCurrentItem} function.

\subsubsection{Growth Policy}

\fw{List}s always grow both horizontally and vertically.