2015-08-23 03:46:57 +03:00
|
|
|
-- | The all-important theming engine!
|
|
|
|
--
|
|
|
|
-- Cf
|
|
|
|
-- https://hackage.haskell.org/package/vty/docs/Graphics-Vty-Attributes.html
|
|
|
|
-- http://hackage.haskell.org/package/brick/docs/Brick-AttrMap.html
|
|
|
|
-- http://hackage.haskell.org/package/brick-0.1/docs/Brick-Util.html
|
|
|
|
-- http://hackage.haskell.org/package/brick-0.1/docs/Brick-Widgets-Core.html#g:5
|
|
|
|
-- http://hackage.haskell.org/package/brick-0.1/docs/Brick-Widgets-Border.html
|
|
|
|
|
2018-03-25 01:51:56 +03:00
|
|
|
{-# LANGUAGE CPP #-}
|
2018-10-23 16:33:21 +03:00
|
|
|
{-# LANGUAGE OverloadedStrings #-}
|
2015-08-23 03:46:57 +03:00
|
|
|
|
|
|
|
module Hledger.UI.Theme (
|
|
|
|
defaultTheme
|
|
|
|
,getTheme
|
|
|
|
,themes
|
|
|
|
,themeNames
|
2018-10-23 16:33:21 +03:00
|
|
|
)
|
|
|
|
where
|
2015-08-23 03:46:57 +03:00
|
|
|
|
|
|
|
import qualified Data.Map as M
|
|
|
|
import Data.Maybe
|
2018-03-25 01:51:56 +03:00
|
|
|
#if !(MIN_VERSION_base(4,11,0))
|
2015-08-23 03:46:57 +03:00
|
|
|
import Data.Monoid
|
2018-03-25 01:51:56 +03:00
|
|
|
#endif
|
2015-08-23 03:46:57 +03:00
|
|
|
import Graphics.Vty
|
|
|
|
import Brick
|
|
|
|
|
|
|
|
defaultTheme :: AttrMap
|
|
|
|
defaultTheme = fromMaybe (snd $ head themesList) $ getTheme "white"
|
|
|
|
-- the theme named here should exist;
|
|
|
|
-- otherwise it will take the first one from the list,
|
|
|
|
-- which must be non-empty.
|
|
|
|
|
|
|
|
-- | Look up the named theme, if it exists.
|
|
|
|
getTheme :: String -> Maybe AttrMap
|
|
|
|
getTheme name = M.lookup name themes
|
|
|
|
|
|
|
|
-- | A selection of named themes specifying terminal colours and styles.
|
|
|
|
-- One of these is active at a time.
|
|
|
|
--
|
|
|
|
-- A hledger-ui theme is a vty/brick AttrMap. Each theme specifies a
|
|
|
|
-- default style (Attr), plus extra styles which are applied when
|
2015-08-25 02:23:20 +03:00
|
|
|
-- their (hierarchical) name matches the widget rendering context.
|
|
|
|
-- "More specific styles, if present, are used and only fall back to
|
|
|
|
-- more general ones when the more specific ones are absent, but also
|
|
|
|
-- these styles get merged, so that if a more specific style only
|
|
|
|
-- provides the foreground color, its more general parent style can
|
|
|
|
-- set the background color, too."
|
|
|
|
-- For example: rendering a widget named "b" inside a widget named "a",
|
|
|
|
-- - if a style named "a" <> "b" exists, it will be used. Anything it
|
|
|
|
-- does not specify will be taken from a style named "a" if that
|
|
|
|
-- exists, otherwise from the default style.
|
|
|
|
-- - otherwise if a style named "a" exists, it will be used, and
|
|
|
|
-- anything it does not specify will be taken from the default style.
|
|
|
|
-- - otherwise (you guessed it) the default style is used.
|
2015-08-23 03:46:57 +03:00
|
|
|
--
|
|
|
|
themes :: M.Map String AttrMap
|
|
|
|
themes = M.fromList themesList
|
|
|
|
|
|
|
|
themeNames :: [String]
|
|
|
|
themeNames = map fst themesList
|
|
|
|
|
|
|
|
(&) = withStyle
|
2018-10-23 17:15:11 +03:00
|
|
|
active = fg brightWhite & bold
|
|
|
|
selectbg = yellow
|
|
|
|
select = black `on` selectbg
|
2018-10-23 16:33:21 +03:00
|
|
|
|
2015-08-23 03:46:57 +03:00
|
|
|
themesList :: [(String, AttrMap)]
|
|
|
|
themesList = [
|
2018-10-23 16:33:21 +03:00
|
|
|
("default", attrMap (black `on` white) [
|
|
|
|
("border" , white `on` black & dim)
|
|
|
|
,("border" <> "bold" , currentAttr & bold)
|
2018-10-23 17:15:11 +03:00
|
|
|
,("border" <> "depth" , active)
|
2018-10-23 16:47:30 +03:00
|
|
|
,("border" <> "filename" , currentAttr)
|
2018-10-23 17:15:11 +03:00
|
|
|
,("border" <> "key" , active)
|
2018-10-23 16:33:21 +03:00
|
|
|
,("border" <> "minibuffer" , white `on` black & bold)
|
2018-10-23 17:15:11 +03:00
|
|
|
,("border" <> "query" , active)
|
|
|
|
,("border" <> "selected" , active)
|
2018-10-23 16:33:21 +03:00
|
|
|
,("error" , fg red)
|
|
|
|
,("help" , white `on` black & dim)
|
|
|
|
,("help" <> "heading" , fg yellow)
|
2018-10-23 17:15:11 +03:00
|
|
|
,("help" <> "key" , active)
|
|
|
|
-- ,("list" , black `on` white)
|
|
|
|
-- ,("list" <> "amount" , currentAttr)
|
2018-10-23 16:33:21 +03:00
|
|
|
,("list" <> "amount" <> "decrease" , fg red)
|
2018-10-23 17:40:06 +03:00
|
|
|
-- ,("list" <> "amount" <> "increase" , fg green)
|
2018-10-23 17:15:11 +03:00
|
|
|
,("list" <> "amount" <> "decrease" <> "selected" , red `on` selectbg & bold)
|
2018-10-23 17:40:06 +03:00
|
|
|
-- ,("list" <> "amount" <> "increase" <> "selected" , green `on` selectbg & bold)
|
2018-10-23 17:15:11 +03:00
|
|
|
,("list" <> "balance" , currentAttr & bold)
|
2018-10-23 16:33:21 +03:00
|
|
|
,("list" <> "balance" <> "negative" , fg red)
|
|
|
|
,("list" <> "balance" <> "positive" , fg black)
|
2018-10-23 17:15:11 +03:00
|
|
|
,("list" <> "balance" <> "negative" <> "selected" , red `on` selectbg & bold)
|
|
|
|
,("list" <> "balance" <> "positive" <> "selected" , select & bold)
|
|
|
|
,("list" <> "selected" , select)
|
2018-10-23 16:33:21 +03:00
|
|
|
-- ,("list" <> "accounts" , white `on` brightGreen)
|
|
|
|
-- ,("list" <> "selected" , black `on` brightYellow)
|
|
|
|
])
|
|
|
|
|
|
|
|
,("greenterm", attrMap (green `on` black) [
|
2018-10-23 17:15:11 +03:00
|
|
|
("list" <> "selected" , black `on` green)
|
2018-10-23 16:33:21 +03:00
|
|
|
])
|
|
|
|
|
|
|
|
,("terminal", attrMap defAttr [
|
|
|
|
("border" , white `on` black),
|
|
|
|
("list" , defAttr),
|
2018-10-23 17:15:11 +03:00
|
|
|
("list" <> "selected" , defAttr & reverseVideo)
|
2018-10-23 16:33:21 +03:00
|
|
|
])
|
2015-08-23 03:46:57 +03:00
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
-- halfbrightattr = defAttr & dim
|
|
|
|
-- reverseattr = defAttr & reverseVideo
|
|
|
|
-- redattr = defAttr `withForeColor` red
|
|
|
|
-- greenattr = defAttr `withForeColor` green
|
|
|
|
-- reverseredattr = defAttr & reverseVideo `withForeColor` red
|
|
|
|
-- reversegreenattr= defAttr & reverseVideo `withForeColor` green
|