ui: refactor, simplify, flatten screen types
This commit is contained in:
		
							parent
							
								
									e6b1d2d5a7
								
							
						
					
					
						commit
						8bda78a447
					
				| @ -5,12 +5,11 @@ | |||||||
| 
 | 
 | ||||||
| module Hledger.UI.AccountsScreen | module Hledger.UI.AccountsScreen | ||||||
|  (accountsScreen |  (accountsScreen | ||||||
|  ,initAccountsScreen |  ,asInit | ||||||
|  ,asSetSelectedAccount |  ,asSetSelectedAccount | ||||||
|  ) |  ) | ||||||
| where | where | ||||||
| 
 | 
 | ||||||
| import Lens.Micro ((^.)) |  | ||||||
| -- import Control.Monad | -- import Control.Monad | ||||||
| import Control.Monad.IO.Class (liftIO) | import Control.Monad.IO.Class (liftIO) | ||||||
| -- import Data.Default | -- import Data.Default | ||||||
| @ -28,7 +27,7 @@ import Brick.Widgets.List | |||||||
| import Brick.Widgets.Edit | import Brick.Widgets.Edit | ||||||
| import Brick.Widgets.Border (borderAttr) | import Brick.Widgets.Border (borderAttr) | ||||||
| -- import Brick.Widgets.Center | -- import Brick.Widgets.Center | ||||||
| import Lens.Micro ((.~), (&)) | import Lens.Micro | ||||||
| 
 | 
 | ||||||
| import Hledger | import Hledger | ||||||
| import Hledger.Cli hiding (progname,prognameandversion,green) | import Hledger.Cli hiding (progname,prognameandversion,green) | ||||||
| @ -42,24 +41,20 @@ import Hledger.UI.ErrorScreen | |||||||
| 
 | 
 | ||||||
| accountsScreen :: Screen | accountsScreen :: Screen | ||||||
| accountsScreen = AccountsScreen{ | accountsScreen = AccountsScreen{ | ||||||
|    _asState  = AccountsScreenState{_asItems=list "accounts" V.empty 1 |    sInit   = asInit | ||||||
|                                   ,_asSelectedAccount="" |   ,sDraw   = asDraw | ||||||
|                                   } |   ,sHandle = asHandle | ||||||
|   ,sInitFn   = initAccountsScreen |   ,_asList            = list "accounts" V.empty 1 | ||||||
|   ,sDrawFn   = drawAccountsScreen |   ,_asSelectedAccount = "" | ||||||
|   ,sHandleFn = handleAccountsScreen |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| asSetSelectedAccount a s@AccountsScreen{} = s & asState . asSelectedAccount .~ a | asInit :: Day -> Bool -> AppState -> AppState | ||||||
| asSetSelectedAccount _ s = s | asInit d reset st@AppState{ | ||||||
| 
 |  | ||||||
| initAccountsScreen :: Day -> Bool -> AppState -> AppState |  | ||||||
| initAccountsScreen d reset st@AppState{ |  | ||||||
|   aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}, |   aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}, | ||||||
|   ajournal=j, |   ajournal=j, | ||||||
|   aScreen=s@AccountsScreen{} |   aScreen=s@AccountsScreen{} | ||||||
|   } = |   } = | ||||||
|   st{aopts=uopts', aScreen=s & asState . asItems .~ newitems'} |   st{aopts=uopts', aScreen=s & asList .~ newitems'} | ||||||
|    where |    where | ||||||
|     newitems = list (Name "accounts") (V.fromList displayitems) 1 |     newitems = list (Name "accounts") (V.fromList displayitems) 1 | ||||||
| 
 | 
 | ||||||
| @ -67,7 +62,7 @@ initAccountsScreen d reset st@AppState{ | |||||||
|     -- (may need to move to the next leaf account when entering flat mode) |     -- (may need to move to the next leaf account when entering flat mode) | ||||||
|     newitems' = listMoveTo selidx newitems |     newitems' = listMoveTo selidx newitems | ||||||
|       where |       where | ||||||
|         selidx = case (reset, listSelectedElement $ s ^. asState . asItems) of |         selidx = case (reset, listSelectedElement $ s ^. asList) of | ||||||
|                    (True, _)               -> 0 |                    (True, _)               -> 0 | ||||||
|                    (_, Nothing)            -> 0 |                    (_, Nothing)            -> 0 | ||||||
|                    (_, Just (_,AccountsScreenItem{asItemAccountName=a})) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch |                    (_, Just (_,AccountsScreenItem{asItemAccountName=a})) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch | ||||||
| @ -104,10 +99,10 @@ initAccountsScreen d reset st@AppState{ | |||||||
|     displayitems = map displayitem items |     displayitems = map displayitem items | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| initAccountsScreen _ _ _ = error "init function called with wrong screen type, should not happen" | asInit _ _ _ = error "init function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| drawAccountsScreen :: AppState -> [Widget] | asDraw :: AppState -> [Widget] | ||||||
| drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | asDraw AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | ||||||
|                            ,ajournal=j |                            ,ajournal=j | ||||||
|                            ,aScreen=s@AccountsScreen{} |                            ,aScreen=s@AccountsScreen{} | ||||||
|                            ,aMinibuffer=mbuf} = |                            ,aMinibuffer=mbuf} = | ||||||
| @ -142,10 +137,10 @@ drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | |||||||
|           fs -> str " with " <+> withAttr (borderAttr <> "query") (str $ intercalate ", " fs) <+> str " txns" |           fs -> str " with " <+> withAttr (borderAttr <> "query") (str $ intercalate ", " fs) <+> str " txns" | ||||||
|       nonzero | empty_ ropts = str "" |       nonzero | empty_ ropts = str "" | ||||||
|               | otherwise    = withAttr (borderAttr <> "query") (str " nonzero") |               | otherwise    = withAttr (borderAttr <> "query") (str " nonzero") | ||||||
|       cur = str (case s ^. asState . asItems ^. listSelectedL of  -- XXX second ^. required here but not below.. |       cur = str (case s ^. asList ^. listSelectedL of  -- XXX second ^. required here but not below.. | ||||||
|                   Nothing -> "-" |                   Nothing -> "-" | ||||||
|                   Just i -> show (i + 1)) |                   Just i -> show (i + 1)) | ||||||
|       total = str $ show $ V.length $ s ^. asState . asItems . listElementsL |       total = str $ show $ V.length $ s ^. asList . listElementsL | ||||||
| 
 | 
 | ||||||
