ui: Esc (outside minibuffer) resets, jumps to top

This commit is contained in:
Simon Michael 2016-06-07 09:26:16 -07:00
parent 579ab45d0a
commit bbcbaf6080
7 changed files with 64 additions and 32 deletions

View File

@ -49,8 +49,8 @@ screen = AccountsScreen{
asSetSelectedAccount a scr@AccountsScreen{asState=(l,_)} = scr{asState=(l,a)}
asSetSelectedAccount _ scr = scr
initAccountsScreen :: Day -> AppState -> AppState
initAccountsScreen d st@AppState{
initAccountsScreen :: Day -> Bool -> AppState -> AppState
initAccountsScreen d reset st@AppState{
aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}},
ajournal=j,
aScreen=s@AccountsScreen{asState=(oldl,selacct)}
@ -63,9 +63,10 @@ initAccountsScreen d st@AppState{
-- (may need to move to the next leaf account when entering flat mode)
newl' = listMoveTo selidx newl
where
selidx = case listSelectedElement oldl of
Nothing -> 0
Just (_,(_,a,_,_)) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch
selidx = case (reset, listSelectedElement oldl) of
(True, _) -> 0
(_, Nothing) -> 0
(_, Just (_,(_,a,_,_))) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch
where
mexactmatch = findIndex ((a ==) . second4) displayitems
mprefixmatch = findIndex ((a `isAccountNamePrefixOf`) . second4) displayitems
@ -99,7 +100,7 @@ initAccountsScreen d st@AppState{
displayitems = map displayitem items
initAccountsScreen _ _ = error "init function called with wrong screen type, should not happen"
initAccountsScreen _ _ _ = error "init function called with wrong screen type, should not happen"
drawAccountsScreen :: AppState -> [Widget]
drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
@ -153,6 +154,7 @@ drawAccountsScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
,("/", "filter")
,("DEL", "unfilter")
,("right/enter", "register")
,("ESC", "cancel/top")
,("g", "reload")
,("q", "quit")
]
@ -253,6 +255,7 @@ handleAccountsScreen st@AppState{
case ev of
Vty.EvKey (Vty.KChar 'q') [] -> halt st'
-- Vty.EvKey (Vty.KChar 'l') [Vty.MCtrl] -> do
Vty.EvKey Vty.KEsc [] -> continue $ resetScreens d st'
Vty.EvKey (Vty.KChar 'g') [] -> do
(ej, _) <- liftIO $ journalReloadIfChanged copts d j

View File

@ -33,9 +33,9 @@ screen = ErrorScreen{
,sHandleFn = handleErrorScreen
}
initErrorScreen :: Day -> AppState -> AppState
initErrorScreen _ st@AppState{aScreen=ErrorScreen{}} = st
initErrorScreen _ _ = error "init function called with wrong screen type, should not happen"
initErrorScreen :: Day -> Bool -> AppState -> AppState
initErrorScreen _ _ st@AppState{aScreen=ErrorScreen{}} = st
initErrorScreen _ _ _ = error "init function called with wrong screen type, should not happen"
drawErrorScreen :: AppState -> [Widget]
drawErrorScreen AppState{ -- aopts=_uopts@UIOpts{cliopts_=_copts@CliOpts{reportopts_=_ropts@ReportOpts{query_=querystr}}},
@ -103,12 +103,12 @@ handleErrorScreen st@AppState{
,aopts=UIOpts{cliopts_=copts}
,ajournal=j
} e = do
d <- liftIO getCurrentDay
case e of
Vty.EvKey Vty.KEsc [] -> halt st
Vty.EvKey (Vty.KChar 'q') [] -> halt st
Vty.EvKey Vty.KEsc [] -> continue $ resetScreens d st
Vty.EvKey (Vty.KChar 'g') [] -> do
d <- liftIO getCurrentDay
(ej, _) <- liftIO $ journalReloadIfChanged copts d j
case ej of
Left err -> continue st{aScreen=s{esState=err}} -- show latest parse error

View File

@ -109,7 +109,7 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do
-- Initialising the accounts screen is awkward, requiring
-- another temporary AppState value..
ascr' = aScreen $
AS.initAccountsScreen d $
AS.initAccountsScreen d True $
AppState{
aopts=uopts'
,ajournal=j
@ -118,7 +118,7 @@ runBrickUi uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}} j = do
,aMinibuffer=Nothing
}
st = (sInitFn scr) d
st = (sInitFn scr) d True
AppState{
aopts=uopts'
,ajournal=j

View File

@ -45,8 +45,8 @@ screen = RegisterScreen{
rsSetCurrentAccount a scr@RegisterScreen{rsState=(l,_)} = scr{rsState=(l,a)}
rsSetCurrentAccount _ scr = scr
initRegisterScreen :: Day -> AppState -> AppState
initRegisterScreen d st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScreen{rsState=(oldl,acct)}} =
initRegisterScreen :: Day -> Bool -> AppState -> AppState
initRegisterScreen d reset st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScreen{rsState=(oldl,acct)}} =
st{aScreen=s{rsState=(newl',acct)}}
where
-- gather arguments and queries
@ -86,12 +86,13 @@ initRegisterScreen d st@AppState{aopts=opts, ajournal=j, aScreen=s@RegisterScree
-- (eg after toggling nonzero mode), otherwise select the last element.
newl' = listMoveTo newselidx newl
where
newselidx = case listSelectedElement oldl of
Nothing -> endidx
Just (_,(_,_,_,_,_,Transaction{tindex=ti})) -> fromMaybe endidx $ findIndex ((==ti) . tindex . sixth6) displayitems
newselidx = case (reset, listSelectedElement oldl) of
(True, _) -> 0
(_, Nothing) -> endidx
(_, Just (_,(_,_,_,_,_,Transaction{tindex=ti}))) -> fromMaybe endidx $ findIndex ((==ti) . tindex . sixth6) displayitems
endidx = length displayitems
initRegisterScreen _ _ = error "init function called with wrong screen type, should not happen"
initRegisterScreen _ _ _ = error "init function called with wrong screen type, should not happen"
drawRegisterScreen :: AppState -> [Widget]
drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
@ -182,6 +183,7 @@ drawRegisterScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
,("/", "filter")
,("DEL", "unfilter")
,("right/enter", "transaction")
,("ESC", "cancel/top")
,("g", "reload")
,("q", "quit")
]
@ -228,6 +230,7 @@ handleRegisterScreen st@AppState{
case ev of
Vty.EvKey (Vty.KChar 'q') [] -> halt st
Vty.EvKey Vty.KEsc [] -> continue $ resetScreens d st
Vty.EvKey (Vty.KChar 'g') [] -> do
(ej, _) <- liftIO $ journalReloadIfChanged copts d j

View File

@ -42,13 +42,13 @@ screen = TransactionScreen{
,sHandleFn = handleTransactionScreen
}
initTransactionScreen :: Day -> AppState -> AppState
initTransactionScreen _d st@AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=_ropts}}
initTransactionScreen :: Day -> Bool -> AppState -> AppState
initTransactionScreen _d _reset st@AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=_ropts}}
,ajournal=_j
,aScreen=s@TransactionScreen{tsState=((n,t),nts,a)}} =
st{aScreen=s{tsState=((n,t),nts,a)}}
initTransactionScreen _ _ = error "init function called with wrong screen type, should not happen"
initTransactionScreen _ _ _ = error "init function called with wrong screen type, should not happen"
drawTransactionScreen :: AppState -> [Widget]
drawTransactionScreen AppState{aopts=UIOpts{cliopts_=CliOpts{reportopts_=ropts}}
@ -104,8 +104,8 @@ handleTransactionScreen st@AppState{
(iprev,tprev) = maybe (i,t) ((i-1),) $ lookup (i-1) nts
(inext,tnext) = maybe (i,t) ((i+1),) $ lookup (i+1) nts
case e of
Vty.EvKey Vty.KEsc [] -> halt st
Vty.EvKey (Vty.KChar 'q') [] -> halt st
Vty.EvKey Vty.KEsc [] -> continue $ resetScreens d st
Vty.EvKey (Vty.KChar 'g') [] -> do
d <- liftIO getCurrentDay

View File

@ -70,7 +70,8 @@ data Screen =
)
,AccountName -- full name of the currently selected account (or "")
)
,sInitFn :: Day -> AppState -> AppState -- ^ function to generate the screen's state on entry or change
,sInitFn :: Day -> Bool -> AppState -> AppState -- ^ function to generate/update the screen's state,
-- takes the current date and whether to reset the selection.
,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
}
@ -85,22 +86,22 @@ data Screen =
)
,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
,sInitFn :: Day -> Bool -> AppState -> AppState
,sDrawFn :: AppState -> [Widget]
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
}
| TransactionScreen {
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
,sInitFn :: Day -> Bool -> AppState -> AppState
,sDrawFn :: AppState -> [Widget]
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
}
| ErrorScreen {
esState :: String -- error message to display
,sInitFn :: Day -> AppState -> AppState
,sInitFn :: Day -> Bool -> AppState -> AppState
,sDrawFn :: AppState -> [Widget]
,sHandleFn :: AppState -> V.Event -> EventM (Next AppState)
}

