diff --git a/src/TaskMachine/UI.hs b/src/TaskMachine/UI.hs index 432ccbb..3c1c2a1 100644 --- a/src/TaskMachine/UI.hs +++ b/src/TaskMachine/UI.hs @@ -1,14 +1,15 @@ -{-# LANGUAGE RecordWildCards #-} - module TaskMachine.UI where --import Data.Monoid -- -import qualified Brick as B -import qualified Brick.Themes as B -import qualified Brick.Widgets.List as B +import qualified Brick as B +import qualified Brick.Focus as B +import qualified Brick.Themes as B +import qualified Graphics.Vty.Input.Events as VTY +import TaskMachine.UI.NewTask import TaskMachine.UI.TaskList +import TaskMachine.UI.TopBar import TaskMachine.UI.Types --import qualified Database.SQLite.Simple as DB --import qualified Brick.Themes as B @@ -44,13 +45,33 @@ Edit _____________________________ -- [_] display loaded tasks in UI drawUIState :: UIState -> [B.Widget RName] -drawUIState UIState{..} = [B.renderList (renderLTask taskEdit) True taskList] +drawUIState s = + let wTopBar = const placeholderTopBar + wTaskList = renderTaskList (taskList s) (taskEdit s) + wNewTask = const placeholderNewTask + in pure $ case B.focusGetCurrent (focus s) of + Nothing -> B.vBox [wTopBar False, wTaskList False, wNewTask False] -- should never happen + (Just BRTopBar) -> B.vBox [wTopBar True, wTaskList False, wNewTask False] + (Just BRTaskList) -> B.vBox [wTopBar False, wTaskList True, wNewTask False] + (Just BRNewTask) -> B.vBox [wTopBar False, wTaskList False, wNewTask True ] + +updateUIState :: UIState -> B.BrickEvent RName () -> B.EventM RName (B.Next UIState) +updateUIState s e = + case B.focusGetCurrent (focus s) of + Nothing -> undefined + (Just BRTopBar) -> placeholderUpdate s e + (Just BRTaskList) -> updateTaskList s e + (Just BRNewTask) -> placeholderUpdate s e + +placeholderUpdate :: UIState -> B.BrickEvent RName () -> B.EventM RName (B.Next UIState) +placeholderUpdate s (B.VtyEvent (VTY.EvKey VTY.KEsc [])) = B.halt s +placeholderUpdate s _ = B.continue s myApp :: B.Theme -> B.App UIState () RName myApp theme = B.App { B.appDraw = drawUIState - , B.appChooseCursor = B.neverShowCursor - , B.appHandleEvent = B.resizeOrQuit + , B.appChooseCursor = B.showFirstCursor + , B.appHandleEvent = updateUIState , B.appStartEvent = pure , B.appAttrMap = const attrMap } diff --git a/src/TaskMachine/UI/NewTask.hs b/src/TaskMachine/UI/NewTask.hs new file mode 100644 index 0000000..ca119ff --- /dev/null +++ b/src/TaskMachine/UI/NewTask.hs @@ -0,0 +1,8 @@ +module TaskMachine.UI.NewTask where + +import qualified Brick as B + +import TaskMachine.UI.Types + +placeholderNewTask :: B.Widget RName +placeholderNewTask = B.str "New: " B.<+> B.vLimit 1 (B.fill '_') diff --git a/src/TaskMachine/UI/TaskList.hs b/src/TaskMachine/UI/TaskList.hs index 559c2bd..37f99b6 100644 --- a/src/TaskMachine/UI/TaskList.hs +++ b/src/TaskMachine/UI/TaskList.hs @@ -1,9 +1,12 @@ {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} module TaskMachine.UI.TaskList where import qualified Brick as B import qualified Brick.Widgets.Edit as B +import qualified Brick.Widgets.List as B +import qualified Graphics.Vty as VTY import TaskMachine.LTask import TaskMachine.Todotxt @@ -31,10 +34,49 @@ renderLTask highlight (LTask _ Task{..}) = in B.hBox [wCompleted, wPriority, wDescription] -} +--type Editor = B.Editor String RName +--type TaskList = B.List RName LTask + +{- Rendering -} + renderLTask :: Maybe (B.Editor String RName) -> Bool -> LTask -> B.Widget RName -renderLTask _ False (LTask _ t) = B.withAttr normal $ B.str $ formatTask t - where normal = "normal" <> "priority" -renderLTask Nothing True (LTask _ t) = B.withAttr highlight $ B.str $ formatTask t - where highlight = "highlight" <> "priority" -renderLTask (Just edit) True _ = B.withAttr highlight $ B.renderEditor (B.str . unlines) True edit - where highlight = "highlight" <> "priority" +renderLTask _ False (LTask _ t) = B.withAttr "normal" $ B.str $ formatTask t +renderLTask Nothing True (LTask _ t) = B.withAttr "highlight" $ B.str $ formatTask t +renderLTask (Just edit) True _ = B.withAttr "highlight" $ B.renderEditor (B.str . unlines) True edit + +renderTaskList :: B.List RName LTask -> Maybe (B.Editor String RName) -> Bool -> B.Widget RName +renderTaskList taskList edit focus = B.renderList (renderLTask edit) focus taskList + +{- Updating state -} + +updateTaskList :: UIState -> B.BrickEvent RName () -> B.EventM RName (B.Next UIState) +-- Exit application +updateTaskList s@UIState{taskEdit=Nothing} (B.VtyEvent (VTY.EvKey VTY.KEsc [])) = B.halt s +-- Scroll focus +updateTaskList s (B.VtyEvent (VTY.EvKey VTY.KBackTab [])) = B.continue $ bigFocusPrev s +updateTaskList s (B.VtyEvent (VTY.EvKey (VTY.KChar '\t') [])) = B.continue $ bigFocusNext s +-- Start editing the current task +updateTaskList s@UIState{taskEdit=Nothing} (B.VtyEvent (VTY.EvKey (VTY.KChar 'e') [])) = + case B.listSelectedElement (taskList s) of + Nothing -> B.continue s + Just (_, (LTask _ t)) -> + let edit = B.editor RTaskEdit (Just 1) ("- editor test -" ++ formatTask t) + in B.continue s{taskEdit=Just edit} +-- Update the task list +updateTaskList s@UIState{taskEdit=Nothing} (B.VtyEvent e) = do + newList <- B.handleListEventVi B.handleListEvent e (taskList s) + B.continue s{taskList=newList} +-- Exit the editor (losing all changes) +updateTaskList s@UIState{taskEdit=Just _} (B.VtyEvent (VTY.EvKey VTY.KEsc [])) = B.continue $ s{taskEdit=Nothing} +-- Exit the editor (keeping all changes) +updateTaskList s@UIState{taskEdit=Just _} (B.VtyEvent (VTY.EvKey VTY.KEnter [])) = do + let changeTask (LTask n t) = LTask n t{taskDescription="hehe, changed"} + newList = B.listModify changeTask (taskList s) + B.continue s{taskList=newList, taskEdit=Nothing} +-- Update the editor +updateTaskList s@UIState{taskEdit=Just edit} (B.VtyEvent e) = do + newEdit <- B.handleEditorEvent e edit + B.continue s{taskEdit=Just newEdit} +-- Catch everything else +updateTaskList s _ = B.halt s +--updateTaskList list (Just editor) (B.VtyEvent e) = (,) <$> const list <*> B.handleEditorEvent e editor diff --git a/src/TaskMachine/UI/TopBar.hs b/src/TaskMachine/UI/TopBar.hs new file mode 100644 index 0000000..9a4a6c7 --- /dev/null +++ b/src/TaskMachine/UI/TopBar.hs @@ -0,0 +1,6 @@ +module TaskMachine.UI.TopBar where + +import qualified Brick as B + +placeholderTopBar :: B.Widget n +placeholderTopBar = B.str "Prune | Reload | Search: " B.<+> B.vLimit 1 (B.fill '_') diff --git a/src/TaskMachine/UI/Types.hs b/src/TaskMachine/UI/Types.hs index 237a8e8..9063568 100644 --- a/src/TaskMachine/UI/Types.hs +++ b/src/TaskMachine/UI/Types.hs @@ -6,8 +6,12 @@ module TaskMachine.UI.Types ( RName(..) + , BigRing(..) + , SmallRing(..) , UIState(..) , startUIState + , bigFocusNext, bigFocusPrev + , smallFocusNext, smallFocusPrev , defaultTheme ) where @@ -24,6 +28,7 @@ import TaskMachine.LTask data RName = RSearchEdit | RTaskList + | RTaskEdit | RNewEdit deriving (Eq, Show, Ord) @@ -75,6 +80,18 @@ startUIState ltasks = UIState , newEdit = B.editor RNewEdit (Just 1) "" } +bigFocusNext :: UIState -> UIState +bigFocusNext s = s{focus=B.focusNext (focus s)} + +bigFocusPrev :: UIState -> UIState +bigFocusPrev s = s{focus=B.focusPrev (focus s)} + +smallFocusNext :: UIState -> UIState +smallFocusNext s = s{focusTopBar=B.focusNext (focusTopBar s)} + +smallFocusPrev :: UIState -> UIState +smallFocusPrev s = s{focusTopBar=B.focusPrev (focusTopBar s)} + defaultTheme :: B.Theme defaultTheme = B.newTheme VTY.defAttr [ ("normal" , none)