|       bottomlabel = borderKeysStr [ |       bottomlabel = borderKeysStr [ | ||||||
|          -- ("up/down/pgup/pgdown/home/end", "move") |          -- ("up/down/pgup/pgdown/home/end", "move") | ||||||
| @ -174,7 +169,7 @@ drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | |||||||
|             -- ltrace "availwidth" $ |             -- ltrace "availwidth" $ | ||||||
|             c^.availWidthL |             c^.availWidthL | ||||||
|             - 2 -- XXX due to margin ? shouldn't be necessary (cf UIUtils) |             - 2 -- XXX due to margin ? shouldn't be necessary (cf UIUtils) | ||||||
|           displayitems = s ^. asState . asItems . listElementsL |           displayitems = s ^. asList . listElementsL | ||||||
|           maxacctwidthseen = |           maxacctwidthseen = | ||||||
|             -- ltrace "maxacctwidthseen" $ |             -- ltrace "maxacctwidthseen" $ | ||||||
|             V.maximum $ |             V.maximum $ | ||||||
| @ -202,12 +197,12 @@ drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | |||||||
| 
 | 
 | ||||||
|           colwidths = (acctwidth, balwidth) |           colwidths = (acctwidth, balwidth) | ||||||
| 
 | 
 | ||||||
|         render $ defaultLayout toplabel bottomarea $ renderList (s ^. asState . asItems) (drawAccountsItem colwidths) |         render $ defaultLayout toplabel bottomarea $ renderList (s ^. asList) (asDrawItem colwidths) | ||||||
| 
 | 
 | ||||||
| drawAccountsScreen _ = error "draw function called with wrong screen type, should not happen" | asDraw _ = error "draw function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| drawAccountsItem :: (Int,Int) -> Bool -> AccountsScreenItem -> Widget | asDrawItem :: (Int,Int) -> Bool -> AccountsScreenItem -> Widget | ||||||
| drawAccountsItem (acctwidth, balwidth) selected AccountsScreenItem{..} = | asDrawItem (acctwidth, balwidth) selected AccountsScreenItem{..} = | ||||||
|   Widget Greedy Fixed $ do |   Widget Greedy Fixed $ do | ||||||
|     -- c <- getContext |     -- c <- getContext | ||||||
|       -- let showitem = intercalate "\n" . balanceReportItemAsText defreportopts fmt |       -- let showitem = intercalate "\n" . balanceReportItemAsText defreportopts fmt | ||||||
| @ -233,8 +228,8 @@ drawAccountsItem (acctwidth, balwidth) selected AccountsScreenItem{..} = | |||||||
|         sel | selected  = (<> "selected") |         sel | selected  = (<> "selected") | ||||||
|             | otherwise = id |             | otherwise = id | ||||||
| 
 | 
 | ||||||
| handleAccountsScreen :: AppState -> Vty.Event -> EventM (Next AppState) | asHandle :: AppState -> Vty.Event -> EventM (Next AppState) | ||||||
| handleAccountsScreen st@AppState{ | asHandle st'@AppState{ | ||||||
|    aScreen=scr@AccountsScreen{..} |    aScreen=scr@AccountsScreen{..} | ||||||
|   ,aopts=UIOpts{cliopts_=copts} |   ,aopts=UIOpts{cliopts_=copts} | ||||||
|   ,ajournal=j |   ,ajournal=j | ||||||
| @ -245,55 +240,52 @@ handleAccountsScreen st@AppState{ | |||||||
|     -- let h = c^.availHeightL |     -- let h = c^.availHeightL | ||||||
|     --     moveSel n l = listMoveBy n l |     --     moveSel n l = listMoveBy n l | ||||||
| 
 | 
 | ||||||
|     -- before we go anywhere, remember the currently selected account. |     -- save the currently selected account, in case we leave this screen and lose the selection | ||||||
|     -- (This is preserved across screen changes, unlike List's selection state) |  | ||||||
|     let |     let | ||||||
|       selacct = case listSelectedElement $ scr ^. asState . asItems of |       selacct = case listSelectedElement $ scr ^. asList of | ||||||
|                   Just (_, AccountsScreenItem{..}) -> asItemAccountName |                   Just (_, AccountsScreenItem{..}) -> asItemAccountName | ||||||
|                   Nothing -> scr ^. asState . asSelectedAccount |                   Nothing -> scr ^. asSelectedAccount | ||||||
|       st' = st{aScreen=scr & asState . asSelectedAccount .~ selacct} |       st = st'{aScreen=scr & asSelectedAccount .~ selacct} | ||||||
| 
 | 
 | ||||||
|     case mbuf of |     case mbuf of | ||||||
|       Nothing -> |       Nothing -> | ||||||
| 
 | 
 | ||||||
|         case ev of |         case ev of | ||||||
|             Vty.EvKey (Vty.KChar 'q') [] -> halt st' |             Vty.EvKey (Vty.KChar 'q') [] -> halt st | ||||||
|             -- Vty.EvKey (Vty.KChar 'l') [Vty.MCtrl] -> do |             -- Vty.EvKey (Vty.KChar 'l') [Vty.MCtrl] -> do | ||||||
|             Vty.EvKey Vty.KEsc   [] -> continue $ resetScreens d st' |             Vty.EvKey Vty.KEsc   [] -> continue $ resetScreens d st | ||||||
|             Vty.EvKey (Vty.KChar 'g') [] -> liftIO (stReloadJournalIfChanged copts d j st') >>= continue |             Vty.EvKey (Vty.KChar 'g') [] -> liftIO (stReloadJournalIfChanged copts d j st) >>= continue | ||||||
|             Vty.EvKey (Vty.KChar '-') [] -> continue $ regenerateScreens j d $ decDepth st' |             Vty.EvKey (Vty.KChar '-') [] -> continue $ regenerateScreens j d $ decDepth st | ||||||
|             Vty.EvKey (Vty.KChar '+') [] -> continue $ regenerateScreens j d $ incDepth st' |             Vty.EvKey (Vty.KChar '+') [] -> continue $ regenerateScreens j d $ incDepth st | ||||||
|             Vty.EvKey (Vty.KChar '=') [] -> continue $ regenerateScreens j d $ incDepth st' |             Vty.EvKey (Vty.KChar '=') [] -> continue $ regenerateScreens j d $ incDepth st | ||||||
|             Vty.EvKey (Vty.KChar '1') [] -> continue $ regenerateScreens j d $ setDepth 1 st' |             Vty.EvKey (Vty.KChar '1') [] -> continue $ regenerateScreens j d $ setDepth 1 st | ||||||
|             Vty.EvKey (Vty.KChar '2') [] -> continue $ regenerateScreens j d $ setDepth 2 st' |             Vty.EvKey (Vty.KChar '2') [] -> continue $ regenerateScreens j d $ setDepth 2 st | ||||||
|             Vty.EvKey (Vty.KChar '3') [] -> continue $ regenerateScreens j d $ setDepth 3 st' |             Vty.EvKey (Vty.KChar '3') [] -> continue $ regenerateScreens j d $ setDepth 3 st | ||||||
|             Vty.EvKey (Vty.KChar '4') [] -> continue $ regenerateScreens j d $ setDepth 4 st' |             Vty.EvKey (Vty.KChar '4') [] -> continue $ regenerateScreens j d $ setDepth 4 st | ||||||
|             Vty.EvKey (Vty.KChar '5') [] -> continue $ regenerateScreens j d $ setDepth 5 st' |             Vty.EvKey (Vty.KChar '5') [] -> continue $ regenerateScreens j d $ setDepth 5 st | ||||||
|             Vty.EvKey (Vty.KChar '6') [] -> continue $ regenerateScreens j d $ setDepth 6 st' |             Vty.EvKey (Vty.KChar '6') [] -> continue $ regenerateScreens j d $ setDepth 6 st | ||||||
|             Vty.EvKey (Vty.KChar '7') [] -> continue $ regenerateScreens j d $ setDepth 7 st' |             Vty.EvKey (Vty.KChar '7') [] -> continue $ regenerateScreens j d $ setDepth 7 st | ||||||
|             Vty.EvKey (Vty.KChar '8') [] -> continue $ regenerateScreens j d $ setDepth 8 st' |             Vty.EvKey (Vty.KChar '8') [] -> continue $ regenerateScreens j d $ setDepth 8 st | ||||||
|             Vty.EvKey (Vty.KChar '9') [] -> continue $ regenerateScreens j d $ setDepth 9 st' |             Vty.EvKey (Vty.KChar '9') [] -> continue $ regenerateScreens j d $ setDepth 9 st | ||||||
|             Vty.EvKey (Vty.KChar '0') [] -> continue $ regenerateScreens j d $ setDepth 0 st' |             Vty.EvKey (Vty.KChar '0') [] -> continue $ regenerateScreens j d $ setDepth 0 st | ||||||
|             Vty.EvKey (Vty.KChar 'F') [] -> continue $ regenerateScreens j d $ stToggleFlat st' |             Vty.EvKey (Vty.KChar 'F') [] -> continue $ regenerateScreens j d $ stToggleFlat st | ||||||
|             Vty.EvKey (Vty.KChar 'E') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleEmpty st') |             Vty.EvKey (Vty.KChar 'E') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleEmpty st) | ||||||
|             Vty.EvKey (Vty.KChar 'C') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleCleared st') |             Vty.EvKey (Vty.KChar 'C') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleCleared st) | ||||||
|             Vty.EvKey (Vty.KChar 'U') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleUncleared st') |             Vty.EvKey (Vty.KChar 'U') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleUncleared st) | ||||||
|             Vty.EvKey (Vty.KChar 'R') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleReal st') |             Vty.EvKey (Vty.KChar 'R') [] -> scrollTop >> (continue $ regenerateScreens j d $ stToggleReal st) | ||||||
|             Vty.EvKey k [] | k `elem` [Vty.KChar '/'] -> continue $ regenerateScreens j d $ stShowMinibuffer st' |             Vty.EvKey k [] | k `elem` [Vty.KChar '/'] -> continue $ regenerateScreens j d $ stShowMinibuffer st | ||||||
|             Vty.EvKey k [] | k `elem` [Vty.KBS, Vty.KDel] -> (continue $ regenerateScreens j d $ stResetFilter st') |             Vty.EvKey k [] | k `elem` [Vty.KBS, Vty.KDel] -> (continue $ regenerateScreens j d $ stResetFilter st) | ||||||
|             Vty.EvKey (Vty.KLeft) []     -> continue $ popScreen st' |             Vty.EvKey (Vty.KLeft) []     -> continue $ popScreen st | ||||||
|             Vty.EvKey (k) [] | k `elem` [Vty.KRight, Vty.KEnter] -> do |             Vty.EvKey (k) [] | k `elem` [Vty.KRight, Vty.KEnter] -> scrollTopRegister >> continue (screenEnter d scr st) | ||||||
|               let |               where | ||||||
|                 scr = rsSetCurrentAccount selacct registerScreen |                 scr = rsSetAccount selacct registerScreen | ||||||
|                 st'' = screenEnter d scr st' |  | ||||||
|               scrollTopRegister |  | ||||||
|               continue st'' |  | ||||||
| 
 | 
 | ||||||
|             -- fall through to the list's event handler (handles up/down) |             -- fall through to the list's event handler (handles up/down) | ||||||
|             ev                       -> do |             ev                       -> do | ||||||
|                                          newitems <- handleEvent ev (scr ^. asState . asItems) |                                          newitems <- handleEvent ev (scr ^. asList) | ||||||
|                                          continue $ st'{aScreen=scr & asState . asItems .~ newitems |                                          continue $ st'{aScreen=scr & asList .~ newitems | ||||||
|                                                                     & asState . asSelectedAccount .~ selacct} |                                                                     & asSelectedAccount .~ selacct | ||||||
|  |                                                                     } | ||||||
|                                      -- continue =<< handleEventLensed st' someLens ev |                                      -- continue =<< handleEventLensed st' someLens ev | ||||||
| 
 | 
 | ||||||
|       Just ed -> |       Just ed -> | ||||||
| @ -313,42 +305,8 @@ handleAccountsScreen st@AppState{ | |||||||
|     scrollTop         = vScrollToBeginning $ viewportScroll "accounts" |     scrollTop         = vScrollToBeginning $ viewportScroll "accounts" | ||||||
|     scrollTopRegister = vScrollToBeginning $ viewportScroll "register" |     scrollTopRegister = vScrollToBeginning $ viewportScroll "register" | ||||||
| 
 | 
 | ||||||
| handleAccountsScreen _ _ = error "event handler called with wrong screen type, should not happen" | asHandle _ _ = error "event handler called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| -- | Get the maximum account depth in the current journal. | asSetSelectedAccount a s@AccountsScreen{} = s & asSelectedAccount .~ a | ||||||
| maxDepth :: AppState -> Int | asSetSelectedAccount _ s = s | ||||||
| maxDepth AppState{ajournal=j} = maximum $ map accountNameLevel $ journalAccountNames j |  | ||||||
| 
 |  | ||||||
| -- | Decrement the current depth limit towards 0. If there was no depth limit, |  | ||||||
| -- set it to one less than the maximum account depth. |  | ||||||
| decDepth :: AppState -> AppState |  | ||||||
| decDepth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts@ReportOpts{..}}}} |  | ||||||
|   = st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=dec depth_}}}} |  | ||||||
|   where |  | ||||||
|     dec (Just d) = Just $ max 0 (d-1) |  | ||||||
|     dec Nothing  = Just $ maxDepth st - 1 |  | ||||||
| 
 |  | ||||||
