diff --git a/hledger-ui/Hledger/UI/Main.hs b/hledger-ui/Hledger/UI/Main.hs index 368da8c18..651d24e53 100644 --- a/hledger-ui/Hledger/UI/Main.hs +++ b/hledger-ui/Hledger/UI/Main.hs @@ -126,15 +126,15 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do ,aPrevScreens=prevscrs ,aMinibuffer=Nothing } - - app :: App (AppState) V.Event - app = App { + + brickapp :: App (AppState) V.Event + brickapp = App { appLiftVtyEvent = id , appStartEvent = return , appAttrMap = const theme , appChooseCursor = showFirstCursor , appHandleEvent = \st ev -> sHandleFn (aScreen st) st ev - , appDraw = \st -> sDrawFn (aScreen st) st + , appDraw = \st -> sDrawFn (aScreen st) st -- XXX bizarro. removing the st arg and parameter above, -- which according to GHCI does not change the type, -- causes "Exception: draw function called with wrong screen type" @@ -142,5 +142,5 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do -- causes an exception on exiting a register. } - void $ defaultMain app st + void $ defaultMain brickapp st diff --git a/hledger-ui/Hledger/UI/UITypes.hs b/hledger-ui/Hledger/UI/UITypes.hs index c44d99b4b..7ca6157bd 100644 --- a/hledger-ui/Hledger/UI/UITypes.hs +++ b/hledger-ui/Hledger/UI/UITypes.hs @@ -1,3 +1,34 @@ +{- | +Overview: +hledger-ui's AppState holds the active screen and any previously visited screens. +Screens have their own render state, render function, event handler, +and app state update function (which can update the whole AppState). +A brick App delegates event-handling and rendering to our AppState's active screen. + +@ +Brick.defaultMain brickapp st + where + brickapp :: App (AppState) V.Event + brickapp = App { + appLiftVtyEvent = id + , appStartEvent = return + , appAttrMap = const theme + , appChooseCursor = showFirstCursor + , appHandleEvent = \st ev -> sHandleFn (aScreen st) st ev + , appDraw = \st -> sDrawFn (aScreen st) st + } + st :: AppState + st = (sInitFn scr) d + AppState{ + aopts=uopts' + ,ajournal=j + ,aScreen=scr + ,aPrevScreens=prevscrs + ,aMinibuffer=Nothing + } +@ +-} + {-# LANGUAGE StandaloneDeriving #-} module Hledger.UI.UITypes where @@ -13,58 +44,68 @@ import Text.Show.Functions () import Hledger import Hledger.UI.UIOptions ----------------------------------------------------------------------- - -instance Show Editor - where - show = const "" - --- | hledger-ui's application state. This is part of, but distinct --- from, brick's App. +-- | hledger-ui's application state. This holds one or more stateful screens. data AppState = AppState { - aopts :: UIOpts -- ^ the command-line options and query currently in effect - ,ajournal :: Journal -- ^ the journal being viewed - ,aScreen :: Screen -- ^ the currently active screen - ,aPrevScreens :: [Screen] -- ^ previously visited screens, most recent first - ,aMinibuffer :: Maybe Editor -- ^ a compact editor used for data entry, when active + aopts :: UIOpts -- ^ the command-line options and query arguments currently in effect + ,ajournal :: Journal -- ^ the journal being viewed + ,aScreen :: Screen -- ^ the currently active screen + ,aPrevScreens :: [Screen] -- ^ previously visited screens, most recent first + ,aMinibuffer :: Maybe Editor -- ^ a compact editor used for data entry, when active } deriving (Show) --- | Types of screen available within the app, along with their state. --- Screen types are distinguished by their constructor and their state --- field, which must have unique names. +-- | Types of screen available within hledger-ui. Each has its own +-- specific state type, and generic initialisation, event handling +-- and rendering functions. -- --- This type causes partial functions, so take care. +-- Screen types are pattern-matched by their constructor and their +-- state field, which must have a unique name. This type causes +-- partial functions, so take care. data Screen = AccountsScreen { - asState :: (List (Int,AccountName,AccountName,[String]), AccountName) -- ^ list widget holding (indent level, full account name, full or short account name to display, rendered amounts); - -- the full name of the currently selected account (or "") - ,sInitFn :: Day -> AppState -> AppState -- ^ function to initialise the screen's state on entry - ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) -- ^ brick event handler to use for this screen - ,sDrawFn :: AppState -> [Widget] -- ^ brick renderer to use for this screen + asState :: (List -- list widget holding: + (Int -- indent level + ,AccountName -- full account name + ,AccountName -- full or short account name to display + ,[String] -- rendered amounts + ) + ,AccountName -- full name of the currently selected account (or "") + ) + ,sInitFn :: Day -> AppState -> AppState -- ^ function to generate the screen's state on entry or change + ,sDrawFn :: AppState -> [Widget] -- ^ brick renderer to use for this screen + ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) -- ^ brick event handler to use for this screen } | RegisterScreen { - rsState :: (List (String,String,String,String,String,Transaction), AccountName) - -- ^ list widget holding (date, description, other accts, change amt, balance amt, and the full transaction); - -- the full name of the account we are showing a register for - ,sInitFn :: Day -> AppState -> AppState - ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) - ,sDrawFn :: AppState -> [Widget] + rsState :: (List -- list widget holding: + (String -- date + ,String -- description + ,String -- other accts + ,String -- change amt + ,String -- balance amt + ,Transaction -- the full transaction + ) + ,AccountName -- full name of the acct we are showing a register for + ) + ,sInitFn :: Day -> AppState -> AppState -- ^ function to generate the screen's state on entry or change + ,sDrawFn :: AppState -> [Widget] -- ^ brick renderer to use for this screen + ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) -- ^ brick event handler to use for this screen } | TransactionScreen { - tsState :: ((Integer,Transaction), [(Integer,Transaction)], AccountName) - -- ^ the (numbered) transaction we are currently viewing, - -- the list of numbered transactions we can step through, - -- and the account whose register we entered this screen from - ,sInitFn :: Day -> AppState -> AppState - ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) - ,sDrawFn :: AppState -> [Widget] + tsState :: ((Integer, Transaction) -- the (numbered) transaction we are currently viewing + ,[(Integer, Transaction)] -- the list of numbered transactions we can step through + ,AccountName -- the account whose register we entered this screen from + ) + ,sInitFn :: Day -> AppState -> AppState + ,sDrawFn :: AppState -> [Widget] + ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) } | ErrorScreen { - esState :: String -- ^ error message to display - ,sInitFn :: Day -> AppState -> AppState - ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) - ,sDrawFn :: AppState -> [Widget] + esState :: String -- error message to display + ,sInitFn :: Day -> AppState -> AppState + ,sDrawFn :: AppState -> [Widget] + ,sHandleFn :: AppState -> V.Event -> EventM (Next AppState) } deriving (Show) instance Show (List a) where show _ = "" +instance Show Editor where show _ = "" +