This module provides types and functions for managing an attribute
map which maps attribute names (AttrName) to attributes (Attr).
Attribute maps work by mapping hierarchical attribute names to
attributes and inheriting parent names' attributes when child names
specify partial attributes. Hierarchical names are created with mappend:
let n = attrName "parent" <> attrName "child"
Attribute names are mapped to attributes, but some attributes may
be partial (specify only a foreground or background color). When
attribute name lookups occur, the attribute corresponding to a more
specific name ('parent <> child' as above) is successively merged with
the parent attribute (parent as above) all the way to the "root"
of the attribute map, the map's default attribute. In this way, more
specific attributes inherit what they don't specify from more general
attributes in the same hierarchy. This allows more modularity and
less repetition in specifying how elements of your user interface
take on different attributes.
An attribute name. Attribute names are hierarchical; use mappend
(<>) to assemble them. Hierarchy in an attribute name is used to
represent increasing levels of specificity in referring to the
attribute you want to use for a visual element, with names to the
left being general and names to the right being more specific. For
example:
Look up the specified attribute name in the map. Map lookups
proceed as follows. If the attribute map is forcing all lookups to a
specific attribute, that attribute is returned along with its style
settings. If the attribute name is empty, the map's default attribute
is returned. If the attribute name is non-empty, every subsequence of
names from the specified name are used to perform a lookup and the
results are combined as in mergeWithDefault, with more specific
results taking precedence over less specific ones. As attributes are
merged, styles are also merged. If a more specific attribute name
introduces a style (underline, say) and a less specific attribute
name introduces an additional style (bold, say) then the final result
will include both styles.
For example:
attrMapLookup (attrName "foo" <> attrName "bar") (attrMap a []) == a
attrMapLookup (attrName "foo" <> attrName "bar") (attrMap (bg blue) [(attrName "foo" <> attrName "bar", fg red)]) == red `on` blue
attrMapLookup (attrName "foo" <> attrName "bar") (attrMap (bg blue) [(attrName "foo" <> attrName "bar", red on cyan)]) == red `on` cyan
attrMapLookup (attrName "foo" <> attrName "bar") (attrMap (bg blue) [(attrName "foo" <> attrName "bar", fg red), ("foo", bg cyan)]) == red `on` cyan
attrMapLookup (attrName "foo" <> attrName "bar") (attrMap (bg blue) [(attrName "foo", fg red)]) == red `on` blue
Given an attribute and a map, merge the attribute with the map's
default attribute. If the map is forcing all lookups to a specific
attribute, the forced attribute is returned without merging it with
the one specified here. Otherwise the attribute given here is merged
with the attribute map's default attribute in that any aspect of the
specified attribute that is not provided falls back to the map
default. For example,
Update an attribute map such that a lookup of ontoName returns
the attribute value specified by fromName. This is useful for
composite widgets with specific attribute names mapping those names
to the sub-widget's expected name when calling that sub-widget's
rendering function. See the ProgressBarDemo for an example usage,
and overrideAttr for an alternate syntax.