| -- | Increment the current depth limit. If this makes it equal to the |  | ||||||
| -- the maximum account depth, remove the depth limit. |  | ||||||
| incDepth :: AppState -> AppState |  | ||||||
| incDepth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts@ReportOpts{..}}}} |  | ||||||
|   = st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=inc depth_}}}} |  | ||||||
|   where |  | ||||||
|     inc (Just d) | d < (maxDepth st - 1) = Just $ d+1 |  | ||||||
|     inc _ = Nothing |  | ||||||
| 
 |  | ||||||
| -- | Set the current depth limit to the specified depth, which should |  | ||||||
| -- be a positive number.  If it is zero, or equal to or greater than the |  | ||||||
| -- current maximum account depth, the depth limit will be removed. |  | ||||||
| -- (Slight inconsistency here: zero is currently a valid display depth |  | ||||||
| -- which can be reached using the - key.  But we need a key to remove |  | ||||||
| -- the depth limit, and 0 is it.) |  | ||||||
| setDepth :: Int -> AppState -> AppState |  | ||||||
| setDepth depth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} |  | ||||||
|   = st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=mdepth'}}}} |  | ||||||
|   where |  | ||||||
|     mdepth' | depth < 0            = depth_ ropts |  | ||||||
|             | depth == 0           = Nothing |  | ||||||
|             | depth >= maxDepth st = Nothing |  | ||||||
|             | otherwise            = Just depth |  | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,19 +30,19 @@ import Hledger.UI.UIUtils | |||||||
| 
 | 
 | ||||||
| errorScreen :: Screen | errorScreen :: Screen | ||||||
| errorScreen = ErrorScreen{ | errorScreen = ErrorScreen{ | ||||||
|    esState  = ErrorScreenState{esError=""} |    sInit    = esInit | ||||||
|   ,sInitFn    = initErrorScreen |   ,sDraw    = esDraw | ||||||
|   ,sDrawFn    = drawErrorScreen |   ,sHandle  = esHandle | ||||||
|   ,sHandleFn = handleErrorScreen |   ,esError  = "" | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| initErrorScreen :: Day -> Bool -> AppState -> AppState | esInit :: Day -> Bool -> AppState -> AppState | ||||||
| initErrorScreen _ _ st@AppState{aScreen=ErrorScreen{}} = st | esInit _ _ st@AppState{aScreen=ErrorScreen{}} = st | ||||||
| initErrorScreen _ _ _ = error "init function called with wrong screen type, should not happen" | esInit _ _ _ = error "init function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| drawErrorScreen :: AppState -> [Widget] | esDraw :: AppState -> [Widget] | ||||||
| drawErrorScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}}, | esDraw AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}}, | ||||||
|                              aScreen=ErrorScreen{esState=ErrorScreenState{..}}} = [ui] |                              aScreen=ErrorScreen{..}} = [ui] | ||||||
|   where |   where | ||||||
|     toplabel = withAttr ("border" <> "bold") (str "Oops. Please fix this problem then press g to reload") |     toplabel = withAttr ("border" <> "bold") (str "Oops. Please fix this problem then press g to reload") | ||||||
|             -- <+> str " transactions" |             -- <+> str " transactions" | ||||||
| @ -77,7 +77,7 @@ drawErrorScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reporto | |||||||
| 
 | 
 | ||||||
|       render $ defaultLayout toplabel bottomlabel $ withAttr "error" $ str $ esError |       render $ defaultLayout toplabel bottomlabel $ withAttr "error" $ str $ esError | ||||||
| 
 | 
 | ||||||
| drawErrorScreen _ = error "draw function called with wrong screen type, should not happen" | esDraw _ = error "draw function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| -- drawErrorItem :: (Int,Int,Int,Int,Int) -> Bool -> (String,String,String,String,String) -> Widget | -- drawErrorItem :: (Int,Int,Int,Int,Int) -> Bool -> (String,String,String,String,String) -> Widget | ||||||
| -- drawErrorItem (datewidth,descwidth,acctswidth,changewidth,balwidth) selected (date,desc,accts,change,bal) = | -- drawErrorItem (datewidth,descwidth,acctswidth,changewidth,balwidth) selected (date,desc,accts,change,bal) = | ||||||
| @ -100,9 +100,9 @@ drawErrorScreen _ = error "draw function called with wrong screen type, should n | |||||||
| --     sel | selected  = (<> "selected") | --     sel | selected  = (<> "selected") | ||||||
| --         | otherwise = id | --         | otherwise = id | ||||||
| 
 | 
 | ||||||