View File

@ -3,6 +3,7 @@
module Hledger.UI.UIUtils (
pushScreen
,popScreen
,resetScreens
,screenEnter
,reload
,getViewportSize
@ -23,6 +24,7 @@ module Hledger.UI.UIUtils (
,stToggleFlat
,stToggleReal
,stFilter
,stResetFilter
,stShowMinibuffer
,stHideMinibuffer
) where
@ -98,6 +100,22 @@ stFilter :: String -> AppState -> AppState
stFilter s st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
st{aopts=uopts{cliopts_=copts{reportopts_=ropts{query_=s}}}}
-- | Clear all filter queries/flags.
stResetFilter :: AppState -> AppState
stResetFilter st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
st{aopts=uopts{cliopts_=copts{reportopts_=ropts{
empty_=True
,cleared_=False
,pending_=False
,uncleared_=False
,real_=False
,query_=""
}}}}
stResetDepth :: AppState -> AppState
stResetDepth st@AppState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
st{aopts=uopts{cliopts_=copts{reportopts_=ropts{depth_=Nothing}}}}
-- | Enable the minibuffer, setting its content to the current query with the cursor at the end.
stShowMinibuffer st = st{aMinibuffer=Just e}
where
@ -117,8 +135,8 @@ reload j d st@AppState{aScreen=s,aPrevScreens=ss} =
let
first:rest = reverse $ s:ss
st0 = st{ajournal=j, aScreen=first, aPrevScreens=[]}
st1 = (sInitFn first) d st0
st2 = foldl' (\st s -> (sInitFn s) d $ pushScreen s st) st1 rest
st1 = (sInitFn first) d False st0
st2 = foldl' (\st s -> (sInitFn s) d False $ pushScreen s st) st1 rest
in
st2
@ -131,13 +149,20 @@ popScreen :: AppState -> AppState
popScreen st@AppState{aPrevScreens=s:ss} = st{aScreen=s, aPrevScreens=ss}
popScreen st = st
resetScreens :: Day -> AppState -> AppState
resetScreens d st@AppState{aScreen=s,aPrevScreens=ss} =
(sInitFn topscreen) d True $ stResetDepth $ stResetFilter $ stHideMinibuffer st{aScreen=topscreen, aPrevScreens=[]}
where
topscreen = case ss of _:_ -> last ss
[] -> s
-- clearScreens :: AppState -> AppState
-- clearScreens st = st{aPrevScreens=[]}
-- | Enter a new screen, saving the old screen & state in the
-- navigation history and initialising the new screen's state.
screenEnter :: Day -> Screen -> AppState -> AppState
screenEnter d scr st = (sInitFn scr) d $
screenEnter d scr st = (sInitFn scr) d True $
pushScreen scr
st