{-# LANGUAGE OverloadedStrings #-}
module Miso.Subscription.Canvas
(
canvasSub
) where
import Control.Monad.Reader (runReaderT)
import Control.Monad (void)
import Data.IORef
import Miso.Canvas
import Miso.DSL
import Miso.Effect
import Miso.String
import Miso.Subscription.Util
canvasSub
:: DOMRef
-> MisoString
-> (Double -> model -> Canvas state)
-> Sub model action
canvasSub :: forall model state action.
DOMRef
-> MisoString
-> (Double -> model -> Canvas state)
-> Sub model action
canvasSub DOMRef
canvasRef MisoString
dim Double -> model -> Canvas state
builder Sink action
snk IO model
getModel = do
IO (DOMRef, IORef Int)
-> ((DOMRef, IORef Int) -> IO ()) -> Sub model action
forall a b model action. IO a -> (a -> IO b) -> Sub model action
createSub IO (DOMRef, IORef Int)
acquire (DOMRef, IORef Int) -> IO ()
release Sink action
snk IO model
getModel
where
acquire :: IO (DOMRef, IORef Int)
acquire = do
ctx <- DOMRef
canvasRef DOMRef -> MisoString -> MisoString -> IO DOMRef
forall object args.
(ToObject object, ToArgs args) =>
object -> MisoString -> args -> IO DOMRef
# MisoString
"getContext" (MisoString -> IO DOMRef) -> MisoString -> IO DOMRef
forall a b. (a -> b) -> a -> b
$ MisoString
dim
cbRef <- newIORef (error "canvasSub: uninitialized, impossible")
idRef <- newIORef (0 :: Int)
callback <-
syncCallback1 $ \DOMRef
jsval -> do
IO state -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (IO state -> IO ())
-> (Canvas state -> IO state) -> Canvas state -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Canvas state -> DOMRef -> IO state)
-> DOMRef -> Canvas state -> IO state
forall a b c. (a -> b -> c) -> b -> a -> c
flip Canvas state -> DOMRef -> IO state
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT DOMRef
ctx (Canvas state -> IO ()) -> IO (Canvas state) -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<
Double -> model -> Canvas state
builder (Double -> model -> Canvas state)
-> IO Double -> IO (model -> Canvas state)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> DOMRef -> IO Double
forall a. FromJSVal a => DOMRef -> IO a
fromJSValUnchecked DOMRef
jsval IO (model -> Canvas state) -> IO model -> IO (Canvas state)
forall a b. IO (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> IO model
getModel
IORef Int -> Int -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef Int
idRef (Int -> IO ()) -> IO Int -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< DOMRef -> IO Int
requestAnimationFrame (DOMRef -> IO Int) -> IO DOMRef -> IO Int
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IORef DOMRef -> IO DOMRef
forall a. IORef a -> IO a
readIORef IORef DOMRef
cbRef
writeIORef cbRef callback
writeIORef idRef =<< requestAnimationFrame callback
pure (callback, idRef)
release :: (DOMRef, IORef Int) -> IO ()
release (DOMRef
callback, IORef Int
idRef) = do
Int -> IO ()
cancelAnimationFrame (Int -> IO ()) -> IO Int -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< IORef Int -> IO Int
forall a. IORef a -> IO a
readIORef IORef Int
idRef
Function -> IO ()
freeFunction (DOMRef -> Function
Function DOMRef
callback)