| handleErrorScreen :: AppState -> Vty.Event -> EventM (Next AppState) | esHandle :: AppState -> Vty.Event -> EventM (Next AppState) | ||||||
| handleErrorScreen st@AppState{ | esHandle st@AppState{ | ||||||
|    aScreen=s@ErrorScreen{esState=_err} |    aScreen=s@ErrorScreen{} | ||||||
|   ,aopts=UIOpts{cliopts_=copts} |   ,aopts=UIOpts{cliopts_=copts} | ||||||
|   ,ajournal=j |   ,ajournal=j | ||||||
|   } e = do |   } e = do | ||||||
| @ -114,7 +114,7 @@ handleErrorScreen st@AppState{ | |||||||
|     Vty.EvKey (Vty.KChar 'g') [] -> do |     Vty.EvKey (Vty.KChar 'g') [] -> do | ||||||
|       (ej, _) <- liftIO $ journalReloadIfChanged copts d j |       (ej, _) <- liftIO $ journalReloadIfChanged copts d j | ||||||
|       case ej of |       case ej of | ||||||
|         Left err -> continue st{aScreen=s{esState=ErrorScreenState{esError=err}}} -- show latest parse error |         Left err -> continue st{aScreen=s{esError=err}} -- show latest parse error | ||||||
|         Right j' -> continue $ regenerateScreens j' d $ popScreen st  -- return to previous screen, and reload it |         Right j' -> continue $ regenerateScreens j' d $ popScreen st  -- return to previous screen, and reload it | ||||||
| 
 | 
 | ||||||
|     -- Vty.EvKey (Vty.KLeft) []     -> continue $ popScreen st |     -- Vty.EvKey (Vty.KLeft) []     -> continue $ popScreen st | ||||||
| @ -124,7 +124,7 @@ handleErrorScreen st@AppState{ | |||||||
|                                  -- is' <- handleEvent ev is |                                  -- is' <- handleEvent ev is | ||||||
|                                  -- continue st{aScreen=s{rsState=is'}} |                                  -- continue st{aScreen=s{rsState=is'}} | ||||||
|                                  -- continue =<< handleEventLensed st someLens e |                                  -- continue =<< handleEventLensed st someLens e | ||||||
| handleErrorScreen _ _ = error "event handler called with wrong screen type, should not happen" | esHandle _ _ = error "event handler called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| -- If journal file(s) have changed, reload the journal and regenerate all screens. | -- If journal file(s) have changed, reload the journal and regenerate all screens. | ||||||
| -- This is here so it can reference the error screen. | -- This is here so it can reference the error screen. | ||||||
| @ -133,5 +133,5 @@ stReloadJournalIfChanged copts d j st = do | |||||||
|   (ej, _) <- journalReloadIfChanged copts d j |   (ej, _) <- journalReloadIfChanged copts d j | ||||||
|   return $ case ej of |   return $ case ej of | ||||||
|     Right j' -> regenerateScreens j' d st |     Right j' -> regenerateScreens j' d st | ||||||
|     Left err -> screenEnter d errorScreen{esState=ErrorScreenState{esError=err}} st |     Left err -> screenEnter d errorScreen{esError=err} st | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -101,7 +101,7 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do | |||||||
|       -- with --register, start on the register screen, and also put |       -- with --register, start on the register screen, and also put | ||||||
|       -- the accounts screen on the prev screens stack so you can exit |       -- the accounts screen on the prev screens stack so you can exit | ||||||
|       -- to that as usual. |       -- to that as usual. | ||||||
|       Just apat -> (rsSetCurrentAccount acct registerScreen, [ascr']) |       Just apat -> (rsSetAccount acct registerScreen, [ascr']) | ||||||
|         where |         where | ||||||
|           acct = headDef |           acct = headDef | ||||||
|                  (error' $ "--register "++apat++" did not match any account") |                  (error' $ "--register "++apat++" did not match any account") | ||||||
| @ -109,7 +109,7 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do | |||||||
|           -- Initialising the accounts screen is awkward, requiring |           -- Initialising the accounts screen is awkward, requiring | ||||||
|           -- another temporary AppState value.. |           -- another temporary AppState value.. | ||||||
|           ascr' = aScreen $ |           ascr' = aScreen $ | ||||||
|                   initAccountsScreen d True $ |                   asInit d True $ | ||||||
|                   AppState{ |                   AppState{ | ||||||
|                     aopts=uopts' |                     aopts=uopts' | ||||||
|                    ,ajournal=j |                    ,ajournal=j | ||||||
| @ -118,7 +118,7 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do | |||||||
|                    ,aMinibuffer=Nothing |                    ,aMinibuffer=Nothing | ||||||
|                    } |                    } | ||||||
|    |    | ||||||
|     st = (sInitFn scr) d True |     st = (sInit scr) d True | ||||||
|          AppState{ |          AppState{ | ||||||
|             aopts=uopts' |             aopts=uopts' | ||||||
|            ,ajournal=j |            ,ajournal=j | ||||||
| @ -133,8 +133,8 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do | |||||||
|       , appStartEvent   = return |       , appStartEvent   = return | ||||||
|       , appAttrMap      = const theme |       , appAttrMap      = const theme | ||||||
|       , appChooseCursor = showFirstCursor |       , appChooseCursor = showFirstCursor | ||||||
|       , appHandleEvent  = \st ev -> sHandleFn (aScreen st) st ev |       , appHandleEvent  = \st ev -> sHandle (aScreen st) st ev | ||||||
|       , appDraw         = \st    -> sDrawFn   (aScreen st) st |       , appDraw         = \st    -> sDraw   (aScreen st) st | ||||||
|          -- XXX bizarro. removing the st arg and parameter above, |          -- XXX bizarro. removing the st arg and parameter above, | ||||||
|          -- which according to GHCI does not change the type, |          -- which according to GHCI does not change the type, | ||||||
|          -- causes "Exception: draw function called with wrong screen type" |          -- causes "Exception: draw function called with wrong screen type" | ||||||
|  | |||||||
| @ -4,7 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| module Hledger.UI.RegisterScreen | module Hledger.UI.RegisterScreen | ||||||
|  (registerScreen |  (registerScreen | ||||||
|  ,rsSetCurrentAccount |  ,rsSetAccount | ||||||
|  ) |  ) | ||||||
| where | where | ||||||
| 
 | 
 | ||||||
| @ -37,20 +37,19 @@ import Hledger.UI.ErrorScreen | |||||||
| 
 | 
 | ||||||
| registerScreen :: Screen | registerScreen :: Screen | ||||||
| registerScreen = RegisterScreen{ | registerScreen = RegisterScreen{ | ||||||
|    rsState   = RegisterScreenState{rsItems=list "register" V.empty 1 |    sInit   = rsInit | ||||||
|                                   ,rsSelectedAccount="" |   ,sDraw   = rsDraw | ||||||
|                                   } |   ,sHandle = rsHandle | ||||||
|   ,sInitFn   = initRegisterScreen |   ,rsList    = list "register" V.empty 1 | ||||||
|   ,sDrawFn   = drawRegisterScreen |   ,rsAccount = "" | ||||||
|   ,sHandleFn = handleRegisterScreen |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| rsSetCurrentAccount a scr@RegisterScreen{..} = scr{rsState=rsState{rsSelectedAccount=a}} | rsSetAccount a scr@RegisterScreen{} = scr{rsAccount=a} | ||||||
| rsSetCurrentAccount _ scr = scr | rsSetAccount _ scr = scr | ||||||
| 
 | 
 | ||||||
| initRegisterScreen :: Day -> Bool -> AppState -> AppState | rsInit :: Day -> Bool -> AppState -> AppState | ||||||
| initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScreen{rsState=rsState@RegisterScreenState{..}}} = | rsInit d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScreen{..}} = | ||||||
|   st{aScreen=s{rsState=rsState{rsItems=newitems'}}} |   st{aScreen=s{rsList=newitems'}} | ||||||
|   where |   where | ||||||
|     -- gather arguments and queries |     -- gather arguments and queries | ||||||
|     ropts = (reportopts_ $ cliopts_ opts) |     ropts = (reportopts_ $ cliopts_ opts) | ||||||
| @ -59,7 +58,7 @@ initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@Registe | |||||||
|               balancetype_=HistoricalBalance |               balancetype_=HistoricalBalance | ||||||
|             } |             } | ||||||
|     -- XXX temp |     -- XXX temp | ||||||
|     thisacctq = Acct $ accountNameToAccountRegex rsSelectedAccount -- includes subs |     thisacctq = Acct $ accountNameToAccountRegex rsAccount -- includes subs | ||||||
|     q = filterQuery (not . queryIsDepth) $ queryFromOpts d ropts |     q = filterQuery (not . queryIsDepth) $ queryFromOpts d ropts | ||||||
| 
 | 
 | ||||||
|     (_label,items) = accountTransactionsReport ropts j q thisacctq |     (_label,items) = accountTransactionsReport ropts j q thisacctq | ||||||
| @ -89,22 +88,22 @@ initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@Registe | |||||||
|     -- (eg after toggling nonzero mode), otherwise select the last element. |     -- (eg after toggling nonzero mode), otherwise select the last element. | ||||||
|     newitems' = listMoveTo newselidx newitems |     newitems' = listMoveTo newselidx newitems | ||||||
|       where |       where | ||||||
|         newselidx = case (reset, listSelectedElement rsItems) of |         newselidx = case (reset, listSelectedElement rsList) of | ||||||
|                       (True, _)    -> 0 |                       (True, _)    -> 0 | ||||||
|                       (_, Nothing) -> endidx |                       (_, Nothing) -> endidx | ||||||
|                       (_, Just (_,RegisterScreenItem{rsItemTransaction=Transaction{tindex=ti}})) |                       (_, Just (_,RegisterScreenItem{rsItemTransaction=Transaction{tindex=ti}})) | ||||||
|                                    -> fromMaybe endidx $ findIndex ((==ti) . tindex . rsItemTransaction) displayitems |                                    -> fromMaybe endidx $ findIndex ((==ti) . tindex . rsItemTransaction) displayitems | ||||||
|         endidx = length displayitems |         endidx = length displayitems | ||||||
| 
 | 
 | ||||||
| initRegisterScreen _ _ _ = error "init function called with wrong screen type, should not happen" | rsInit _ _ _ = error "init function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| drawRegisterScreen :: AppState -> [Widget] | rsDraw :: AppState -> [Widget] | ||||||
| drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | rsDraw AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | ||||||
|                            ,aScreen=RegisterScreen{rsState=RegisterScreenState{..}} |                            ,aScreen=RegisterScreen{..} | ||||||
|                            ,aMinibuffer=mbuf} |                            ,aMinibuffer=mbuf} | ||||||
|   = [ui] |   = [ui] | ||||||
|   where |   where | ||||||
|     toplabel = withAttr ("border" <> "bold") (str $ T.unpack rsSelectedAccount) |     toplabel = withAttr ("border" <> "bold") (str $ T.unpack rsAccount) | ||||||
|             <+> togglefilters |             <+> togglefilters | ||||||
|             <+> str " transactions" |             <+> str " transactions" | ||||||
|             <+> borderQueryStr (query_ ropts) |             <+> borderQueryStr (query_ ropts) | ||||||
| @ -124,11 +123,11 @@ drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | |||||||
|           ] of |           ] of | ||||||
|         [] -> str "" |         [] -> str "" | ||||||
|         fs -> withAttr (borderAttr <> "query") (str $ " " ++ intercalate ", " fs) |         fs -> withAttr (borderAttr <> "query") (str $ " " ++ intercalate ", " fs) | ||||||
|     cur = str $ case rsItems ^. listSelectedL of |     cur = str $ case rsList ^. listSelectedL of | ||||||
|                  Nothing -> "-" |                  Nothing -> "-" | ||||||
|                  Just i -> show (i + 1) |                  Just i -> show (i + 1) | ||||||
|     total = str $ show $ length displayitems |     total = str $ show $ length displayitems | ||||||
|     displayitems = V.toList $ rsItems ^. listElementsL |     displayitems = V.toList $ rsList ^. listElementsL | ||||||
| 
 | 
 | ||||||
|     -- query = query_ $ reportopts_ $ cliopts_ opts |     -- query = query_ $ reportopts_ $ cliopts_ opts | ||||||
| 
 | 
 | ||||||
| @ -196,12 +195,12 @@ drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | |||||||
|                       Nothing  -> bottomlabel |                       Nothing  -> bottomlabel | ||||||
|                       Just ed  -> minibuffer ed |                       Just ed  -> minibuffer ed | ||||||
| 
 | 
 | ||||||
|       render $ defaultLayout toplabel bottomarea $ renderList rsItems (drawRegisterItem colwidths) |       render $ defaultLayout toplabel bottomarea $ renderList rsList (rsDrawItem colwidths) | ||||||
| 
 | 
 | ||||||
