module Graphics.Vty.Widgets.ProgressBar
( ProgressBar
, newProgressBar
, setProgress
, setProgressTextAlignment
, setProgressText
, addProgress
, getProgress
, onProgressChange
)
where
import Control.Monad
import Graphics.Vty
import Graphics.Vty.Widgets.Core
import Graphics.Vty.Widgets.Events
import Graphics.Vty.Widgets.Text
import Graphics.Vty.Widgets.Alignment
data ProgressBar = ProgressBar { progressBarAmount :: Int
, onChangeHandlers :: Handlers Int
, progressBarText :: String
, progressBarTextAlignment :: Alignment
}
instance Show ProgressBar where
show p = concat [ "ProgressBar { "
, ", " ++ (show $ progressBarAmount p)
, ", ... }"
]
newProgressBar :: Attr -> Attr -> IO (Widget ProgressBar)
newProgressBar completeAttr incompleteAttr = do
chs <- newHandlers
t <- plainText ""
let initSt = ProgressBar 0 chs "" AlignCenter
wRef <- newWidget initSt $ \w ->
w { growHorizontal_ = const $ return True
, render_ =
\this size ctx -> do
prog <- progressBarAmount <~~ this
txt <- progressBarText <~~ this
al <- progressBarTextAlignment <~~ this
let complete_width = fromEnum $ (toRational prog / toRational (100.0 :: Double)) *
(toRational $ fromEnum $ region_width size)
full_width = fromEnum $ region_width size
full_str = take full_width $ mkStr txt al
mkStr s AlignLeft = s ++ replicate (full_width length txt) ' '
mkStr s AlignRight = replicate (full_width length txt) ' ' ++ s
mkStr s AlignCenter = concat [ half
, s
, half
, if length half * 2 < (full_width + length txt)
then " "
else ""
]
where
half = replicate ((full_width length txt) `div` 2) ' '
(complete_str, incomplete_str) = ( take complete_width full_str
, drop complete_width full_str
)
setTextWithAttrs t [ (complete_str, completeAttr)
, (incomplete_str, incompleteAttr)
]
render t size ctx
}
setProgress wRef 0
return wRef
onProgressChange :: Widget ProgressBar -> (Int -> IO ()) -> IO ()
onProgressChange = addHandler (onChangeHandlers <~~)
setProgress :: Widget ProgressBar -> Int -> IO ()
setProgress p amt =
when (amt >= 0 && amt <= 100) $ do
updateWidgetState p $ \st -> st { progressBarAmount = amt }
fireEvent p (onChangeHandlers <~~) amt
setProgressTextAlignment :: Widget ProgressBar -> Alignment -> IO ()
setProgressTextAlignment p al =
updateWidgetState p $ \st -> st { progressBarTextAlignment = al }
setProgressText :: Widget ProgressBar -> String -> IO ()
setProgressText p s =
updateWidgetState p $ \st -> st { progressBarText = s }
getProgress :: Widget ProgressBar -> IO Int
getProgress = (progressBarAmount <~~)
addProgress :: Widget ProgressBar -> Int -> IO ()
addProgress p amt = do
cur <- getProgress p
let newAmt = cur + amt
when (newAmt >= 0 && newAmt <= 100) $
setProgress p newAmt