packages feed

reheat-0.1.5: src/Context.hs

-----------------------------------------------------------------------------
--
-- Module      :  Context
-- Copyright   :  GPL v3
-- License     :  AllRightsReserved
--
-- Maintainer  :  Ingolf Wagner <palipalo9@gmail.com>
-- Stability   :  experimental
-- Portability :
--
-- | Holds all the objects and functions for manipulating them.
-- It should be used as a real programm while View should wire this module to create
-- the UI.
--
-----------------------------------------------------------------------------

module Context where

import Graphics.Vty.Widgets.All
import Graphics.Vty.Attributes
import Graphics.Vty
import Control.Monad
import System.IO
import System.Directory
import Data.IORef
import qualified Data.Text as T

import Task

type TaskViewList         = Widget (List Task Task)
type TaskDescription      = Widget FormattedText
type BreadCrumbWidget     = Widget BreadCrumb
type BreadCrumb           = [Task]


data Context = Context {
    description :: TaskDescription,
    bread       :: BreadCrumbWidget,
    leftList    :: TaskViewList,
    rightList   :: TaskViewList,
    tasks       :: IORef Tasks
    }

-- | create Context out of a file
createContext :: FilePath -> IO Context
createContext filePath = do
    tasks      <- newIORef =<< readFromFile filePath
    leftList   <- newTaskList []
    fullText   <- textWidget wrap $ T.pack "Welcome to Reheat"
    bread      <- newBreadCrumb []
    rightList  <- newTaskList []
    return $ Context fullText bread leftList rightList tasks

-- | creates a new task list
newTaskList :: [Task] -> IO TaskViewList
newTaskList tasks = do
    list <- newList (green `on` black)
    appendTasksToList list tasks
    return list


-- | Append single task to list
appendTask :: Context -> Task -> IO ()
appendTask context task = do
    modifyIORef (tasks context) $ addTask task
    updateLeftList context

-- | updates left list in context
updateLeftList :: Context -> IO ()
updateLeftList context = do
    t <- readIORef $ tasks context
    let ts = actual t
    setList ts (leftList context)
    updateBreadCrumbs context
    return ()

-- | unwrapps the actual task list from the context
actualTaskList :: Context -> IO [Task]
actualTaskList context = do
    t <- readIORef $ tasks context
    return $ actual t

unappendTask :: Int -> Context -> IO ()
unappendTask index context = do
    modifyIORef (tasks context) $ removeTask index
    updateLeftList context

-- | move into task
moveInto :: Task -> Context -> IO ()
moveInto task context = do
    modifyIORef (tasks context) $ goInto task
    updateLeftList context

-- | move out of the actual task list
moveOut :: Context -> IO ()
moveOut context = do
    modifyIORef (tasks context) goOut
    updateLeftList context

swapTasks' :: Int -> Int -> Context -> IO ()
swapTasks' a b context = do
    modifyIORef (tasks context) $ swapTasks a b
    updateLeftList context


-- | clear list and set tasks to that value
setList :: [Task] -> TaskViewList -> IO ()
setList tasks list = do
    clearList list
    appendTasksToList list (reverse tasks)
    setSelected list 0
    return ()

-- | returns the active tasks right now
activeTasks :: Context -> IO [Task]
activeTasks context = do
    l <- readIORef $ tasks context
    return $ actual l


-- | append some tasks to the list
appendTasksToList list tasks =
    forM_ tasks $ \t -> do
        f <- newTask t
        b <- bordered f
        (insertIntoList list t f 0)




{- write and read from and to file here -}


-- | write tasks to file
writeToFile :: FilePath -> IORef Tasks -> IO ()
writeToFile fileName wRef = do
    tasks <- readIORef wRef
    withFile fileName WriteMode $ \h -> do
        hPutStr h (show $ saveTasks tasks)

-- | read from file
readFromFile :: FilePath -> IO Tasks
readFromFile f = do
    exist <- doesFileExist f
    case exist of -- | if is not working here
        False -> do return $ emptyTasks
        True  -> do
            withFile f ReadMode $ \h -> do
                ls <- hGetLine h
                return $ readTasks $ read ls


{- render Task stuff here -}


-- | create a rendarble Task
newTask :: Task -> IO (Widget Task)
newTask t = do
    newWidget t $ \w ->
        w { render_ =  \this region ctx -> do
            elem  <- getState this
            renderTask region ctx elem
          }



-- | Task to Image Renderer
renderTask :: DisplayRegion -> RenderContext -> Task -> IO Image
renderTask region ctx task = do     
    let header            = T.pack $ head . lines . text $ task
        width             = (fromEnum $ region_width region)
        (truncated, _, _) = clip1d (Phys 0) (Phys width) header
    return $ string (getNormalAttr ctx) $ T.unpack truncated



{- bread crumbs here -}


updateBreadCrumbs :: Context -> IO ()
updateBreadCrumbs ctx = do
    t <- readIORef $ tasks ctx
    let newCrumbs = breadCrumbs t
        crumbObject = bread ctx
    setBreadCrumbs newCrumbs crumbObject
    return ()


setBreadCrumbs :: [Task] -> Widget BreadCrumb -> IO ()
setBreadCrumbs t bread = do
    updateWidgetState bread (\a -> t)

newBreadCrumb :: [Task] -> IO (Widget BreadCrumb)
newBreadCrumb tasks = newWidget tasks $ \w ->
    w { render_ = \this region ctx -> do
        listOfTasks <- getState this
        renderBreadCrumb region ctx listOfTasks
      }

renderBreadCrumb :: DisplayRegion -> RenderContext -> BreadCrumb -> IO Image
renderBreadCrumb region ctx bread = do

    return $ string (getNormalAttr ctx) $ renderBread bread ""
    where
        width = (fromEnum $ region_width region)
        renderBread bread acc
            | width     <= (length acc)= drop ((length acc) - width) acc
            | bread == [] && acc == [] = "/"
            | bread == []              = acc
            | otherwise                =
                let header            = T.pack $ head . lines . text . head $ bread
                    (truncated, _, _) = clip1d (Phys 0) (Phys width) header
                    str               = T.unpack truncated
                in renderBread (tail bread) (str ++ " > " ++ acc)