| drawRegisterScreen _ = error "draw function called with wrong screen type, should not happen" | rsDraw _ = error "draw function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| drawRegisterItem :: (Int,Int,Int,Int,Int) -> Bool -> RegisterScreenItem -> Widget | rsDrawItem :: (Int,Int,Int,Int,Int) -> Bool -> RegisterScreenItem -> Widget | ||||||
| drawRegisterItem (datewidth,descwidth,acctswidth,changewidth,balwidth) selected RegisterScreenItem{..} = | rsDrawItem (datewidth,descwidth,acctswidth,changewidth,balwidth) selected RegisterScreenItem{..} = | ||||||
|   Widget Greedy Fixed $ do |   Widget Greedy Fixed $ do | ||||||
|     render $ |     render $ | ||||||
|       str (fitString (Just datewidth) (Just datewidth) True True rsItemDate) <+> |       str (fitString (Just datewidth) (Just datewidth) True True rsItemDate) <+> | ||||||
| @ -221,9 +220,9 @@ drawRegisterItem (datewidth,descwidth,acctswidth,changewidth,balwidth) selected | |||||||
|     sel | selected  = (<> "selected") |     sel | selected  = (<> "selected") | ||||||
|         | otherwise = id |         | otherwise = id | ||||||
| 
 | 
 | ||||||
| handleRegisterScreen :: AppState -> Vty.Event -> EventM (Next AppState) | rsHandle :: AppState -> Vty.Event -> EventM (Next AppState) | ||||||
| handleRegisterScreen st@AppState{ | rsHandle st@AppState{ | ||||||
|    aScreen=s@RegisterScreen{rsState=rsState@RegisterScreenState{..}} |    aScreen=s@RegisterScreen{..} | ||||||
|   ,aopts=UIOpts{cliopts_=copts} |   ,aopts=UIOpts{cliopts_=copts} | ||||||
|   ,ajournal=j |   ,ajournal=j | ||||||
|   ,aMinibuffer=mbuf |   ,aMinibuffer=mbuf | ||||||
| @ -245,22 +244,22 @@ handleRegisterScreen st@AppState{ | |||||||
|         Vty.EvKey (Vty.KLeft)     [] -> continue $ popScreen st |         Vty.EvKey (Vty.KLeft)     [] -> continue $ popScreen st | ||||||
| 
 | 
 | ||||||
|         Vty.EvKey (k) [] | k `elem` [Vty.KRight, Vty.KEnter] -> do |         Vty.EvKey (k) [] | k `elem` [Vty.KRight, Vty.KEnter] -> do | ||||||
|           case listSelectedElement rsItems of |           case listSelectedElement rsList of | ||||||
|             Just (_, RegisterScreenItem{rsItemTransaction=t}) -> |             Just (_, RegisterScreenItem{rsItemTransaction=t}) -> | ||||||
|               let |               let | ||||||
|                 ts = map rsItemTransaction $ V.toList $ listElements rsItems |                 ts = map rsItemTransaction $ V.toList $ listElements rsList | ||||||
|                 numberedts = zip [1..] ts |                 numberedts = zip [1..] ts | ||||||
|                 i = fromIntegral $ maybe 0 (+1) $ elemIndex t ts -- XXX |                 i = fromIntegral $ maybe 0 (+1) $ elemIndex t ts -- XXX | ||||||
|               in |               in | ||||||
|                 continue $ screenEnter d transactionScreen{tsState=TransactionScreenState{tsTransaction=(i,t) |                 continue $ screenEnter d transactionScreen{tsTransaction=(i,t) | ||||||
|                                                                                          ,tsTransactions=numberedts |                                                           ,tsTransactions=numberedts | ||||||
|                                                                                          ,tsSelectedAccount=rsSelectedAccount}} st |                                                           ,tsAccount=rsAccount} st | ||||||
|             Nothing -> continue st |             Nothing -> continue st | ||||||
| 
 | 
 | ||||||
|         -- fall through to the list's event handler (handles [pg]up/down) |         -- fall through to the list's event handler (handles [pg]up/down) | ||||||
|         ev                       -> do |         ev                       -> do | ||||||
|                                      newitems <- handleEvent ev rsItems |                                      newitems <- handleEvent ev rsList | ||||||
|                                      continue st{aScreen=s{rsState=rsState{rsItems=newitems}}} |                                      continue st{aScreen=s{rsList=newitems}} | ||||||
|                                      -- continue =<< handleEventLensed st someLens ev |                                      -- continue =<< handleEventLensed st someLens ev | ||||||
| 
 | 
 | ||||||
|     Just ed -> |     Just ed -> | ||||||
| @ -275,4 +274,5 @@ handleRegisterScreen st@AppState{ | |||||||
|     -- Encourage a more stable scroll position when toggling list items (cf AccountsScreen.hs) |     -- Encourage a more stable scroll position when toggling list items (cf AccountsScreen.hs) | ||||||
|     scrollTop = vScrollToBeginning $ viewportScroll "register" |     scrollTop = vScrollToBeginning $ viewportScroll "register" | ||||||
| 
 | 
 | ||||||
| handleRegisterScreen _ _ = error "event handler called with wrong screen type, should not happen" | rsHandle _ _ = error "event handler called with wrong screen type, should not happen" | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ | |||||||
| 
 | 
 | ||||||
| module Hledger.UI.TransactionScreen | module Hledger.UI.TransactionScreen | ||||||
|  (transactionScreen |  (transactionScreen | ||||||
|  |  ,rsSelect | ||||||
|  ) |  ) | ||||||
| where | where | ||||||
| 
 | 
 | ||||||
| @ -37,26 +38,26 @@ import Hledger.UI.ErrorScreen | |||||||
| 
 | 
 | ||||||
| transactionScreen :: Screen | transactionScreen :: Screen | ||||||
| transactionScreen = TransactionScreen{ | transactionScreen = TransactionScreen{ | ||||||
|    tsState   = TransactionScreenState{tsTransaction=(1,nulltransaction) |    sInit   = tsInit | ||||||
|                                      ,tsTransactions=[(1,nulltransaction)] |   ,sDraw   = tsDraw | ||||||
|                                      ,tsSelectedAccount=""} |   ,sHandle = tsHandle | ||||||
|   ,sInitFn   = initTransactionScreen |   ,tsTransaction  = (1,nulltransaction) | ||||||
|   ,sDrawFn   = drawTransactionScreen |   ,tsTransactions = [(1,nulltransaction)] | ||||||
|   ,sHandleFn = handleTransactionScreen |   ,tsAccount      = "" | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| initTransactionScreen :: Day -> Bool -> AppState -> AppState | tsInit :: Day -> Bool -> AppState -> AppState | ||||||
| initTransactionScreen _d _reset st@AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=_ropts}} | tsInit _d _reset st@AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=_ropts}} | ||||||
|                                            ,ajournal=_j |                                            ,ajournal=_j | ||||||
|                                            ,aScreen=TransactionScreen{..}} = st |                                            ,aScreen=TransactionScreen{..}} = st | ||||||
| initTransactionScreen _ _ _ = error "init function called with wrong screen type, should not happen" | tsInit _ _ _ = error "init function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| drawTransactionScreen :: AppState -> [Widget] | tsDraw :: AppState -> [Widget] | ||||||
| drawTransactionScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | tsDraw AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | ||||||
|                               ,aScreen=TransactionScreen{ |                               ,aScreen=TransactionScreen{ | ||||||
|                                   tsState=TransactionScreenState{tsTransaction=(i,t) |                                    tsTransaction=(i,t) | ||||||
|                                                                 ,tsTransactions=nts |                                   ,tsTransactions=nts | ||||||
|                                                                 ,tsSelectedAccount=acct}}} = |                                   ,tsAccount=acct}} = | ||||||
|   [ui] |   [ui] | ||||||
|   where |   where | ||||||
|     -- datedesc = show (tdate t) ++ " " ++ tdescription t |     -- datedesc = show (tdate t) ++ " " ++ tdescription t | ||||||
| @ -96,13 +97,13 @@ drawTransactionScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}} | |||||||
|         -- (if real_ ropts then filterTransactionPostings (Real True) else id) -- filter postings by --real |         -- (if real_ ropts then filterTransactionPostings (Real True) else id) -- filter postings by --real | ||||||
|         t |         t | ||||||
| 
 | 
 | ||||||
| drawTransactionScreen _ = error "draw function called with wrong screen type, should not happen" | tsDraw _ = error "draw function called with wrong screen type, should not happen" | ||||||
| 
 | 
 | ||||||
| handleTransactionScreen :: AppState -> Vty.Event -> EventM (Next AppState) | tsHandle :: AppState -> Vty.Event -> EventM (Next AppState) | ||||||
| handleTransactionScreen | tsHandle | ||||||
|   st@AppState{aScreen=s@TransactionScreen{tsState=tsState@TransactionScreenState{tsTransaction=(i,t) |   st@AppState{aScreen=s@TransactionScreen{tsTransaction=(i,t) | ||||||
|                                                                                 ,tsTransactions=nts |                                          ,tsTransactions=nts | ||||||
|                                                                                 ,tsSelectedAccount=acct}} |                                          ,tsAccount=acct} | ||||||
|              ,aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} |              ,aopts=UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} | ||||||
|              ,ajournal=j |              ,ajournal=j | ||||||
|              } |              } | ||||||
| @ -121,7 +122,7 @@ handleTransactionScreen | |||||||
|       case ej of |       case ej of | ||||||
|         Right j' -> do |         Right j' -> do | ||||||
|           -- got to redo the register screen's transactions report, to get the latest transactions list for this screen |           -- got to redo the register screen's transactions report, to get the latest transactions list for this screen | ||||||
|           -- XXX duplicates initRegisterScreen |           -- XXX duplicates rsInit | ||||||
|           let |           let | ||||||
|             ropts' = ropts {depth_=Nothing |             ropts' = ropts {depth_=Nothing | ||||||
|                            ,balancetype_=HistoricalBalance |                            ,balancetype_=HistoricalBalance | ||||||
| @ -138,31 +139,31 @@ handleTransactionScreen | |||||||
|                          Nothing | null numberedts -> (0,nulltransaction) |                          Nothing | null numberedts -> (0,nulltransaction) | ||||||
|                                  | i > fst (last numberedts) -> last numberedts |                                  | i > fst (last numberedts) -> last numberedts | ||||||
|                                  | otherwise -> head numberedts |                                  | otherwise -> head numberedts | ||||||
|             st' = st{aScreen=s{tsState=TransactionScreenState{tsTransaction=(i',t') |             st' = st{aScreen=s{tsTransaction=(i',t') | ||||||
|                                                              ,tsTransactions=numberedts |                               ,tsTransactions=numberedts | ||||||
|                                                              ,tsSelectedAccount=acct}}} |                               ,tsAccount=acct}} | ||||||
|           continue $ regenerateScreens j' d st' |           continue $ regenerateScreens j' d st' | ||||||
| 
 | 
 | ||||||
