{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE MultiWayIf #-} {-# LANGUAGE ScopedTypeVariables #-} module Graphics.Vty.Attributes.Color ( Color(..) , ColorMode(..) -- ** Fixed Colors -- | Standard 8-color ANSI terminal color codes. -- -- Note that these map to colors in the terminal's custom palette. For -- instance, `white` maps to whatever the terminal color theme uses for -- white. -- -- Use these functions if you want to make apps that fit the terminal theme. -- If you want access to more/stronger colors use `rgbColor` , black , red , green , yellow , blue , magenta , cyan , white -- | Bright/Vivid variants of the standard 8-color ANSI , brightBlack , brightRed , brightGreen , brightYellow , brightBlue , brightMagenta , brightCyan , brightWhite -- ** Creating Colors From RGB , linearColor , srgbColor , rgbColor , color240 , module Graphics.Vty.Attributes.Color240 ) where import Data.Word import GHC.Generics import Control.DeepSeq import Graphics.Vty.Attributes.Color240 -- | Abstract data type representing a color. -- -- Currently the foreground and background color are specified as points -- in either a: -- -- * 16 color palette. Where the first 8 colors are equal to the 8 -- colors of the ISO 6429 (ANSI) 8 color palette and the second 8 -- colors are bright/vivid versions of the first 8 colors. -- -- * 240 color palette. This palette is a regular sampling of the full -- RGB colorspace for the first 224 colors. The remaining 16 colors is -- a greyscale palette. -- -- The 8 ISO 6429 (ANSI) colors are as follows: -- -- * black (0) -- -- * red (1) -- -- * green (2) -- -- * yellow (3) -- -- * blue (4) -- -- * magenta (5) -- -- * cyan (6) -- -- * white (7) -- -- The mapping from points in the 240 color palette to colors actually -- displayable by the terminal depends on the number of colors the -- terminal claims to support. Which is usually determined by the -- terminfo "colors" property. If this property is not being accurately -- reported then the color reproduction will be incorrect. -- -- If the terminal reports <= 16 colors then the 240 color palette -- points are only mapped to the 8 color palette. I'm not sure of -- the RGB points for the "bright" colors which is why they are not -- addressable via the 240 color palette. -- -- If the terminal reports > 16 colors then the 240 color palette -- points are mapped to the nearest points in a ("color count" - 16) -- subsampling of the 240 color palette. -- -- All of this assumes the terminals are behaving similarly to xterm and -- rxvt when handling colors. And that the individual colors have not -- been remapped by the user. There may be a way to verify this through -- terminfo but I don't know it. -- -- Seriously, terminal color support is INSANE. data Color = ISOColor !Word8 | Color240 !Word8 | RGBColor !Word8 !Word8 !Word8 deriving ( Eq, Show, Read, Generic, NFData ) data ColorMode = NoColor | ColorMode8 | ColorMode16 | ColorMode240 !Word8 | FullColor deriving ( Eq, Show, Read ) black, red, green, yellow, blue, magenta, cyan, white :: Color black = ISOColor 0 red = ISOColor 1 green = ISOColor 2 yellow = ISOColor 3 blue = ISOColor 4 magenta= ISOColor 5 cyan = ISOColor 6 white = ISOColor 7 brightBlack, brightRed, brightGreen, brightYellow :: Color brightBlue, brightMagenta, brightCyan, brightWhite :: Color brightBlack = ISOColor 8 brightRed = ISOColor 9 brightGreen = ISOColor 10 brightYellow = ISOColor 11 brightBlue = ISOColor 12 brightMagenta= ISOColor 13 brightCyan = ISOColor 14 brightWhite = ISOColor 15 -- | Create a color value from RGB values in the 0..255 range inclusive. -- No transformation of the input values is done; a color is created -- directly from the RGB values specified, unlike the 'srgbColor' and -- 'color240' functions. linearColor :: Integral i => i -> i -> i -> Color linearColor r g b = RGBColor r' g' b' where r' = fromIntegral (clamp r) :: Word8 g' = fromIntegral (clamp g) :: Word8 b' = fromIntegral (clamp b) :: Word8 clamp = min 255 . max 0 -- | Given RGB values in the range 0..255 inclusive, create a color -- using the sRGB transformation described at -- -- https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation srgbColor :: Integral i => i -> i -> i -> Color srgbColor r g b = -- TODO: it may be worth translating this to a lookup table, as with color240 let shrink n = fromIntegral n / 255 :: Double -- called gamma^-1 in wiki gamma u | u <= 0.04045 = u/12.92 | otherwise = ((u + 0.055) / 1.055) ** 2.4 -- TODO: this is a slightly inaccurate conversion. is it worth doing proterly? expand n = round (255 * n) convert = expand . gamma . shrink in RGBColor (convert r) (convert g) (convert b) color240 :: Integral i => i -> i -> i -> Color color240 r g b = Color240 (rgbColorToColor240 r g b) -- | Create a Vty 'Color' (in the 240 color set) from an RGB triple. -- This is a synonym for 'color240'. This function is lossy in the sense -- that we only internally support 240 colors but the #RRGGBB format -- supports 256^3 colors. rgbColor :: Integral i => i -> i -> i -> Color rgbColor = color240