gruff-0.3: src/Progress.hs
module Progress (Progress(..), progressNew, Cont) where
import Control.Monad (forM_, when)
import Graphics.UI.Gtk (Pixbuf)
import Fractal.RUFF.Mandelbrot.Address
import Fractal.RUFF.Mandelbrot.Atom
import Fractal.RUFF.Types.Complex
import Number (R)
import StatusDialog
-- | A continuation gets passed the result.
type Cont a = (Maybe a -> IO ()) -> IO ()
-- | Cancellable actions with status updates.
data Progress = Progress
{ progressLocate :: Complex Rational -> Double -> Cont (MuAtom Rational)
, progressAtom :: AngledInternalAddress -> Cont (MuAtom Rational)
, progressAddress :: MuAtom Rational -> Cont AngledInternalAddress
}
-- | Create a new Progress with a status dialog.
progressNew :: Pixbuf -> IO Progress
progressNew icon = do
-- FIXME this is a horrible hack to avoid race conditions when re-using the same status dialog
sd1 <- statusDialogNew icon
sd2 <- statusDialogNew icon
sd3 <- statusDialogNew icon
return Progress
{ progressLocate = progressLocate' sd1
, progressAtom = progressAtom' sd2
, progressAddress = progressAddress' sd3
}
-- | Much like Fractal.RUFF.Mandelbrot.Atom.locate_
progressLocate' :: StatusDialog -> Complex Rational -> Double -> Cont (MuAtom Rational)
progressLocate' sd (re :+ im) r next = do
statusDialog sd "gruff status" $ \progress' -> do
let c = fromRational re :+ fromRational im :: Complex R
forM_ (locate c r) $ \mp -> case mp of
LocateScanTodo -> progress' "Scanning for period..."
LocateScan -> progress' "Scanning for period..."
LocateScanDone p -> progress'$"Scanning for period... " ++ show p
LocateNucleusTodo -> progress' "Computing nucleus..."
LocateNucleus i -> when (i `mod` 20 == 0) . progress'$"Computing nucleus... " ++ show i
LocateNucleusDone _ -> progress' "Computing nucleus... done"
LocateBondTodo -> progress' "Computing bond..."
LocateBond i -> when (i `mod` 20 == 0) . progress'$"Computing bond... " ++ show i
LocateBondDone _ -> progress' "Computing bond... done"
LocateSuccess mu -> do
progress' "Success!"
let (re' :+ im') = muNucleus mu
next $ Just mu{ muNucleus = toRational re' :+ toRational im' }
LocateFailed -> do
progress' "Failed!"
next $ Nothing
-- | Much like Fractal.RUFF.Mandelbrot.Atom.findAddress_
progressAddress' :: StatusDialog -> MuAtom Rational -> Cont AngledInternalAddress
progressAddress' sd mu next = do
statusDialog sd "gruff status" $ \progress' -> do
let re :+ im = muNucleus mu
c = fromRational re :+ fromRational im :: Complex R
forM_ (findAddress mu{ muNucleus = c }) $ \mp' -> case mp' of
AddressCuspTodo -> progress' "Computing cusp..."
AddressCuspDone _ -> progress' "Computing cusp... done"
AddressDwellTodo -> progress' "Computing dwell..."
AddressDwell i -> when (i `mod` 100 == 0) . progress'$"Computing dwell... " ++ show i
AddressDwellDone _ -> progress' "Computing dwell... done"
AddressRayOutTodo -> progress' "Tracing rays..."
AddressRayOut i -> progress'$"Tracing rays... " ++ show (round $ i * 100 :: Int) ++ "%"
AddressRayOutDone _ -> progress' "Tracing rays... done"
AddressExternalTodo -> progress' "Computing angle..."
AddressExternalDone _ -> progress' "Computing angle... done"
AddressAddressTodo -> progress' "Finding address..."
AddressSuccess a -> do
progress' "Success!"
next $ Just a
AddressFailed -> do
progress' "Failed!"
next $ Nothing
-- | Much like Fractal.RUFF.Mandelbrot.Atom.findAtom_
progressAtom' :: StatusDialog -> AngledInternalAddress -> Cont (MuAtom Rational)
progressAtom' sd addr next = do
statusDialog sd "gruff status" $ \progress' -> do
forM_ (findAtom addr) $ \mp -> case mp of
AtomSplitTodo -> progress' "Splitting address..."
AtomSplitDone _ _ -> progress' "Splitting address... done"
AtomAnglesTodo -> progress' "Computing angles..."
AtomAnglesDone _ _ -> progress' "Computing angles... done"
AtomRayTodo -> progress' "Tracing rays..."
AtomRay n -> when (n `mod` 20 == 0) . progress'$"Tracing rays... " ++ show n
AtomRayDone _ -> progress' "Tracing rays... done"
AtomNucleusTodo -> progress' "Computing nucleus..."
AtomNucleus n -> when (n `mod` 20 == 0) . progress'$"Computing nucleus... " ++ show n
AtomNucleusDone _ -> progress' "Computing nucleus... done"
AtomBondTodo -> progress' "Computing bond..."
AtomBond n -> when (n `mod` 20 == 0) . progress'$"Computing bond... " ++ show n
AtomBondDone _ -> progress' "Computing bond... done"
AtomSuccess mu -> do
progress' "Success!"
let (re' :+ im') = muNucleus mu :: Complex R
next $ Just mu{ muNucleus = toRational re' :+ toRational im' }
AtomFailed -> do
progress' "Failed!"
next $ Nothing