|         Left err -> continue $ screenEnter d errorScreen{esState=ErrorScreenState{esError=err}} st |         Left err -> continue $ screenEnter d errorScreen{esError=err} st | ||||||
| 
 | 
 | ||||||
|     -- if allowing toggling here, we should refresh the txn list from the parent register screen |     -- if allowing toggling here, we should refresh the txn list from the parent register screen | ||||||
|     -- Vty.EvKey (Vty.KChar 'E') [] -> continue $ regenerateScreens j d $ stToggleEmpty st |     -- Vty.EvKey (Vty.KChar 'E') [] -> continue $ regenerateScreens j d $ stToggleEmpty st | ||||||
|     -- Vty.EvKey (Vty.KChar 'C') [] -> continue $ regenerateScreens j d $ stToggleCleared st |     -- Vty.EvKey (Vty.KChar 'C') [] -> continue $ regenerateScreens j d $ stToggleCleared st | ||||||
|     -- Vty.EvKey (Vty.KChar 'R') [] -> continue $ regenerateScreens j d $ stToggleReal st |     -- Vty.EvKey (Vty.KChar 'R') [] -> continue $ regenerateScreens j d $ stToggleReal st | ||||||
| 
 | 
 | ||||||
|     Vty.EvKey (Vty.KUp) []       -> continue $ regenerateScreens j d st{aScreen=s{tsState=tsState{tsTransaction=(iprev,tprev)}}} |     Vty.EvKey (Vty.KUp) []       -> continue $ regenerateScreens j d st{aScreen=s{tsTransaction=(iprev,tprev)}} | ||||||
|     Vty.EvKey (Vty.KDown) []     -> continue $ regenerateScreens j d st{aScreen=s{tsState=tsState{tsTransaction=(inext,tnext)}}} |     Vty.EvKey (Vty.KDown) []     -> continue $ regenerateScreens j d st{aScreen=s{tsTransaction=(inext,tnext)}} | ||||||
| 
 | 
 | ||||||
|     Vty.EvKey (Vty.KLeft) []     -> continue st'' |     Vty.EvKey (Vty.KLeft) []     -> continue st'' | ||||||
|       where |       where | ||||||
|         st'@AppState{aScreen=scr} = popScreen st |         st'@AppState{aScreen=scr} = popScreen st | ||||||
|         st'' = st'{aScreen=rsSetSelectedTransaction (fromIntegral i) scr} |         st'' = st'{aScreen=rsSelect (fromIntegral i) scr} | ||||||
| 
 | 
 | ||||||
|     _ev -> continue st |     _ev -> continue st | ||||||
| 
 | 
 | ||||||
| handleTransactionScreen _ _ = error "event handler called with wrong screen type, should not happen" | tsHandle _ _ = error "event handler called with wrong screen type, should not happen" | ||||||
| 
 |  | ||||||
