packages feed

mywork-1.0.1.0: lib/Panes/Notes.hs

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

module Panes.Notes () where

import           Brick hiding ( Location )
import           Brick.Panes
import           Brick.Widgets.List
import           Control.Lens
import           Control.Monad ( join )
import qualified Data.List as DL
import qualified Data.Vector as V
import qualified Graphics.Vty as Vty

import           Defs


instance Pane WName MyWorkEvent Note where
  data (PaneState Note MyWorkEvent) = N { nL :: List WName Note
                                        , nLoc :: Maybe Location
                                        }
  type (InitConstraints Note s) = ( HasLocation s
                                  , HasProjects s
                                  , HasSelection s
                                  )
  type (DrawConstraints Note s WName) = ( HasFocus s WName
                                        , HasLocation s
                                        , HasDate s
                                        )
  type (UpdateType Note) = Maybe Location
  initPaneState gs =
    let l = N (list (WName "Notes:List") mempty 1) Nothing
    in flip updatePane l $ join $ snd <$> getCurrentLocation gs
  updatePane mbl ps =
    let curElem = maybe id listMoveTo $ listSelected $ nL ps
        nl =
          case mbl of
            Just l -> curElem
                      . listReplace (V.fromList $ sortNotes $ l^.notesL) (Just 0)
            Nothing -> listReplace mempty Nothing
        sortNotes = DL.sort -- see Ord instance for Note
    in N (nl (nL ps)) mbl
  drawPane ps gs =
    let isFcsd = gs^.getFocus.to focused == Just WNotes
        rndr nt = ttlAttr nt
                  $ str (show (nt ^. notedOnL))
                  <+> txt " -"
                  <+> (if nt ^. noteSourceL == ProjLoc
                      then txt "@ "
                      else txt "- ")
                  <+> ttl nt
        -- KWQ: show indication on Location or Project of expired/todo/inprog?
        ttlAttr nt = case nt ^. noteSourceL of
                       MyWorkDB -> withAttr a'NoteSourceMyWork
                       ProjLoc -> withAttr a'NoteSourceProjLoc
                       MyWorkGenerated -> withAttr a'NoteSourceGenerated
        pendColor present due =
          let ndays = fromEnum due - fromEnum present
              v = min (255::Int) ndays
              r = 255 - v
              g = if v == 0 then 0 else 25 + v `div` 2
              color = Vty.rgbColor r g 0
              amap = forceAttrMap (fg color)
          in updateAttrMap (const amap)
        ttl n = case noteKeyword n of
                  (Just (FUTURE_ d), NoteRemTitle r) ->
                    withAttr a'NoteWordFuture (txt "FUTURE")
                    <+> txt " "
                    <+> (if getToday gs <= d
                          then pendColor (getToday gs) d $ str $ show d
                          else withAttr a'NoteWordExpired $ str $ show d)
                    <+> txt " "
                    <+> txt r
                  (Just (TODO_ d), NoteRemTitle r) ->
                    withAttr a'NoteWordTODO (txt "TODO")
                    <+> txt " "
                    <+> (if getToday gs <= d
                          then pendColor (getToday gs) d $ str $ show d
                          else withAttr a'NoteWordExpired $ str $ show d)
                    <+> txt " "
                    <+> txt r
                  (Just o, NoteRemTitle r) ->
                    withAttr (noteKeywordAttr o) (str $ show o)
                    <+> txt " "
                    <+> txt r
                  (Nothing, NoteRemTitle t) -> txt t
    in Just $ vBox [ withVScrollBars OnRight
                     $ renderList (const rndr) isFcsd (nL ps)
                     -- , hBorder
                   , vLimit 1 (fill '-'
                               <+> str " vv - Full Note - vv "
                               <+> fill '-')
                   , let rndrN nt = vLimit 1 (ttlAttr nt $ ttl nt)
                                    <=>
                                    (vLimitPercent 75
                                     $ withVScrollBars OnRight
                                     $ viewport (WName "Notes:Scroll") Vertical
                                     $ txtWrap
                                     $ noteBody
                                     $ nt)
                         blank = str " "
                     in maybe blank (rndrN . snd) $ listSelectedElement $ nL ps
                   ]
  focusable _ ps = focus1If WNotes $ not $ null $ listElements $ nL ps
  handlePaneEvent _ =
    let scroll o amt = \ps ->
          do _ <- o (viewportScroll (WName "Notes:Scroll")) amt
             return ps
    in \case
      --   * Scroll full note region with CTRL-up/down/page-up/page-down
      Vty.EvKey Vty.KUp [Vty.MCtrl] -> scroll vScrollBy (-1)
      Vty.EvKey Vty.KDown [Vty.MCtrl] -> scroll vScrollBy 1
      Vty.EvKey Vty.KLeft [Vty.MCtrl] -> scroll hScrollBy (-1)
      Vty.EvKey Vty.KRight [Vty.MCtrl] -> scroll hScrollBy 1
      Vty.EvKey Vty.KPageUp [Vty.MCtrl] -> scroll vScrollBy (-10)
      Vty.EvKey Vty.KPageDown [Vty.MCtrl] -> scroll vScrollBy 10
      ev -> nList %%~ \w -> nestEventM' w (handleListEvent ev)


nList :: Lens' (PaneState Note MyWorkEvent) (List WName Note)
nList f ps = (\n -> ps { nL = n }) <$> f (nL ps)


instance HasNote (PaneState Note MyWorkEvent) where
  selectedNote ps = do
    curr <- listSelectedElement $ nL ps
    locn <- nLoc ps
    return ( locn ^. locationL, noteTitle $ snd curr )