-- This file is part of purebred
-- Copyright (C) 2017-2019 RĂ³man Joost and Fraser Tweedale
--
-- purebred is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with this program. If not, see .
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE OverloadedStrings #-}
module Purebred.UI.Help.Main
( renderHelp
, createKeybindingIndex
, HelpIndex
, KeybindingHelp(..)
) where
import Data.Function (on)
import Data.List (nubBy)
import Brick.Types (Widget)
import qualified Brick.Types as T
import Brick.Widgets.Core
(Padding(..), viewport, hLimit, padLeft, padBottom, padRight, txt, (<=>),
(<+>), vBox, withAttr, emptyWidget)
import Graphics.Vty.Input.Events (Event(..), Key(..), Modifier(..))
import Control.Lens (view, views, ifoldr)
import qualified Data.Map.Strict as M
import Data.Text (Text, singleton, intercalate, pack)
import Purebred.Config (helpTitleAttr, helpKeybindingAttr)
import Purebred.Types
import Purebred.UI.Utils (titleize, Titleize)
data KeybindingHelp =
KeybindingHelp
Text -- ^ keys
Text -- ^ description
String -- ^ raw key event
type HelpIndex = M.Map Name [KeybindingHelp]
-- | Build a map between widget and it's configured key bindings
--
createKeybindingIndex :: Configuration -> HelpIndex
createKeybindingIndex cfg = M.fromList
[ (ListOfThreads, views (confIndexView . ivBrowseThreadsKeybindings) kbGroup cfg)
, (ComposeSubject, views (confComposeView . cvSubjectKeybindings) kbGroup cfg)
, (ComposeBcc, views (confComposeView . cvBccKeybindings) kbGroup cfg)
, (ComposeCc, views (confComposeView . cvCcKeybindings) kbGroup cfg)
, (ComposeFrom, views (confComposeView . cvFromKeybindings) kbGroup cfg)
, (ComposeTo, views (confComposeView . cvToKeybindings) kbGroup cfg)
, (ConfirmDialog, views (confComposeView . cvConfirmKeybindings) kbGroup cfg)
, (SaveToDiskPathEditor, views (confMailView . mvSaveToDiskKeybindings) kbGroup cfg)
, (ScrollingMailViewFindWordEditor, views (confMailView . mvFindWordEditorKeybindings) kbGroup cfg)
, (MailAttachmentPipeToEditor, views (confMailView . mvPipeToKeybindings) kbGroup cfg)
, (MailAttachmentOpenWithEditor, views (confMailView . mvOpenWithKeybindings) kbGroup cfg)
, (MailListOfAttachments, views (confMailView . mvMailListOfAttachmentsKeybindings) kbGroup cfg)
, (ManageMailTagsEditor, views (confMailView . mvManageMailTagsKeybindings) kbGroup cfg)
, (SearchThreadsEditor, views (confIndexView . ivSearchThreadsKeybindings) kbGroup cfg)
, (ManageThreadTagsEditor, views (confIndexView . ivManageThreadTagsKeybindings) kbGroup cfg)
, (ScrollingMailView, views (confMailView . mvKeybindings) kbGroup cfg)
, (ScrollingHelpView, views (confHelpView . hvKeybindings) kbGroup cfg)
, (ComposeListOfAttachments, views (confComposeView . cvListOfAttachmentsKeybindings) kbGroup cfg)
, (ListOfFiles, views (confFileBrowserView . fbKeybindings) kbGroup cfg)
, (ManageFileBrowserSearchPath, views (confFileBrowserView . fbSearchPathKeybindings) kbGroup cfg)
]
kbGroup :: [Keybinding v ctx] -> [KeybindingHelp]
kbGroup kbs = fmap createKeybindingHelp uniqKBs
where
uniqKBs = nubBy ((==) `on` view kbEvent) kbs
createKeybindingHelp :: Keybinding v ctx -> KeybindingHelp
createKeybindingHelp kb =
let keys = view kbEvent kb
actions = view (kbAction . aDescription) kb
in KeybindingHelp (ppKbEvent keys) (intercalate " > " actions) (show keys)
renderHelp :: AppState -> Widget Name
renderHelp s =
let index = createKeybindingIndex (view asConfig s)
in viewport ScrollingHelpView T.Vertical $
ifoldr renderKbGroup emptyWidget index
renderKbGroup ::
Titleize a => a -> [KeybindingHelp] -> Widget Name -> Widget Name
renderKbGroup name kbs sibling =
sibling
<=> withAttr helpTitleAttr (padBottom (Pad 1) $ txt (titleize name))
<=> padBottom (Pad 1) (vBox (renderKeybinding <$> kbs))
renderKeybinding :: KeybindingHelp -> Widget Name
renderKeybinding (KeybindingHelp keys actions _) =
withAttr helpKeybindingAttr (hLimit 30 (padRight Max $ txt keys)) <+>
padLeft (Pad 3) (txt actions)
ppKbEvent :: Event -> Text
ppKbEvent (EvKey k modifiers) = intercalate " + " $ (ppMod <$> modifiers) <> [ppKey k]
ppKbEvent _ = "??>"
ppKey :: Key -> Text
ppKey KBS = ""
ppKey KBackTab = "-"
ppKey KEsc= ""
ppKey KDel = ""
ppKey KEnd = ""
ppKey KHome = ""
ppKey KRight = ""
ppKey KLeft = ""
ppKey KUp = ""
ppKey KDown = ""
ppKey KEnter = ""
ppKey KPageUp = ""
ppKey KPageDown = ""
ppKey (KChar c) = ppChar c
ppKey (KFun n) = " pack (show n) <> ">"
ppKey _ = "??>"
ppChar :: Char -> Text
ppChar '\t' = ""
ppChar ' ' = "Space"
ppChar c = singleton c
ppMod :: Modifier -> Text
ppMod MMeta = ""
ppMod MAlt = ""
ppMod MShift = ""
ppMod MCtrl = ""