| rsSetSelectedTransaction i scr@RegisterScreen{rsState=rsState@RegisterScreenState{..}} = scr{rsState=rsState{rsItems=l'}} |  | ||||||
|   where l' = listMoveTo (i-1) rsItems |  | ||||||
| rsSetSelectedTransaction _ scr = scr |  | ||||||
| 
 | 
 | ||||||
|  | -- | Select the nth item on the register screen. | ||||||
|  | rsSelect i scr@RegisterScreen{..} = scr{rsList=l'} | ||||||
|  |   where l' = listMoveTo (i-1) rsList | ||||||
|  | rsSelect _ scr = scr | ||||||
|  | |||||||
| @ -1,9 +1,11 @@ | |||||||
| {- | | {- | | ||||||
| Overview: | Overview: | ||||||
| hledger-ui's AppState holds the active screen and any previously visited screens. | hledger-ui's AppState holds the currently active screen and any previously visited | ||||||
| Screens have their own render state, render function, event handler, | screens (and their states). | ||||||
| and app state update function (which can update the whole AppState). | The brick App delegates all event-handling and rendering | ||||||
| A brick App delegates event-handling and rendering to our AppState's active screen. | to the AppState's active screen. | ||||||
|  | Screens have their own screen state, render function, event handler, and app state | ||||||
|  | update function, so they have full control. | ||||||
| 
 | 
 | ||||||
| @ | @ | ||||||
| Brick.defaultMain brickapp st | Brick.defaultMain brickapp st | ||||||
| @ -14,15 +16,15 @@ Brick.defaultMain brickapp st | |||||||
|       , appStartEvent   = return |       , appStartEvent   = return | ||||||
|       , appAttrMap      = const theme |       , appAttrMap      = const theme | ||||||
|       , appChooseCursor = showFirstCursor |       , appChooseCursor = showFirstCursor | ||||||
|       , appHandleEvent  = \st ev -> sHandleFn (aScreen st) st ev |       , appHandleEvent  = \st ev -> sHandle (aScreen st) st ev | ||||||
|       , appDraw         = \st    -> sDrawFn   (aScreen st) st |       , appDraw         = \st    -> sDraw   (aScreen st) st | ||||||
|       } |       } | ||||||
|     st :: AppState |     st :: AppState | ||||||
|     st = (sInitFn scr) d |     st = (sInit s) d | ||||||
|          AppState{ |          AppState{ | ||||||
|             aopts=uopts' |             aopts=uopts' | ||||||
|            ,ajournal=j |            ,ajournal=j | ||||||
|            ,aScreen=scr |            ,aScreen=s | ||||||
|            ,aPrevScreens=prevscrs |            ,aPrevScreens=prevscrs | ||||||
|            ,aMinibuffer=Nothing |            ,aMinibuffer=Nothing | ||||||
|            } |            } | ||||||
| @ -30,9 +32,9 @@ Brick.defaultMain brickapp st | |||||||
| -} | -} | ||||||
| 
 | 
 | ||||||
| {-# LANGUAGE StandaloneDeriving #-} | {-# LANGUAGE StandaloneDeriving #-} | ||||||
| {-# LANGUAGE DeriveAnyClass #-} | {-# LANGUAGE DeriveAnyClass     #-} | ||||||
| {-# LANGUAGE OverloadedStrings #-} | {-# LANGUAGE OverloadedStrings  #-} | ||||||
| {-# LANGUAGE TemplateHaskell #-} | {-# LANGUAGE TemplateHaskell    #-} | ||||||
| 
 | 
 | ||||||
| module Hledger.UI.UITypes where | module Hledger.UI.UITypes where | ||||||
| 
 | 
 | ||||||
| @ -51,63 +53,57 @@ import Text.Show.Functions () | |||||||
| import Hledger | import Hledger | ||||||
| import Hledger.UI.UIOptions | import Hledger.UI.UIOptions | ||||||
| 
 | 
 | ||||||
|  | instance Show (List a) where show _ = "<List>" | ||||||
|  | instance Show Editor   where show _ = "<Editor>" | ||||||
|  | 
 | ||||||
| -- | hledger-ui's application state. This holds one or more stateful screens. | -- | hledger-ui's application state. This holds one or more stateful screens. | ||||||
| data AppState = AppState { | data AppState = AppState { | ||||||
|    aopts        :: UIOpts       -- ^ the command-line options and query arguments currently in effect |    aopts        :: UIOpts       -- ^ the command-line options and query arguments currently in effect | ||||||
|   ,ajournal     :: Journal      -- ^ the journal being viewed |   ,ajournal     :: Journal      -- ^ the journal being viewed | ||||||
|   ,aScreen      :: Screen       -- ^ the currently active screen |   ,aScreen      :: Screen       -- ^ the currently active screen | ||||||
|   ,aPrevScreens :: [Screen]     -- ^ previously visited screens, most recent first |   ,aPrevScreens :: [Screen]     -- ^ previously visited screens, most recent first | ||||||
|   ,aMinibuffer  :: Maybe Editor -- ^ a compact editor used for data entry, when active |   ,aMinibuffer  :: Maybe Editor -- ^ a compact editor, when active, used for data entry on all screens | ||||||
|   } deriving (Show) |   } deriving (Show) | ||||||
| 
 | 
 | ||||||
| -- | Types of screen available within hledger-ui. Each has its own | -- | hledger-ui screen types & instances. | ||||||
| -- specific state type, and generic initialisation, event handling | -- Each screen type has generically named initialisation, draw, and event handling functions, | ||||||
| -- and rendering functions. | -- and zero or more uniquely named screen state fields, which hold the data for a particular | ||||||
| -- | -- instance of this screen. The latter create 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 = | data Screen = | ||||||
|     AccountsScreen { |     AccountsScreen { | ||||||
|        _asState   :: AccountsScreenState |        sInit   :: Day -> Bool -> AppState -> AppState              -- ^ function to update the screen's state | ||||||
|       ,sInitFn   :: Day -> Bool -> AppState -> AppState            -- ^ function to generate the screen's state on entry or change |       ,sDraw   :: AppState -> [Widget]                             -- ^ brick renderer for this screen | ||||||
|       ,sDrawFn   :: AppState -> [Widget]                           -- ^ brick renderer for this screen |       ,sHandle :: AppState -> Vty.Event -> EventM (Next AppState)  -- ^ brick event handler for this screen | ||||||
|       ,sHandleFn :: AppState -> Vty.Event -> EventM (Next AppState)  -- ^ brick event handler for this screen |       -- state fields. These ones have lenses: | ||||||
|  |       ,_asList            :: List AccountsScreenItem  -- ^ list widget showing account names & balances | ||||||
|  |       ,_asSelectedAccount :: AccountName              -- ^ a backup of the account name from the list widget's selected item (or "") | ||||||
|     } |     } | ||||||
|   | RegisterScreen { |   | RegisterScreen { | ||||||
|        rsState   :: RegisterScreenState |        sInit   :: Day -> Bool -> AppState -> AppState | ||||||
|       ,sInitFn   :: Day -> Bool -> AppState -> AppState |       ,sDraw   :: AppState -> [Widget] | ||||||
|       ,sDrawFn   :: AppState -> [Widget] |       ,sHandle :: AppState -> Vty.Event -> EventM (Next AppState) | ||||||
|       ,sHandleFn :: AppState -> Vty.Event -> EventM (Next AppState) |       -- | ||||||
|  |       ,rsList    :: List RegisterScreenItem           -- ^ list widget showing transactions affecting this account | ||||||
|  |       ,rsAccount :: AccountName                       -- ^ the account this register is for | ||||||
|     } |     } | ||||||
|   | TransactionScreen { |   | TransactionScreen { | ||||||
|        tsState   :: TransactionScreenState |        sInit   :: Day -> Bool -> AppState -> AppState | ||||||
|       ,sInitFn   :: Day -> Bool -> AppState -> AppState |       ,sDraw   :: AppState -> [Widget] | ||||||
|       ,sDrawFn   :: AppState -> [Widget] |       ,sHandle :: AppState -> Vty.Event -> EventM (Next AppState) | ||||||
|       ,sHandleFn :: AppState -> Vty.Event -> EventM (Next AppState) |       -- | ||||||
|  |       ,tsTransaction  :: NumberedTransaction          -- ^ the transaction we are currently viewing, and its position in the list | ||||||
|  |       ,tsTransactions :: [NumberedTransaction]        -- ^ list of transactions we can step through | ||||||
|  |       ,tsAccount      :: AccountName                  -- ^ the account whose register we entered this screen from | ||||||
|     } |     } | ||||||
|   | ErrorScreen { |   | ErrorScreen { | ||||||
|        esState   :: ErrorScreenState |        sInit   :: Day -> Bool -> AppState -> AppState | ||||||
|       ,sInitFn   :: Day -> Bool -> AppState -> AppState |       ,sDraw   :: AppState -> [Widget] | ||||||
|       ,sDrawFn   :: AppState -> [Widget] |       ,sHandle :: AppState -> Vty.Event -> EventM (Next AppState) | ||||||
|       ,sHandleFn :: AppState -> Vty.Event -> EventM (Next AppState) |       -- | ||||||
|  |       ,esError :: String                              -- ^ error message to show | ||||||
|     } |     } | ||||||
|   deriving (Show) |   deriving (Show) | ||||||
| 
 | 
 | ||||||
| instance Show (List a) where show _ = "<List>" |  | ||||||
| instance Show Editor   where show _ = "<Editor>" |  | ||||||
| 
 |  | ||||||
| instance Monoid (List a) |  | ||||||
|   where |  | ||||||
|     mempty      = list "" V.empty 1 |  | ||||||
|     mappend a b = a & listElementsL .~ (a^.listElementsL <> b^.listElementsL) |  | ||||||
| 
 |  | ||||||
| -- | Render state for this type of screen. |  | ||||||
| data AccountsScreenState = AccountsScreenState { |  | ||||||
|    _asItems           :: List AccountsScreenItem  -- ^ list of account names & balances |  | ||||||
|   ,_asSelectedAccount :: AccountName              -- ^ full name of the currently selected account (or "") |  | ||||||
|   } deriving (Show) |  | ||||||
| 
 |  | ||||||
| -- | An item in the accounts screen's list of accounts and balances. | -- | An item in the accounts screen's list of accounts and balances. | ||||||
| data AccountsScreenItem = AccountsScreenItem { | data AccountsScreenItem = AccountsScreenItem { | ||||||
|    asItemIndentLevel        :: Int          -- ^ indent level |    asItemIndentLevel        :: Int          -- ^ indent level | ||||||
| @ -116,12 +112,6 @@ data AccountsScreenItem = AccountsScreenItem { | |||||||
|   ,asItemRenderedAmounts    :: [String]     -- ^ rendered amounts |   ,asItemRenderedAmounts    :: [String]     -- ^ rendered amounts | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| -- | Render state for this type of screen. |  | ||||||
| data RegisterScreenState = RegisterScreenState { |  | ||||||
|    rsItems           :: List RegisterScreenItem  -- ^ list of transactions affecting this account |  | ||||||
|   ,rsSelectedAccount :: AccountName              -- ^ full name of the account we are showing a register for |  | ||||||
|   } deriving (Show) |  | ||||||
| 
 |  | ||||||
| -- | An item in the register screen's list of transactions in the current account. | -- | An item in the register screen's list of transactions in the current account. | ||||||
| data RegisterScreenItem = RegisterScreenItem { | data RegisterScreenItem = RegisterScreenItem { | ||||||
|    rsItemDate           :: String           -- ^ date |    rsItemDate           :: String           -- ^ date | ||||||
| @ -132,26 +122,15 @@ data RegisterScreenItem = RegisterScreenItem { | |||||||
|   ,rsItemTransaction    :: Transaction      -- ^ the full transaction |   ,rsItemTransaction    :: Transaction      -- ^ the full transaction | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| -- | Render state for this type of screen. |  | ||||||
| data TransactionScreenState = TransactionScreenState { |  | ||||||
|    tsTransaction     :: NumberedTransaction    -- ^ the transaction we are currently viewing, and its position in the list |  | ||||||
|   ,tsTransactions    :: [NumberedTransaction]  -- ^ the list of transactions we can step through |  | ||||||
|   ,tsSelectedAccount :: AccountName            -- ^ the account whose register we entered this screen from |  | ||||||
|   } deriving (Show) |  | ||||||
| 
 |  | ||||||
| type NumberedTransaction = (Integer, Transaction) | type NumberedTransaction = (Integer, Transaction) | ||||||
| 
 | 
 | ||||||
| -- | Render state for this type of screen. | -- needed for lenses | ||||||
| data ErrorScreenState = ErrorScreenState { | instance Monoid (List a) | ||||||
|                            esError :: String  -- ^ error message to show |   where | ||||||
|   } deriving (Show) |     mempty        = list "" V.empty 1 | ||||||
|  |     mappend l1 l2 = l1 & listElementsL .~ (l1^.listElementsL <> l2^.listElementsL) | ||||||
| 
 | 
 | ||||||
| -- makeLenses ''AccountsScreenState |  | ||||||
| concat <$> mapM makeLenses [ | concat <$> mapM makeLenses [ | ||||||
|    ''AccountsScreenState |    ''Screen | ||||||
| --   ,''RegisterScreenState |  | ||||||
| --   ,''TransactionScreenState |  | ||||||
| --   ,''ErrorScreenState |  | ||||||
|   ,''Screen |  | ||||||
|   ] |   ] | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,33 +1,36 @@ | |||||||
| {-# LANGUAGE OverloadedStrings #-} | {-# LANGUAGE OverloadedStrings #-} | ||||||
|  | {-# LANGUAGE RecordWildCards   #-} | ||||||
| 
 | 
 | ||||||
| module Hledger.UI.UIUtils ( | module Hledger.UI.UIUtils | ||||||
|   pushScreen | --   ( | ||||||
|  ,popScreen | --   pushScreen | ||||||
|  ,resetScreens | --  ,popScreen | ||||||
|  ,screenEnter | --  ,resetScreens | ||||||
|  ,regenerateScreens | --  ,screenEnter | ||||||
|  ,getViewportSize | --  ,regenerateScreens | ||||||
|  -- ,margin | --  ,getViewportSize | ||||||
|  ,withBorderAttr | --  -- ,margin | ||||||
|  ,topBottomBorderWithLabel | --  ,withBorderAttr | ||||||
|  ,topBottomBorderWithLabels | --  ,topBottomBorderWithLabel | ||||||
|  ,defaultLayout | --  ,topBottomBorderWithLabels | ||||||
|  ,borderQueryStr | --  ,defaultLayout | ||||||
|  ,borderDepthStr | --  ,borderQueryStr | ||||||
|  ,borderKeysStr | --  ,borderDepthStr | ||||||
|  ,minibuffer | --  ,borderKeysStr | ||||||
|  -- | --  ,minibuffer | ||||||
|  ,stToggleCleared | --  -- | ||||||
|  ,stTogglePending | --  ,stToggleCleared | ||||||
|  ,stToggleUncleared | --  ,stTogglePending | ||||||
|  ,stToggleEmpty | --  ,stToggleUncleared | ||||||
|  ,stToggleFlat | --  ,stToggleEmpty | ||||||
|  ,stToggleReal | --  ,stToggleFlat | ||||||
|  ,stFilter | --  ,stToggleReal | ||||||
|  ,stResetFilter | --  ,stFilter | ||||||
|  ,stShowMinibuffer | --  ,stResetFilter | ||||||
|  ,stHideMinibuffer | --  ,stShowMinibuffer | ||||||
|  ) where | --  ,stHideMinibuffer | ||||||
|  | --  ) | ||||||
|  |   where | ||||||
| 
 | 
 | ||||||
| import Lens.Micro ((^.)) | import Lens.Micro ((^.)) | ||||||
| -- import Control.Monad | -- import Control.Monad | ||||||
| @ -44,13 +47,10 @@ import Brick.Widgets.Border | |||||||
| import Brick.Widgets.Border.Style | import Brick.Widgets.Border.Style | ||||||
| import Graphics.Vty as Vty | import Graphics.Vty as Vty | ||||||
| 
 | 
 | ||||||
| import Hledger.UI.UITypes | import Hledger | ||||||
| import Hledger.Data.Types (Journal) |  | ||||||
| import Hledger.UI.UIOptions |  | ||||||
| import Hledger.Cli.CliOptions | import Hledger.Cli.CliOptions | ||||||
| import Hledger.Reports.ReportOptions | import Hledger.UI.UITypes | ||||||
| import Hledger.Utils (applyN) | import Hledger.UI.UIOptions | ||||||
| -- import Hledger.Utils.Debug |  | ||||||
| 
 | 
 | ||||||
| -- | Toggle between showing only cleared items or all items. | -- | Toggle between showing only cleared items or all items. | ||||||
| stToggleCleared :: AppState -> AppState | stToggleCleared :: AppState -> AppState | ||||||
| @ -116,6 +116,43 @@ stResetDepth :: AppState -> AppState | |||||||
| stResetDepth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} = | stResetDepth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} = | ||||||
|   st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=Nothing}}}} |   st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=Nothing}}}} | ||||||
| 
 | 
 | ||||||
|  | -- | Get the maximum account depth in the current journal. | ||||||
|  | maxDepth :: AppState -> Int | ||||||
|  | maxDepth AppState{ajournal=j} = maximum $ map accountNameLevel $ journalAccountNames j | ||||||
|  | 
 | ||||||
|  | -- | Decrement the current depth limit towards 0. If there was no depth limit, | ||||||
|  | -- set it to one less than the maximum account depth. | ||||||
|  | decDepth :: AppState -> AppState | ||||||
|  | decDepth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts@ReportOpts{..}}}} | ||||||
|  |   = st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=dec depth_}}}} | ||||||
|  |   where | ||||||
|  |     dec (Just d) = Just $ max 0 (d-1) | ||||||
|  |     dec Nothing  = Just $ maxDepth st - 1 | ||||||
|  | 
 | ||||||
