vty-6.6: src/Graphics/Vty/Attributes.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
-- | Display attributes
--
-- Attributes have three components: a foreground color, a background
-- color, and a style mask. The simplest attribute is the default
-- attribute, or 'defAttr'. Attributes can be modified with
-- 'withForeColor', 'withBackColor', and 'withStyle', e.g.,
--
-- @
-- defAttr \`withForeColor\` red
-- @
--
-- 'Image' constructors often require an 'Attr' to indicate the
-- attributes used in the image, e.g.,
--
-- @
-- string (defAttr \`withForeColor\` red) "this text will be red"
-- @
--
-- The appearance of 'Image's using 'defAttr' is determined by the The
-- terminal, so this is not something VTY can control. The user is free
-- to The define the color scheme of the terminal as they see fit.
--
-- The value 'currentAttr' will keep the attributes of whatever was
-- output previously.
module Graphics.Vty.Attributes
( module Graphics.Vty.Attributes.Color
, Attr(..)
, FixedAttr(..)
, MaybeDefault(..)
, defAttr
, currentAttr
-- * Styles
, Style
, withStyle
, standout
, italic
, strikethrough
, underline
, reverseVideo
, blink
, dim
, bold
, defaultStyleMask
, styleMask
, hasStyle
-- * Setting attribute colors
, withForeColor
, withBackColor
-- * Setting hyperlinks
, withURL
)
where
import Control.DeepSeq
import Data.Bits
import Data.Text (Text)
import Data.Word
import GHC.Generics
import Graphics.Vty.Attributes.Color
-- | A display attribute defines the Color and Style of all the
-- characters rendered after the attribute is applied.
--
-- At most 256 colors, picked from a 240 and 16 color palette, are
-- possible for the background and foreground. The 240 colors and
-- 16 colors are points in different palettes. See Color for more
-- information.
data Attr = Attr
{ attrStyle :: !(MaybeDefault Style)
, attrForeColor :: !(MaybeDefault Color)
, attrBackColor :: !(MaybeDefault Color)
, attrURL :: !(MaybeDefault Text)
} deriving ( Eq, Show, Read, Generic, NFData )
-- This could be encoded into a single 32 bit word. The 32 bit word is
-- first divided into 4 groups of 8 bits where: The first group codes
-- what action should be taken with regards to the other groups.
-- XXYYZZ__
-- XX - style action
-- 00 => reset to default
-- 01 => unchanged
-- 10 => set
-- YY - foreground color action
-- 00 => reset to default
-- 01 => unchanged
-- 10 => set
-- ZZ - background color action
-- 00 => reset to default
-- 01 => unchanged
-- 10 => set
-- __ - unused
--
-- Next is the style flags
-- SURBDOI_
-- S - standout
-- U - underline
-- R - reverse video
-- B - blink
-- D - dim
-- O - bold
-- I - italic
-- _ - unused
--
-- Then the foreground color encoded into 8 bits.
-- Then the background color encoded into 8 bits.
-- | Specifies the display attributes such that the final style and
-- color values do not depend on the previously applied display
-- attribute. The display attributes can still depend on the terminal's
-- default colors (unfortunately).
data FixedAttr = FixedAttr
{ fixedStyle :: !Style
, fixedForeColor :: !(Maybe Color)
, fixedBackColor :: !(Maybe Color)
, fixedURL :: !(Maybe Text)
} deriving ( Eq, Show )
-- | The style and color attributes can either be the terminal defaults.
-- Or be equivalent to the previously applied style. Or be a specific
-- value.
data MaybeDefault v = Default | KeepCurrent | SetTo !v
deriving (Eq, Read, Show)
instance (NFData v) => NFData (MaybeDefault v) where
rnf Default = ()
rnf KeepCurrent = ()
rnf (SetTo v) = rnf v
-- | Styles are represented as an 8 bit word. Each bit in the word is 1
-- if the style attribute assigned to that bit should be applied and 0
-- if the style attribute should not be applied.
type Style = Word8
-- | Valid style attributes include:
--
-- * standout
--
-- * underline
--
-- * reverseVideo
--
-- * blink
--
-- * dim
--
-- * bold/bright
--
-- * italic
--
-- * strikethrough (via the smxx/rmxx terminfo capabilities)
--
-- (The invisible, protect, and altcharset display attributes some
-- terminals support are not supported via VTY.)
standout, underline, reverseVideo, blink, dim, bold, italic, strikethrough :: Style
standout = 0x01
underline = 0x02
reverseVideo = 0x04
blink = 0x08
dim = 0x10
bold = 0x20
italic = 0x40
strikethrough = 0x80
defaultStyleMask :: Style
defaultStyleMask = 0x00
styleMask :: Attr -> Word8
styleMask attr
= case attrStyle attr of
Default -> 0
KeepCurrent -> 0
SetTo v -> v
-- | true if the given Style value has the specified Style set.
hasStyle :: Style -> Style -> Bool
hasStyle s bitMask = ( s .&. bitMask ) /= 0
-- | Set the foreground color of an `Attr'.
withForeColor :: Attr -> Color -> Attr
withForeColor attr c = attr { attrForeColor = SetTo c }
-- | Set the background color of an `Attr'.
withBackColor :: Attr -> Color -> Attr
withBackColor attr c = attr { attrBackColor = SetTo c }
-- | Add the given style attribute
withStyle :: Attr -> Style -> Attr
withStyle attr 0 = attr
withStyle attr styleFlag = attr { attrStyle = SetTo $ styleMask attr .|. styleFlag }
-- | Add a hyperlinked URL using the proposed [escape sequences for
-- hyperlinked
-- URLs](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda).
-- These escape sequences are comparatively new and aren't widely
-- supported in terminal emulators yet, but most terminal emulators
-- that don't know about these sequences will ignore these sequences,
-- and therefore this should fall back sensibly. In some cases they
-- won't and this will result in garbage, so this is why hyperlinking is
-- disabled by default, in which case this combinator has no observable
-- effect. To enable it, enable 'Hyperlink' mode on your Vty output
-- interface.
withURL :: Attr -> Text -> Attr
withURL attr url = attr { attrURL = SetTo url }
-- | Sets the style, background color and foreground color to the
-- default values for the terminal. There is no easy way to determine
-- what the default background and foreground colors are.
defAttr :: Attr
defAttr = Attr Default Default Default Default
-- | Keeps the style, background color and foreground color that was
-- previously set. Used to override some part of the previous style.
--
-- EG: current_style `withForeColor` brightMagenta
--
-- Would be the currently applied style (be it underline, bold, etc) but
-- with the foreground color set to brightMagenta.
currentAttr :: Attr
currentAttr = Attr KeepCurrent KeepCurrent KeepCurrent KeepCurrent