|  | -- | Increment the current depth limit. If this makes it equal to the | ||||||
|  | -- the maximum account depth, remove the depth limit. | ||||||
|  | incDepth :: AppState -> AppState | ||||||
|  | incDepth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts@ReportOpts{..}}}} | ||||||
|  |   = st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=inc depth_}}}} | ||||||
|  |   where | ||||||
|  |     inc (Just d) | d < (maxDepth st - 1) = Just $ d+1 | ||||||
|  |     inc _ = Nothing | ||||||
|  | 
 | ||||||
|  | -- | Set the current depth limit to the specified depth, which should | ||||||
|  | -- be a positive number.  If it is zero, or equal to or greater than the | ||||||
|  | -- current maximum account depth, the depth limit will be removed. | ||||||
|  | -- (Slight inconsistency here: zero is currently a valid display depth | ||||||
|  | -- which can be reached using the - key.  But we need a key to remove | ||||||
|  | -- the depth limit, and 0 is it.) | ||||||
|  | setDepth :: Int -> AppState -> AppState | ||||||
|  | setDepth depth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} | ||||||
|  |   = st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=mdepth'}}}} | ||||||
|  |   where | ||||||
|  |     mdepth' | depth < 0            = depth_ ropts | ||||||
|  |             | depth == 0           = Nothing | ||||||
|  |             | depth >= maxDepth st = Nothing | ||||||
|  |             | otherwise            = Just depth | ||||||
|  | 
 | ||||||
| -- | Enable the minibuffer, setting its content to the current query with the cursor at the end. | -- | Enable the minibuffer, setting its content to the current query with the cursor at the end. | ||||||
| stShowMinibuffer st = st{aMinibuffer=Just e} | stShowMinibuffer st = st{aMinibuffer=Just e} | ||||||
|   where |   where | ||||||
| @ -129,14 +166,14 @@ stHideMinibuffer st = st{aMinibuffer=Nothing} | |||||||
| regenerateScreens :: Journal -> Day -> AppState -> AppState | regenerateScreens :: Journal -> Day -> AppState -> AppState | ||||||
| regenerateScreens j d st@AppState{aScreen=s,aPrevScreens=ss} = | regenerateScreens j d st@AppState{aScreen=s,aPrevScreens=ss} = | ||||||
|   -- XXX clumsy due to entanglement of AppState and Screen. |   -- XXX clumsy due to entanglement of AppState and Screen. | ||||||
|   -- sInitFn operates only on an appstate's current screen, so |   -- sInit operates only on an appstate's current screen, so | ||||||
|   -- remove all the screens from the appstate and then add them back |   -- remove all the screens from the appstate and then add them back | ||||||
|   -- one at a time, regenerating as we go. |   -- one at a time, regenerating as we go. | ||||||
|   let |   let | ||||||
|     first:rest = reverse $ s:ss :: [Screen] |     first:rest = reverse $ s:ss :: [Screen] | ||||||
|     st0 = st{ajournal=j, aScreen=first, aPrevScreens=[]} :: AppState |     st0 = st{ajournal=j, aScreen=first, aPrevScreens=[]} :: AppState | ||||||
|     st1 = (sInitFn first) d False st0 :: AppState |     st1 = (sInit first) d False st0 :: AppState | ||||||
|     st2 = foldl' (\st s -> (sInitFn s) d False $ pushScreen s st) st1 rest :: AppState |     st2 = foldl' (\st s -> (sInit s) d False $ pushScreen s st) st1 rest :: AppState | ||||||
|   in |   in | ||||||
|     st2 |     st2 | ||||||
| 
 | 
 | ||||||
| @ -151,7 +188,7 @@ popScreen st = st | |||||||
| 
 | 
 | ||||||
| resetScreens :: Day -> AppState -> AppState | resetScreens :: Day -> AppState -> AppState | ||||||
| resetScreens d st@AppState{aScreen=s,aPrevScreens=ss} = | resetScreens d st@AppState{aScreen=s,aPrevScreens=ss} = | ||||||
|   (sInitFn topscreen) d True $ stResetDepth $ stResetFilter $ stHideMinibuffer st{aScreen=topscreen, aPrevScreens=[]} |   (sInit topscreen) d True $ stResetDepth $ stResetFilter $ stHideMinibuffer st{aScreen=topscreen, aPrevScreens=[]} | ||||||
|   where |   where | ||||||
|     topscreen = case ss of _:_ -> last ss |     topscreen = case ss of _:_ -> last ss | ||||||
|                            []  -> s |                            []  -> s | ||||||
| @ -162,7 +199,7 @@ resetScreens d st@AppState{aScreen=s,aPrevScreens=ss} = | |||||||
| -- | Enter a new screen, saving the old screen & state in the | -- | Enter a new screen, saving the old screen & state in the | ||||||
| -- navigation history and initialising the new screen's state. | -- navigation history and initialising the new screen's state. | ||||||
| screenEnter :: Day -> Screen -> AppState -> AppState | screenEnter :: Day -> Screen -> AppState -> AppState | ||||||
| screenEnter d scr st = (sInitFn scr) d True $ | screenEnter d scr st = (sInit scr) d True $ | ||||||
|                        pushScreen scr |                        pushScreen scr | ||||||
|                        st |                        st | ||||||
| 
 | 
 | ||||||
| @ -230,7 +267,7 @@ _topBottomBorderWithLabel2 label = \wrapped -> | |||||||
| -- thickness, using the current background colour or the specified | -- thickness, using the current background colour or the specified | ||||||
| -- colour. | -- colour. | ||||||
| -- XXX May disrupt border style of inner widgets. | -- XXX May disrupt border style of inner widgets. | ||||||
| -- XXX Should reduce the available size visible to inner widget, but doesn't seem to (cf drawRegisterScreen2). | -- XXX Should reduce the available size visible to inner widget, but doesn't seem to (cf rsDraw2). | ||||||
| margin :: Int -> Int -> Maybe Color -> Widget -> Widget | margin :: Int -> Int -> Maybe Color -> Widget -> Widget | ||||||
| margin h v mcolour = \w -> | margin h v mcolour = \w -> | ||||||
|   Widget Greedy Greedy $ do |   Widget Greedy Greedy $ do | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user