From 5ec3ef8af4249ca0b776027bef47f209d2794883 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Wed, 7 Oct 2020 13:48:09 +0800 Subject: [PATCH 001/114] Add chalkduster to changelog. --- docs/changelog-2020-10.md | 1 + docs/changelog/chalkduster.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 docs/changelog/chalkduster.svg diff --git a/docs/changelog-2020-10.md b/docs/changelog-2020-10.md index 1617c37..99f8f3a 100644 --- a/docs/changelog-2020-10.md +++ b/docs/changelog-2020-10.md @@ -8,3 +8,4 @@ Made it easier to use built-in LaTeX fonts as well as TTF/OTF font files. ![Inconsolata](changelog/inconsolata.svg) ![ComputerModern](changelog/computermodern.svg) ![Magnolia](changelog/magnolia.svg) +![Chalkduster](changelog/chalkduster.svg) diff --git a/docs/changelog/chalkduster.svg b/docs/changelog/chalkduster.svg new file mode 100644 index 0000000..8df3377 --- /dev/null +++ b/docs/changelog/chalkduster.svg @@ -0,0 +1 @@ + \ No newline at end of file From 54652dd51fbaf805b605ac21ab077f50718addd7 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 8 Oct 2020 15:26:02 +0800 Subject: [PATCH 002/114] SimpleIcons.org external data set. (#178) * Add 'simpleIcons' external icon set. * Add complete support for Simple Icons. * Add documentation gif. --- docs/gifs/doc_simpleIcon.gif | Bin 0 -> 4895 bytes src/Reanimate/External.hs | 117 +++++++++++++++++++++++++++++++++-- src/Reanimate/Raster.hs | 2 +- src/Reanimate/Svg/Unuse.hs | 19 +++++- 4 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 docs/gifs/doc_simpleIcon.gif diff --git a/docs/gifs/doc_simpleIcon.gif b/docs/gifs/doc_simpleIcon.gif new file mode 100644 index 0000000000000000000000000000000000000000..9f7880d1fec9e17adb7896b81628122525ea6b7b GIT binary patch literal 4895 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 kYA_V)) +import Reanimate.Raster (mkImage) +import System.Directory (doesDirectoryExist, doesFileExist, findExecutable, getDirectoryContents) +import System.FilePath (splitExtension, (<.>), ()) import System.IO.Unsafe (unsafePerformIO) import System.Process (callProcess) @@ -59,7 +74,7 @@ zipArchive url sha256 = unsafePerformIO $ tarball :: URL -> SHA256 -> FilePath tarball url sha256 = unsafePerformIO $ fetchStaticFile url sha256 $ \folder tarfile -> - callProcess "tar" ["--overwrite", "--one-top-level=" ++ folder, "-xf", tarfile] + callProcess "tar" ["--overwrite", "--one-top-level=" ++ folder, "-xzf", tarfile] downloadFile :: URL -> (FilePath -> IO a) -> IO a downloadFile url action = do @@ -75,12 +90,15 @@ downloadFileCurl curl url action = withTempFile "dl" $ \path -> do callProcess curl [ url, + "--location", "--output", path, "--silent", "--show-error", "--max-filesize", - "10M" + "10M", + "--max-time", + "60" ] action path @@ -93,3 +111,94 @@ downloadFileWget wget url action = withTempFile "dl" $ \path -> do "--quiet" ] action path + + + +------------------------------------------------------------------------------- +-- SimpleIcons + +simpleIconsFolder :: FilePath +simpleIconsFolder = + tarball + "https://github.com/simple-icons/simple-icons/archive/3.11.0.tar.gz" + "NXa8TrHHuQofrPbqTf0pBGt1GDRfuQ4IcQ7kNEk9OcQ=" + "simple-icons-3.11.0" + +{-# NOINLINE simpleIconPath #-} +simpleIconPath :: String -> FilePath +simpleIconPath key = unsafePerformIO $ do + let path = simpleIconsFolder "icons" key <.> "svg" + hit <- doesFileExist path + if hit + then pure path + else error $ "Key not found in simple-icons dataset: " ++ show key + +-- | Icons from . Version 3.11.0. License: CC0 +-- +-- @ +-- let icon = "cplusplus" in `Reanimate.mkGroup` +-- [ `Reanimate.mkBackgroundPixel` (`Codec.Picture.Types.promotePixel` $ `simpleIconColor` icon) +-- , `Reanimate.withFillOpacity` 1 $ `simpleIcon` icon ] +-- @ +-- +-- <> +simpleIcon :: String -> SVG +simpleIcon = mkImage screenWidth screenHeight . simpleIconPath + +-- | Simple Icons svgs do not contain color. Instead, each icon has an associated color value. +simpleIconColor :: String -> PixelRGB8 +simpleIconColor key = + case M.lookup key simpleIconColors of + Nothing -> error $ "Key not found in simple-icons dataset: " ++ show key + Just pixel -> pixel + +-- | Complete list of all Simple Icons. +simpleIconColors :: Map String PixelRGB8 +simpleIconColors = unsafePerformIO $ do + let path = simpleIconsFolder "_data" "simple-icons.json" + mbRet <- decodeFileStrict path + let parsed = do + m <- mbRet + icons <- M.lookup "icons" m + pure $ + M.fromList + [ (fromTitle title, parseHex hex) | icon <- icons, Just title <- [M.lookup "title" icon], Just hex <- [M.lookup "hex" icon] + ] + case parsed of + Nothing -> error "Invalid json in simpleIcons" + Just v -> pure v + where + fromTitle :: String -> String + fromTitle = replaceChars . map toLower + + replaceChars :: String -> String + replaceChars ('.' : x : xs) = "dot-" ++ replaceChars (x : xs) + replaceChars "." = "dot" + replaceChars (x : '.' : []) = replaceChars (x : "-dot") + replaceChars (x : '.' : xs) = replaceChars (x : "-dot-" ++ xs) + replaceChars (x : xs) + | isSpace x || x `elem` "!:'’" = replaceChars xs + replaceChars ('&' : xs) = "-and-" ++ replaceChars xs + replaceChars ('+' : xs) = "plus" ++ replaceChars xs + replaceChars (x : xs) + | x `elem` "àáâãä" = 'a' : replaceChars xs + | x `elem` "ìíîï" = 'i' : replaceChars xs + | x `elem` "èéêë" = 'e' : replaceChars xs + | x `elem` "šś" = 's' : replaceChars xs + replaceChars (x : xs) = x : replaceChars xs + replaceChars [] = [] + parseHex :: String -> PixelRGB8 + parseHex hex = PixelRGB8 (p 0) (p 2) (p 4) + where + p offset = case readHex (take 2 $ drop offset hex) of + [(num, "")] -> num + _ -> error $ "Invalid hex: " ++ (take 2 $ drop offset hex) + +{-# NOINLINE simpleIcons #-} +simpleIcons :: [String] +simpleIcons = unsafePerformIO $ do + let folder = simpleIconsFolder "icons" + files <- getDirectoryContents folder + return $ + sort + [key | file <- files, let (key, ext) = splitExtension file, ext == ".svg"] diff --git a/src/Reanimate/Raster.hs b/src/Reanimate/Raster.hs index e43b777..4a6eb0d 100644 --- a/src/Reanimate/Raster.hs +++ b/src/Reanimate/Raster.hs @@ -87,7 +87,7 @@ mkImage width height path | takeExtension path == ".svg" = unsafePerformIO $ do Just svg -> return $ scaleXY (width / screenWidth) (height / screenHeight) - $ embedDocument svg + $ unboxFit svg mkImage width height path | pRaster == RasterNone = unsafePerformIO $ do inp <- LBS.readFile path let imgData = LBS.unpack $ Base64.encode inp diff --git a/src/Reanimate/Svg/Unuse.hs b/src/Reanimate/Svg/Unuse.hs index 288a5f8..6d9435b 100644 --- a/src/Reanimate/Svg/Unuse.hs +++ b/src/Reanimate/Svg/Unuse.hs @@ -8,6 +8,7 @@ Portability : POSIX module Reanimate.Svg.Unuse ( replaceUses , unbox + , unboxFit , embedDocument ) where @@ -56,13 +57,29 @@ replaceUses doc = doc & documentElements %~ map (mapTree replace) -- FIXME: the viewbox is ignored. Can we use the viewbox as a mask? -- | Transform out viewbox. Definitions and CSS rules are discarded. unbox :: Document -> Tree -unbox doc@Document{_documentViewBox = Just (_minx, _minw, _width, _height)} = +unbox doc@Document{_documentViewBox = Just (_minx, _miny, _width, _height)} = groupTree $ defaultSvg & groupChildren .~ doc^.documentElements unbox doc = groupTree $ defaultSvg & groupChildren .~ doc^.documentElements +-- | Transform out viewbox and fit image to screen size. +unboxFit :: Document -> Tree +unboxFit doc@Document{_documentViewBox = Just (minx, miny, width, height)} = + let widthScale = screenWidth/width + heightScale = screenHeight/height + scaler = min widthScale heightScale + in + scaleXY scaler (-scaler) $ + translate (-minx-width/2) (-miny-height/2) $ + groupTree $ defaultSvg + & groupChildren .~ doc^.documentElements +unboxFit doc = + groupTree $ defaultSvg + & groupChildren .~ doc^.documentElements + + -- | Embed 'Document'. This keeps the entire document intact but makes -- it more difficult to use, say, `Reanimate.Svg.pathify` on it. embedDocument :: Document -> Tree From edd776beacf3d858994da8a5c60f298cd7d0c514 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 8 Oct 2020 15:26:19 +0800 Subject: [PATCH 003/114] Add a few more built-in font configurations. (#179) --- docs/gifs/doc_biolinum.gif | Bin 0 -> 5931 bytes docs/gifs/doc_droidSans.gif | Bin 0 -> 5630 bytes docs/gifs/doc_droidSerif.gif | Bin 0 -> 6049 bytes examples/doc_biolinum.hs | 13 ++++++ examples/doc_droidSans.hs | 13 ++++++ examples/doc_droidSerif.hs | 13 ++++++ src/Reanimate/LaTeX.hs | 75 ++++++++++++++++++++++++++--------- 7 files changed, 95 insertions(+), 19 deletions(-) create mode 100644 docs/gifs/doc_biolinum.gif create mode 100644 docs/gifs/doc_droidSans.gif create mode 100644 docs/gifs/doc_droidSerif.gif create mode 100755 examples/doc_biolinum.hs create mode 100755 examples/doc_droidSans.hs create mode 100755 examples/doc_droidSerif.hs diff --git a/docs/gifs/doc_biolinum.gif b/docs/gifs/doc_biolinum.gif new file mode 100644 index 0000000000000000000000000000000000000000..b91c57c3e81f474572aaafdbc30d05428c7bd01b GIT binary patch literal 5931 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 +biolinum :: TexConfig +biolinum = + TexConfig + { texConfigEngine = LaTeX, + texConfigHeaders = + ["\\usepackage{libertine}" + ,"\\renewcommand{\\familydefault}{\\sfdefault}"], + texConfigPostScript = [] + } + +-- | +-- @ +-- `latexCfg` `droidSerif` "droidSerif" +-- @ +-- +-- <> +droidSerif :: TexConfig +droidSerif = + TexConfig + { texConfigEngine = LaTeX, + texConfigHeaders = + ["\\usepackage[default]{droidserif}" + ,"\\let\\varepsilon\\epsilon"], + texConfigPostScript = [] + } + +-- | +-- @ +-- `latexCfg` `droidSans` "droidSans" +-- @ +-- +-- <> +droidSans :: TexConfig +droidSans = + TexConfig + { texConfigEngine = LaTeX, + texConfigHeaders = + ["\\usepackage[default]{droidsans}" + ,"\\let\\varepsilon\\epsilon"], + texConfigPostScript = [] + } From f14192f6376cb2473fed9de1020d3dbc695131da Mon Sep 17 00:00:00 2001 From: Michal Kukiela Date: Fri, 9 Oct 2020 09:50:16 +0200 Subject: [PATCH 004/114] Move .golden files to a subdirectory. (#78) --- examples/{ => golden}/bug_play1.golden | 0 examples/{ => golden}/bug_play2.golden | 0 examples/{ => golden}/bug_play3.golden | 0 examples/{ => golden}/bug_quad.golden | 0 examples/{ => golden}/counter.golden | 0 examples/{ => golden}/doc_addStatic.golden | 0 examples/{ => golden}/doc_andThen.golden | 0 examples/{ => golden}/doc_applyVar.golden | 0 examples/{ => golden}/doc_bellS.golden | 0 examples/{ => golden}/doc_chainT.golden | 0 examples/{ => golden}/doc_cividis.golden | 0 examples/{ => golden}/doc_constantS.golden | 0 examples/{ => golden}/doc_cubicBezierS.golden | 0 examples/{ => golden}/doc_curveS.golden | 0 examples/{ => golden}/doc_destroySprite.golden | 0 examples/{ => golden}/doc_drawBox.golden | 0 examples/{ => golden}/doc_drawCircle.golden | 0 examples/{ => golden}/doc_drawProgress.golden | 0 examples/{ => golden}/doc_fadeT.golden | 0 examples/{ => golden}/doc_fork.golden | 0 examples/{ => golden}/doc_fromToS.golden | 0 examples/{ => golden}/doc_githubIcon.golden | 0 examples/{ => golden}/doc_greyscale.golden | 0 examples/{ => golden}/doc_haskellLogo.golden | 0 examples/{ => golden}/doc_hsv.golden | 0 examples/{ => golden}/doc_hsvComponents.golden | 0 examples/{ => golden}/doc_hsvMatlab.golden | 0 examples/{ => golden}/doc_inferno.golden | 0 examples/{ => golden}/doc_jet.golden | 0 examples/{ => golden}/doc_labComponents.golden | 0 examples/{ => golden}/doc_latex.golden | 0 examples/{ => golden}/doc_latexAlign.golden | 0 examples/{ => golden}/doc_lchComponents.golden | 0 examples/{ => golden}/doc_magma.golden | 0 examples/{ => golden}/doc_mapA.golden | 0 examples/{ => golden}/doc_mkBackground.golden | 0 examples/{ => golden}/doc_mkText.golden | 0 examples/{ => golden}/doc_newSprite.golden | 0 examples/{ => golden}/doc_newSpriteA'.golden | 0 examples/{ => golden}/doc_newSpriteA.golden | 0 examples/{ => golden}/doc_newSpriteSVG.golden | 0 examples/{ => golden}/doc_oscillateS.golden | 0 examples/{ => golden}/doc_overlapT.golden | 0 examples/{ => golden}/doc_parA.golden | 0 examples/{ => golden}/doc_parDropA.golden | 0 examples/{ => golden}/doc_parLoopA.golden | 0 examples/{ => golden}/doc_parula.golden | 0 examples/{ => golden}/doc_pathify.golden | 0 examples/{ => golden}/doc_pause.golden | 0 examples/{ => golden}/doc_pauseAround.golden | 0 examples/{ => golden}/doc_pauseAtBeginning.golden | 0 examples/{ => golden}/doc_pauseAtEnd.golden | 0 examples/{ => golden}/doc_plasma.golden | 0 examples/{ => golden}/doc_play.golden | 0 examples/{ => golden}/doc_playThenReverseA.golden | 0 examples/{ => golden}/doc_queryNow.golden | 0 examples/{ => golden}/doc_repeatA.golden | 0 examples/{ => golden}/doc_reverseA.golden | 0 examples/{ => golden}/doc_reverseS.golden | 0 examples/{ => golden}/doc_rgbComponents.golden | 0 examples/{ => golden}/doc_seqA.golden | 0 examples/{ => golden}/doc_signalA.golden | 0 examples/{ => golden}/doc_simpleVar.golden | 0 examples/{ => golden}/doc_sinebow.golden | 0 examples/{ => golden}/doc_slideDownT.golden | 0 examples/{ => golden}/doc_slideLeftT.golden | 0 examples/{ => golden}/doc_slideUpT.golden | 0 examples/{ => golden}/doc_spriteE.golden | 0 examples/{ => golden}/doc_spriteMap.golden | 0 examples/{ => golden}/doc_spriteTween.golden | 0 examples/{ => golden}/doc_spriteVar.golden | 0 examples/{ => golden}/doc_spriteZ.golden | 0 examples/{ => golden}/doc_svgLogo.golden | 0 examples/{ => golden}/doc_turbo.golden | 0 examples/{ => golden}/doc_unVar.golden | 0 examples/{ => golden}/doc_viridis.golden | 0 examples/{ => golden}/doc_wait.golden | 0 examples/{ => golden}/doc_waitOn.golden | 0 examples/{ => golden}/doc_withViewBox.golden | 0 examples/{ => golden}/doc_writeVar.golden | 0 examples/{ => golden}/doc_xyzComponents.golden | 0 examples/{ => golden}/goo.golden | 0 examples/{ => golden}/intro_canvas.golden | 0 examples/{ => golden}/intro_canvas_square.golden | 0 examples/{ => golden}/intro_hello.golden | 0 examples/{ => golden}/latex_basic.golden | 0 examples/{ => golden}/raster.golden | 0 reanimate.cabal | 2 +- test/UnitTests.hs | 10 ++++++---- 89 files changed, 7 insertions(+), 5 deletions(-) rename examples/{ => golden}/bug_play1.golden (100%) rename examples/{ => golden}/bug_play2.golden (100%) rename examples/{ => golden}/bug_play3.golden (100%) rename examples/{ => golden}/bug_quad.golden (100%) rename examples/{ => golden}/counter.golden (100%) rename examples/{ => golden}/doc_addStatic.golden (100%) rename examples/{ => golden}/doc_andThen.golden (100%) rename examples/{ => golden}/doc_applyVar.golden (100%) rename examples/{ => golden}/doc_bellS.golden (100%) rename examples/{ => golden}/doc_chainT.golden (100%) rename examples/{ => golden}/doc_cividis.golden (100%) rename examples/{ => golden}/doc_constantS.golden (100%) rename examples/{ => golden}/doc_cubicBezierS.golden (100%) rename examples/{ => golden}/doc_curveS.golden (100%) rename examples/{ => golden}/doc_destroySprite.golden (100%) rename examples/{ => golden}/doc_drawBox.golden (100%) rename examples/{ => golden}/doc_drawCircle.golden (100%) rename examples/{ => golden}/doc_drawProgress.golden (100%) rename examples/{ => golden}/doc_fadeT.golden (100%) rename examples/{ => golden}/doc_fork.golden (100%) rename examples/{ => golden}/doc_fromToS.golden (100%) rename examples/{ => golden}/doc_githubIcon.golden (100%) rename examples/{ => golden}/doc_greyscale.golden (100%) rename examples/{ => golden}/doc_haskellLogo.golden (100%) rename examples/{ => golden}/doc_hsv.golden (100%) rename examples/{ => golden}/doc_hsvComponents.golden (100%) rename examples/{ => golden}/doc_hsvMatlab.golden (100%) rename examples/{ => golden}/doc_inferno.golden (100%) rename examples/{ => golden}/doc_jet.golden (100%) rename examples/{ => golden}/doc_labComponents.golden (100%) rename examples/{ => golden}/doc_latex.golden (100%) rename examples/{ => golden}/doc_latexAlign.golden (100%) rename examples/{ => golden}/doc_lchComponents.golden (100%) rename examples/{ => golden}/doc_magma.golden (100%) rename examples/{ => golden}/doc_mapA.golden (100%) rename examples/{ => golden}/doc_mkBackground.golden (100%) rename examples/{ => golden}/doc_mkText.golden (100%) rename examples/{ => golden}/doc_newSprite.golden (100%) rename examples/{ => golden}/doc_newSpriteA'.golden (100%) rename examples/{ => golden}/doc_newSpriteA.golden (100%) rename examples/{ => golden}/doc_newSpriteSVG.golden (100%) rename examples/{ => golden}/doc_oscillateS.golden (100%) rename examples/{ => golden}/doc_overlapT.golden (100%) rename examples/{ => golden}/doc_parA.golden (100%) rename examples/{ => golden}/doc_parDropA.golden (100%) rename examples/{ => golden}/doc_parLoopA.golden (100%) rename examples/{ => golden}/doc_parula.golden (100%) rename examples/{ => golden}/doc_pathify.golden (100%) rename examples/{ => golden}/doc_pause.golden (100%) rename examples/{ => golden}/doc_pauseAround.golden (100%) rename examples/{ => golden}/doc_pauseAtBeginning.golden (100%) rename examples/{ => golden}/doc_pauseAtEnd.golden (100%) rename examples/{ => golden}/doc_plasma.golden (100%) rename examples/{ => golden}/doc_play.golden (100%) rename examples/{ => golden}/doc_playThenReverseA.golden (100%) rename examples/{ => golden}/doc_queryNow.golden (100%) rename examples/{ => golden}/doc_repeatA.golden (100%) rename examples/{ => golden}/doc_reverseA.golden (100%) rename examples/{ => golden}/doc_reverseS.golden (100%) rename examples/{ => golden}/doc_rgbComponents.golden (100%) rename examples/{ => golden}/doc_seqA.golden (100%) rename examples/{ => golden}/doc_signalA.golden (100%) rename examples/{ => golden}/doc_simpleVar.golden (100%) rename examples/{ => golden}/doc_sinebow.golden (100%) rename examples/{ => golden}/doc_slideDownT.golden (100%) rename examples/{ => golden}/doc_slideLeftT.golden (100%) rename examples/{ => golden}/doc_slideUpT.golden (100%) rename examples/{ => golden}/doc_spriteE.golden (100%) rename examples/{ => golden}/doc_spriteMap.golden (100%) rename examples/{ => golden}/doc_spriteTween.golden (100%) rename examples/{ => golden}/doc_spriteVar.golden (100%) rename examples/{ => golden}/doc_spriteZ.golden (100%) rename examples/{ => golden}/doc_svgLogo.golden (100%) rename examples/{ => golden}/doc_turbo.golden (100%) rename examples/{ => golden}/doc_unVar.golden (100%) rename examples/{ => golden}/doc_viridis.golden (100%) rename examples/{ => golden}/doc_wait.golden (100%) rename examples/{ => golden}/doc_waitOn.golden (100%) rename examples/{ => golden}/doc_withViewBox.golden (100%) rename examples/{ => golden}/doc_writeVar.golden (100%) rename examples/{ => golden}/doc_xyzComponents.golden (100%) rename examples/{ => golden}/goo.golden (100%) rename examples/{ => golden}/intro_canvas.golden (100%) rename examples/{ => golden}/intro_canvas_square.golden (100%) rename examples/{ => golden}/intro_hello.golden (100%) rename examples/{ => golden}/latex_basic.golden (100%) rename examples/{ => golden}/raster.golden (100%) diff --git a/examples/bug_play1.golden b/examples/golden/bug_play1.golden similarity index 100% rename from examples/bug_play1.golden rename to examples/golden/bug_play1.golden diff --git a/examples/bug_play2.golden b/examples/golden/bug_play2.golden similarity index 100% rename from examples/bug_play2.golden rename to examples/golden/bug_play2.golden diff --git a/examples/bug_play3.golden b/examples/golden/bug_play3.golden similarity index 100% rename from examples/bug_play3.golden rename to examples/golden/bug_play3.golden diff --git a/examples/bug_quad.golden b/examples/golden/bug_quad.golden similarity index 100% rename from examples/bug_quad.golden rename to examples/golden/bug_quad.golden diff --git a/examples/counter.golden b/examples/golden/counter.golden similarity index 100% rename from examples/counter.golden rename to examples/golden/counter.golden diff --git a/examples/doc_addStatic.golden b/examples/golden/doc_addStatic.golden similarity index 100% rename from examples/doc_addStatic.golden rename to examples/golden/doc_addStatic.golden diff --git a/examples/doc_andThen.golden b/examples/golden/doc_andThen.golden similarity index 100% rename from examples/doc_andThen.golden rename to examples/golden/doc_andThen.golden diff --git a/examples/doc_applyVar.golden b/examples/golden/doc_applyVar.golden similarity index 100% rename from examples/doc_applyVar.golden rename to examples/golden/doc_applyVar.golden diff --git a/examples/doc_bellS.golden b/examples/golden/doc_bellS.golden similarity index 100% rename from examples/doc_bellS.golden rename to examples/golden/doc_bellS.golden diff --git a/examples/doc_chainT.golden b/examples/golden/doc_chainT.golden similarity index 100% rename from examples/doc_chainT.golden rename to examples/golden/doc_chainT.golden diff --git a/examples/doc_cividis.golden b/examples/golden/doc_cividis.golden similarity index 100% rename from examples/doc_cividis.golden rename to examples/golden/doc_cividis.golden diff --git a/examples/doc_constantS.golden b/examples/golden/doc_constantS.golden similarity index 100% rename from examples/doc_constantS.golden rename to examples/golden/doc_constantS.golden diff --git a/examples/doc_cubicBezierS.golden b/examples/golden/doc_cubicBezierS.golden similarity index 100% rename from examples/doc_cubicBezierS.golden rename to examples/golden/doc_cubicBezierS.golden diff --git a/examples/doc_curveS.golden b/examples/golden/doc_curveS.golden similarity index 100% rename from examples/doc_curveS.golden rename to examples/golden/doc_curveS.golden diff --git a/examples/doc_destroySprite.golden b/examples/golden/doc_destroySprite.golden similarity index 100% rename from examples/doc_destroySprite.golden rename to examples/golden/doc_destroySprite.golden diff --git a/examples/doc_drawBox.golden b/examples/golden/doc_drawBox.golden similarity index 100% rename from examples/doc_drawBox.golden rename to examples/golden/doc_drawBox.golden diff --git a/examples/doc_drawCircle.golden b/examples/golden/doc_drawCircle.golden similarity index 100% rename from examples/doc_drawCircle.golden rename to examples/golden/doc_drawCircle.golden diff --git a/examples/doc_drawProgress.golden b/examples/golden/doc_drawProgress.golden similarity index 100% rename from examples/doc_drawProgress.golden rename to examples/golden/doc_drawProgress.golden diff --git a/examples/doc_fadeT.golden b/examples/golden/doc_fadeT.golden similarity index 100% rename from examples/doc_fadeT.golden rename to examples/golden/doc_fadeT.golden diff --git a/examples/doc_fork.golden b/examples/golden/doc_fork.golden similarity index 100% rename from examples/doc_fork.golden rename to examples/golden/doc_fork.golden diff --git a/examples/doc_fromToS.golden b/examples/golden/doc_fromToS.golden similarity index 100% rename from examples/doc_fromToS.golden rename to examples/golden/doc_fromToS.golden diff --git a/examples/doc_githubIcon.golden b/examples/golden/doc_githubIcon.golden similarity index 100% rename from examples/doc_githubIcon.golden rename to examples/golden/doc_githubIcon.golden diff --git a/examples/doc_greyscale.golden b/examples/golden/doc_greyscale.golden similarity index 100% rename from examples/doc_greyscale.golden rename to examples/golden/doc_greyscale.golden diff --git a/examples/doc_haskellLogo.golden b/examples/golden/doc_haskellLogo.golden similarity index 100% rename from examples/doc_haskellLogo.golden rename to examples/golden/doc_haskellLogo.golden diff --git a/examples/doc_hsv.golden b/examples/golden/doc_hsv.golden similarity index 100% rename from examples/doc_hsv.golden rename to examples/golden/doc_hsv.golden diff --git a/examples/doc_hsvComponents.golden b/examples/golden/doc_hsvComponents.golden similarity index 100% rename from examples/doc_hsvComponents.golden rename to examples/golden/doc_hsvComponents.golden diff --git a/examples/doc_hsvMatlab.golden b/examples/golden/doc_hsvMatlab.golden similarity index 100% rename from examples/doc_hsvMatlab.golden rename to examples/golden/doc_hsvMatlab.golden diff --git a/examples/doc_inferno.golden b/examples/golden/doc_inferno.golden similarity index 100% rename from examples/doc_inferno.golden rename to examples/golden/doc_inferno.golden diff --git a/examples/doc_jet.golden b/examples/golden/doc_jet.golden similarity index 100% rename from examples/doc_jet.golden rename to examples/golden/doc_jet.golden diff --git a/examples/doc_labComponents.golden b/examples/golden/doc_labComponents.golden similarity index 100% rename from examples/doc_labComponents.golden rename to examples/golden/doc_labComponents.golden diff --git a/examples/doc_latex.golden b/examples/golden/doc_latex.golden similarity index 100% rename from examples/doc_latex.golden rename to examples/golden/doc_latex.golden diff --git a/examples/doc_latexAlign.golden b/examples/golden/doc_latexAlign.golden similarity index 100% rename from examples/doc_latexAlign.golden rename to examples/golden/doc_latexAlign.golden diff --git a/examples/doc_lchComponents.golden b/examples/golden/doc_lchComponents.golden similarity index 100% rename from examples/doc_lchComponents.golden rename to examples/golden/doc_lchComponents.golden diff --git a/examples/doc_magma.golden b/examples/golden/doc_magma.golden similarity index 100% rename from examples/doc_magma.golden rename to examples/golden/doc_magma.golden diff --git a/examples/doc_mapA.golden b/examples/golden/doc_mapA.golden similarity index 100% rename from examples/doc_mapA.golden rename to examples/golden/doc_mapA.golden diff --git a/examples/doc_mkBackground.golden b/examples/golden/doc_mkBackground.golden similarity index 100% rename from examples/doc_mkBackground.golden rename to examples/golden/doc_mkBackground.golden diff --git a/examples/doc_mkText.golden b/examples/golden/doc_mkText.golden similarity index 100% rename from examples/doc_mkText.golden rename to examples/golden/doc_mkText.golden diff --git a/examples/doc_newSprite.golden b/examples/golden/doc_newSprite.golden similarity index 100% rename from examples/doc_newSprite.golden rename to examples/golden/doc_newSprite.golden diff --git a/examples/doc_newSpriteA'.golden b/examples/golden/doc_newSpriteA'.golden similarity index 100% rename from examples/doc_newSpriteA'.golden rename to examples/golden/doc_newSpriteA'.golden diff --git a/examples/doc_newSpriteA.golden b/examples/golden/doc_newSpriteA.golden similarity index 100% rename from examples/doc_newSpriteA.golden rename to examples/golden/doc_newSpriteA.golden diff --git a/examples/doc_newSpriteSVG.golden b/examples/golden/doc_newSpriteSVG.golden similarity index 100% rename from examples/doc_newSpriteSVG.golden rename to examples/golden/doc_newSpriteSVG.golden diff --git a/examples/doc_oscillateS.golden b/examples/golden/doc_oscillateS.golden similarity index 100% rename from examples/doc_oscillateS.golden rename to examples/golden/doc_oscillateS.golden diff --git a/examples/doc_overlapT.golden b/examples/golden/doc_overlapT.golden similarity index 100% rename from examples/doc_overlapT.golden rename to examples/golden/doc_overlapT.golden diff --git a/examples/doc_parA.golden b/examples/golden/doc_parA.golden similarity index 100% rename from examples/doc_parA.golden rename to examples/golden/doc_parA.golden diff --git a/examples/doc_parDropA.golden b/examples/golden/doc_parDropA.golden similarity index 100% rename from examples/doc_parDropA.golden rename to examples/golden/doc_parDropA.golden diff --git a/examples/doc_parLoopA.golden b/examples/golden/doc_parLoopA.golden similarity index 100% rename from examples/doc_parLoopA.golden rename to examples/golden/doc_parLoopA.golden diff --git a/examples/doc_parula.golden b/examples/golden/doc_parula.golden similarity index 100% rename from examples/doc_parula.golden rename to examples/golden/doc_parula.golden diff --git a/examples/doc_pathify.golden b/examples/golden/doc_pathify.golden similarity index 100% rename from examples/doc_pathify.golden rename to examples/golden/doc_pathify.golden diff --git a/examples/doc_pause.golden b/examples/golden/doc_pause.golden similarity index 100% rename from examples/doc_pause.golden rename to examples/golden/doc_pause.golden diff --git a/examples/doc_pauseAround.golden b/examples/golden/doc_pauseAround.golden similarity index 100% rename from examples/doc_pauseAround.golden rename to examples/golden/doc_pauseAround.golden diff --git a/examples/doc_pauseAtBeginning.golden b/examples/golden/doc_pauseAtBeginning.golden similarity index 100% rename from examples/doc_pauseAtBeginning.golden rename to examples/golden/doc_pauseAtBeginning.golden diff --git a/examples/doc_pauseAtEnd.golden b/examples/golden/doc_pauseAtEnd.golden similarity index 100% rename from examples/doc_pauseAtEnd.golden rename to examples/golden/doc_pauseAtEnd.golden diff --git a/examples/doc_plasma.golden b/examples/golden/doc_plasma.golden similarity index 100% rename from examples/doc_plasma.golden rename to examples/golden/doc_plasma.golden diff --git a/examples/doc_play.golden b/examples/golden/doc_play.golden similarity index 100% rename from examples/doc_play.golden rename to examples/golden/doc_play.golden diff --git a/examples/doc_playThenReverseA.golden b/examples/golden/doc_playThenReverseA.golden similarity index 100% rename from examples/doc_playThenReverseA.golden rename to examples/golden/doc_playThenReverseA.golden diff --git a/examples/doc_queryNow.golden b/examples/golden/doc_queryNow.golden similarity index 100% rename from examples/doc_queryNow.golden rename to examples/golden/doc_queryNow.golden diff --git a/examples/doc_repeatA.golden b/examples/golden/doc_repeatA.golden similarity index 100% rename from examples/doc_repeatA.golden rename to examples/golden/doc_repeatA.golden diff --git a/examples/doc_reverseA.golden b/examples/golden/doc_reverseA.golden similarity index 100% rename from examples/doc_reverseA.golden rename to examples/golden/doc_reverseA.golden diff --git a/examples/doc_reverseS.golden b/examples/golden/doc_reverseS.golden similarity index 100% rename from examples/doc_reverseS.golden rename to examples/golden/doc_reverseS.golden diff --git a/examples/doc_rgbComponents.golden b/examples/golden/doc_rgbComponents.golden similarity index 100% rename from examples/doc_rgbComponents.golden rename to examples/golden/doc_rgbComponents.golden diff --git a/examples/doc_seqA.golden b/examples/golden/doc_seqA.golden similarity index 100% rename from examples/doc_seqA.golden rename to examples/golden/doc_seqA.golden diff --git a/examples/doc_signalA.golden b/examples/golden/doc_signalA.golden similarity index 100% rename from examples/doc_signalA.golden rename to examples/golden/doc_signalA.golden diff --git a/examples/doc_simpleVar.golden b/examples/golden/doc_simpleVar.golden similarity index 100% rename from examples/doc_simpleVar.golden rename to examples/golden/doc_simpleVar.golden diff --git a/examples/doc_sinebow.golden b/examples/golden/doc_sinebow.golden similarity index 100% rename from examples/doc_sinebow.golden rename to examples/golden/doc_sinebow.golden diff --git a/examples/doc_slideDownT.golden b/examples/golden/doc_slideDownT.golden similarity index 100% rename from examples/doc_slideDownT.golden rename to examples/golden/doc_slideDownT.golden diff --git a/examples/doc_slideLeftT.golden b/examples/golden/doc_slideLeftT.golden similarity index 100% rename from examples/doc_slideLeftT.golden rename to examples/golden/doc_slideLeftT.golden diff --git a/examples/doc_slideUpT.golden b/examples/golden/doc_slideUpT.golden similarity index 100% rename from examples/doc_slideUpT.golden rename to examples/golden/doc_slideUpT.golden diff --git a/examples/doc_spriteE.golden b/examples/golden/doc_spriteE.golden similarity index 100% rename from examples/doc_spriteE.golden rename to examples/golden/doc_spriteE.golden diff --git a/examples/doc_spriteMap.golden b/examples/golden/doc_spriteMap.golden similarity index 100% rename from examples/doc_spriteMap.golden rename to examples/golden/doc_spriteMap.golden diff --git a/examples/doc_spriteTween.golden b/examples/golden/doc_spriteTween.golden similarity index 100% rename from examples/doc_spriteTween.golden rename to examples/golden/doc_spriteTween.golden diff --git a/examples/doc_spriteVar.golden b/examples/golden/doc_spriteVar.golden similarity index 100% rename from examples/doc_spriteVar.golden rename to examples/golden/doc_spriteVar.golden diff --git a/examples/doc_spriteZ.golden b/examples/golden/doc_spriteZ.golden similarity index 100% rename from examples/doc_spriteZ.golden rename to examples/golden/doc_spriteZ.golden diff --git a/examples/doc_svgLogo.golden b/examples/golden/doc_svgLogo.golden similarity index 100% rename from examples/doc_svgLogo.golden rename to examples/golden/doc_svgLogo.golden diff --git a/examples/doc_turbo.golden b/examples/golden/doc_turbo.golden similarity index 100% rename from examples/doc_turbo.golden rename to examples/golden/doc_turbo.golden diff --git a/examples/doc_unVar.golden b/examples/golden/doc_unVar.golden similarity index 100% rename from examples/doc_unVar.golden rename to examples/golden/doc_unVar.golden diff --git a/examples/doc_viridis.golden b/examples/golden/doc_viridis.golden similarity index 100% rename from examples/doc_viridis.golden rename to examples/golden/doc_viridis.golden diff --git a/examples/doc_wait.golden b/examples/golden/doc_wait.golden similarity index 100% rename from examples/doc_wait.golden rename to examples/golden/doc_wait.golden diff --git a/examples/doc_waitOn.golden b/examples/golden/doc_waitOn.golden similarity index 100% rename from examples/doc_waitOn.golden rename to examples/golden/doc_waitOn.golden diff --git a/examples/doc_withViewBox.golden b/examples/golden/doc_withViewBox.golden similarity index 100% rename from examples/doc_withViewBox.golden rename to examples/golden/doc_withViewBox.golden diff --git a/examples/doc_writeVar.golden b/examples/golden/doc_writeVar.golden similarity index 100% rename from examples/doc_writeVar.golden rename to examples/golden/doc_writeVar.golden diff --git a/examples/doc_xyzComponents.golden b/examples/golden/doc_xyzComponents.golden similarity index 100% rename from examples/doc_xyzComponents.golden rename to examples/golden/doc_xyzComponents.golden diff --git a/examples/goo.golden b/examples/golden/goo.golden similarity index 100% rename from examples/goo.golden rename to examples/golden/goo.golden diff --git a/examples/intro_canvas.golden b/examples/golden/intro_canvas.golden similarity index 100% rename from examples/intro_canvas.golden rename to examples/golden/intro_canvas.golden diff --git a/examples/intro_canvas_square.golden b/examples/golden/intro_canvas_square.golden similarity index 100% rename from examples/intro_canvas_square.golden rename to examples/golden/intro_canvas_square.golden diff --git a/examples/intro_hello.golden b/examples/golden/intro_hello.golden similarity index 100% rename from examples/intro_hello.golden rename to examples/golden/intro_hello.golden diff --git a/examples/latex_basic.golden b/examples/golden/latex_basic.golden similarity index 100% rename from examples/latex_basic.golden rename to examples/golden/latex_basic.golden diff --git a/examples/raster.golden b/examples/golden/raster.golden similarity index 100% rename from examples/raster.golden rename to examples/golden/raster.golden diff --git a/reanimate.cabal b/reanimate.cabal index e165a9c..ae0eeab 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -14,7 +14,7 @@ synopsis: Animation library based on SVGs. homepage: https://reanimate.github.io bug-reports: https://github.com/reanimate/reanimate/issues build-type: Simple -extra-source-files: ChangeLog.md, examples/*.hs, examples/*.golden +extra-source-files: ChangeLog.md, examples/*.hs, examples/golden/*.golden extra-doc-files: docs/gifs/*.gif diff --git a/test/UnitTests.hs b/test/UnitTests.hs index 4e7dcdf..ad36b0f 100644 --- a/test/UnitTests.hs +++ b/test/UnitTests.hs @@ -47,7 +47,8 @@ unitTestsDisabled = unitTestFolder :: FilePath -> IO TestTree unitTestFolder _ | unitTestsDisabled = return $ testGroup "animate (disabled)" [] unitTestFolder path = do - files <- sort <$> getDirectoryContents path + let goldenPath = path "golden" + files <- sort <$> getDirectoryContents goldenPath mbWDiff <- findExecutable "wdiff" let diff = case mbWDiff of Nothing -> ["diff", "--strip-trailing-cr"] @@ -55,8 +56,8 @@ unitTestFolder path = do return $ testGroup "animate" [ goldenVsStringDiff file (\ref new -> diff ++ [ref, new]) fullPath (genGolden hsPath) | file <- files - , let fullPath = path file - hsPath = replaceExtension fullPath "hs" + , let fullPath = goldenPath file + hsPath = path replaceExtension file "hs" , takeExtension fullPath == ".golden" ] @@ -81,6 +82,7 @@ compileTestFolder :: FilePath -> IO TestTree compileTestFolder _ | unitTestsDisabled = return $ testGroup "compile (disabled)" [] compileTestFolder path = do files <- sort <$> getDirectoryContents path + goldenFiles <- getDirectoryContents $ path "golden" return $ testGroup "compile" [ testCase file $ do (ret, _stdout, err) <- @@ -95,7 +97,7 @@ compileTestFolder path = do | file <- files , let fullPath = path file , takeExtension file == ".hs" || takeExtension file == ".lhs" - , notElem (replaceExtension file "golden") files + , notElem (replaceExtension file "golden") goldenFiles ] where ghcOpts = ["-fno-code", "-O0", "-Werror", "-Wall"] From 1fa503721c2219bcf1a4f19fd468e4a4e935e1f6 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Fri, 9 Oct 2020 17:24:56 +0800 Subject: [PATCH 005/114] Fix path to golden files. --- .github/workflows/gh-pages.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index d6c497a..6bcfd8a 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -41,9 +41,11 @@ jobs: - name: Generate HPC files run: | set -o xtrace - for gold in examples/*.golden; do - cabal v2-exec --enable-coverage -- ghc -package reanimate "${gold%.golden}.hs" --make - reanimate_datadir=$(pwd) ${gold%.golden} test > /dev/null + for gold in examples/golden/*.golden; do + BASE=examples/$(basename $gold) + BASE=${BASE%.golden} + cabal v2-exec --enable-coverage -- ghc -package reanimate "$BASE.hs" --make + reanimate_datadir=$(pwd) ${BASE%.hs} test > /dev/null done; - name: Merge HPC files From b1cc939dfa2a562d793c2aef9c62b8b156e31d01 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Fri, 9 Oct 2020 17:26:10 +0800 Subject: [PATCH 006/114] Disable HPC badge generation. --- .github/workflows/gh-pages.yml | 52 +++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 6bcfd8a..ba1711e 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -38,36 +38,36 @@ jobs: run: | cabal v2-build --enable-coverage - - name: Generate HPC files - run: | - set -o xtrace - for gold in examples/golden/*.golden; do - BASE=examples/$(basename $gold) - BASE=${BASE%.golden} - cabal v2-exec --enable-coverage -- ghc -package reanimate "$BASE.hs" --make - reanimate_datadir=$(pwd) ${BASE%.hs} test > /dev/null - done; + # - name: Generate HPC files + # run: | + # set -o xtrace + # for gold in examples/golden/*.golden; do + # BASE=examples/$(basename $gold) + # BASE=${BASE%.golden} + # cabal v2-exec --enable-coverage -- ghc -package reanimate "$BASE.hs" --make + # reanimate_datadir=$(pwd) ${BASE%.hs} test > /dev/null + # done; - - name: Merge HPC files - run: hpc sum --union *.tix --output=total.tix + # - name: Merge HPC files + # run: hpc sum --union *.tix --output=total.tix - - name: Report - run: | - hpc report --hpcdir $(find dist-newstyle -name 'hpc')/vanilla/mix/*/ total.tix + # - name: Report + # run: | + # hpc report --hpcdir $(find dist-newstyle -name 'hpc')/vanilla/mix/*/ total.tix - - name: Markup - run: | - hpc markup --destdir=hpc --hpcdir $(find dist-newstyle -name 'hpc')/vanilla/mix/*/ total.tix + # - name: Markup + # run: | + # hpc markup --destdir=hpc --hpcdir $(find dist-newstyle -name 'hpc')/vanilla/mix/*/ total.tix - - name: HPC Badge - run: | - COVERAGE=$(cat hpc/hpc_index.html | tr '\n' ' ' | sed "s/.*Program Coverage Total.*>\([0-9]\{1,3\}\)%.*>\([0-9]\{1,3\}\)%.*>\([0-9]\{1,3\}\)%.*/\1/") - echo "\ - { \"schemaVersion\": 1, \ - \"label\": \"api tests\", \ - \"message\": \"$COVERAGE%\", \ - \"color\": \"success\" \ - }" > hpc/hpc_badge.json + # - name: HPC Badge + # run: | + # COVERAGE=$(cat hpc/hpc_index.html | tr '\n' ' ' | sed "s/.*Program Coverage Total.*>\([0-9]\{1,3\}\)%.*>\([0-9]\{1,3\}\)%.*>\([0-9]\{1,3\}\)%.*/\1/") + # echo "\ + # { \"schemaVersion\": 1, \ + # \"label\": \"api tests\", \ + # \"message\": \"$COVERAGE%\", \ + # \"color\": \"success\" \ + # }" > hpc/hpc_badge.json - name: Haddock Badge run: | From 7d16bc79b05cbaf2bd22c8f4b63e32ce7f24d88f Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Fri, 9 Oct 2020 19:01:44 +0800 Subject: [PATCH 007/114] Rename gh-pages dist folder. --- .github/workflows/gh-pages.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index ba1711e..2416609 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -33,6 +33,7 @@ jobs: run: | cabal v2-update cabal v2-build --enable-coverage --only-dependencies + mkdir pages - name: Build run: | @@ -67,21 +68,21 @@ jobs: # \"label\": \"api tests\", \ # \"message\": \"$COVERAGE%\", \ # \"color\": \"success\" \ - # }" > hpc/hpc_badge.json + # }" > pages/hpc_badge.json - name: Haddock Badge run: | # Stack is required because cabal doesn't build docs for dependencies. # Without those, coverage will not reach 100% stack build --haddock --only-dependencies - stack haddock 2>&1 | grep ") in " | sort -hr > hpc/haddock.txt - COVERAGE=$(awk '{good += $3; total += $5} END {printf "%.0f", good/total*100}' hpc/haddock.txt) + stack haddock 2>&1 | grep ") in " | sort -hr > pages/haddock.txt + COVERAGE=$(awk '{good += $3; total += $5} END {printf "%.0f", good/total*100}' pages/haddock.txt) echo "\ { \"schemaVersion\": 1, \ \"label\": \"api docs\", \ \"message\": \"$COVERAGE%\", \ \"color\": \"success\" \ - }" > hpc/haddock_badge.json + }" > pages/haddock_badge.json # Is there a way to reuse the script from playground.yml? - name: Playground @@ -96,12 +97,12 @@ jobs: cd viewer-elm npm install npm run build - mkdir $CWD/hpc/playground - cp dist/* $CWD/hpc/playground/ + mkdir $CWD/pages/playground + cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 uses: JamesIves/github-pages-deploy-action@3.5.9 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. - FOLDER: hpc # The folder the action should deploy. + FOLDER: pages # The folder the action should deploy. From e9a2bd3bd012aa0e4f3d6918ce8682948636d094 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sat, 10 Oct 2020 15:19:55 +0800 Subject: [PATCH 008/114] Depend on reanimate-svg >= 0.13 --- examples/doc_simpleIcon.hs | 13 ++++++++ reanimate.cabal | 2 +- src/Reanimate/Builtin/Images.hs | 58 ++++++++++++++++++--------------- src/Reanimate/LaTeX.hs | 3 +- src/Reanimate/Raster.hs | 5 +-- stack-lts-13.yaml | 2 +- stack-lts-14.yaml | 2 +- stack-lts-15.yaml | 2 +- stack.yaml | 2 +- 9 files changed, 54 insertions(+), 35 deletions(-) create mode 100755 examples/doc_simpleIcon.hs diff --git a/examples/doc_simpleIcon.hs b/examples/doc_simpleIcon.hs new file mode 100755 index 0000000..6f8bc54 --- /dev/null +++ b/examples/doc_simpleIcon.hs @@ -0,0 +1,13 @@ +#!/usr/bin/env stack +-- stack runghc --package reanimate +module Main(main) where + +import Reanimate +import Reanimate.External +import Codec.Picture.Types + +main :: IO () +main = reanimate $ staticFrame 1 $ + let icon = "cplusplus" in mkGroup + [ mkBackgroundPixel (promotePixel $ simpleIconColor icon) + , withFillOpacity 1 $ simpleIcon icon ] diff --git a/reanimate.cabal b/reanimate.cabal index ae0eeab..0ac331b 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -134,7 +134,7 @@ library process >=1.6.3.0, random >=1.1, random-shuffle >=0.0.4, - reanimate-svg >=0.12.2.0, + reanimate-svg >=0.13.0.0, split >=0.2.3.3, temporary >=1.3, text >=1.2.3.0, diff --git a/src/Reanimate/Builtin/Images.hs b/src/Reanimate/Builtin/Images.hs index d8fbe38..70c2f7b 100644 --- a/src/Reanimate/Builtin/Images.hs +++ b/src/Reanimate/Builtin/Images.hs @@ -1,36 +1,36 @@ -{-| -Module : Reanimate.Builtin.Images -Copyright : Written by David Himmelstrup -License : Unlicense -Maintainer : lemmih@gmail.com -Stability : experimental -Portability : POSIX - -Collection of built-in images. - --} +-- | +-- Module : Reanimate.Builtin.Images +-- Copyright : Written by David Himmelstrup +-- License : Unlicense +-- Maintainer : lemmih@gmail.com +-- Stability : experimental +-- Portability : POSIX +-- +-- Collection of built-in images. module Reanimate.Builtin.Images - ( svgLogo - , haskellLogo - , githubIcon - , githubWhiteIcon - , smallEarth - ) where + ( svgLogo, + haskellLogo, + githubIcon, + githubWhiteIcon, + smallEarth, + ) +where -import Codec.Picture -import qualified Data.ByteString as B -import Graphics.SvgTree (parseSvgFile) -import Paths_reanimate -import Reanimate.Animation -import Reanimate.Svg -import System.IO.Unsafe +import Codec.Picture +import qualified Data.ByteString as B +import qualified Data.Text.IO as T +import Graphics.SvgTree (parseSvgFile) +import Paths_reanimate +import Reanimate.Animation +import Reanimate.Svg +import System.IO.Unsafe embedImage :: FilePath -> IO SVG embedImage key = do svg_file <- getDataFileName key - svg_data <- B.readFile svg_file + svg_data <- T.readFile svg_file case parseSvgFile svg_file svg_data of - Nothing -> error "Malformed svg" + Nothing -> error "Malformed svg" Just svg -> return $ embedDocument svg loadJPG :: FilePath -> Image PixelRGBA8 @@ -38,25 +38,29 @@ loadJPG key = unsafePerformIO $ do jpg_file <- getDataFileName key dat <- B.readFile jpg_file case decodeJpeg dat of - Left err -> error err + Left err -> error err Right img -> return $ convertRGBA8 img {- HLINT ignore svgLogo -} + -- | <> svgLogo :: SVG svgLogo = unsafePerformIO $ embedImage "data/svg-logo.svg" {- HLINT ignore haskellLogo -} + -- | <> haskellLogo :: SVG haskellLogo = unsafePerformIO $ embedImage "data/haskell.svg" {- HLINT ignore githubIcon -} + -- | <> githubIcon :: SVG githubIcon = unsafePerformIO $ embedImage "data/github-icon.svg" {-# NOINLINE githubWhiteIcon #-} + -- | <> githubWhiteIcon :: SVG githubWhiteIcon = unsafePerformIO $ embedImage "data/github-icon-white.svg" diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index 4123ad5..e065c02 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -41,6 +41,7 @@ import Data.Hashable import Data.Monoid import Data.Text (Text) import qualified Data.Text as T +import qualified Data.Text.IO as T import qualified Data.Text.Encoding as T import GHC.Generics (Generic) import Graphics.SvgTree @@ -227,7 +228,7 @@ latexToSVG engine dviExt latexExec latexArgs tex = do "-o", svg_file ] - svg_data <- B.readFile svg_file + svg_data <- T.readFile svg_file case parseSvgFile svg_file svg_data of Nothing -> error "Malformed svg" Just svg -> diff --git a/src/Reanimate/Raster.hs b/src/Reanimate/Raster.hs index 4a6eb0d..ca0a7e0 100644 --- a/src/Reanimate/Raster.hs +++ b/src/Reanimate/Raster.hs @@ -36,6 +36,7 @@ import qualified Data.ByteString.Base64.Lazy as Base64 import qualified Data.ByteString.Lazy.Char8 as LBS import Data.Hashable import qualified Data.Text as T +import qualified Data.Text.IO as T import Graphics.SvgTree ( Number(..) , defaultSvg , parseSvgFile @@ -81,7 +82,7 @@ mkImage -> FilePath -- ^ Path to external image file. -> SVG mkImage width height path | takeExtension path == ".svg" = unsafePerformIO $ do - svg_data <- B.readFile path + svg_data <- T.readFile path case parseSvgFile path svg_data of Nothing -> error "Malformed svg" Just svg -> @@ -273,7 +274,7 @@ vectorize_ args path = unsafePerformIO $ do runCmd magick [path, "-flatten", tmpBmpPath] runCmd potrace (args ++ ["--svg", "--output", tmpSvgPath, tmpBmpPath]) renameOrCopyFile tmpSvgPath svgPath - svg_data <- B.readFile svgPath + svg_data <- T.readFile svgPath case parseSvgFile svgPath svg_data of Nothing -> do removeFile svgPath diff --git a/stack-lts-13.yaml b/stack-lts-13.yaml index 90307a9..695e158 100644 --- a/stack-lts-13.yaml +++ b/stack-lts-13.yaml @@ -6,7 +6,7 @@ packages: - . extra-deps: -- reanimate-svg-0.12.2.0 +- reanimate-svg-0.13.0.0 - chiphunk-0.1.2.1 - cubicbezier-0.6.0.6@sha256:2191ff47144d9a13a2784651a33d340cd31be1926a6c188925143103eb3c8db3 - fast-math-1.0.2@sha256:91181eb836e54413cc5a841e797c42b2264954e893ea530b6fc4da0dccf6a8b7 diff --git a/stack-lts-14.yaml b/stack-lts-14.yaml index 76bbcfb..2b39b0a 100644 --- a/stack-lts-14.yaml +++ b/stack-lts-14.yaml @@ -6,7 +6,7 @@ packages: - . extra-deps: -- reanimate-svg-0.12.2.0 +- reanimate-svg-0.13.0.0 - chiphunk-0.1.2.1 - cubicbezier-0.6.0.6@sha256:2191ff47144d9a13a2784651a33d340cd31be1926a6c188925143103eb3c8db3 - fast-math-1.0.2@sha256:91181eb836e54413cc5a841e797c42b2264954e893ea530b6fc4da0dccf6a8b7 diff --git a/stack-lts-15.yaml b/stack-lts-15.yaml index aea97b5..b672188 100644 --- a/stack-lts-15.yaml +++ b/stack-lts-15.yaml @@ -8,7 +8,7 @@ packages: extra-deps: - chiphunk-0.1.2.1 - earcut-0.1.0.4@sha256:d5118b3eecf24d130263d81fb30f1ff56b1db43036582bfd1d8cc9ba3adae8be,1010 -- reanimate-svg-0.12.2.0 +- reanimate-svg-0.13.0.0 - hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 - hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/stack.yaml b/stack.yaml index 520043a..addd26d 100644 --- a/stack.yaml +++ b/stack.yaml @@ -7,7 +7,7 @@ packages: extra-deps: - earcut-0.1.0.4 -- reanimate-svg-0.12.2.0 +- reanimate-svg-0.13.0.0 - hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 - hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 From 96cd95f8650161dfa895982b7f6985d47238fb00 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sat, 10 Oct 2020 17:25:15 +0800 Subject: [PATCH 009/114] Add logos from svgporn.com --- docs/gifs/doc_svgLogo.gif | Bin 6487 -> 15435 bytes examples/doc_svgLogo.hs | 14 ++++++++++---- src/Reanimate/External.hs | 39 +++++++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/docs/gifs/doc_svgLogo.gif b/docs/gifs/doc_svgLogo.gif index 59f14cc16d5ba314f226bab9dfc4e4239674e415..78b3ef1f833e2bfe2c36f3568aed7e99a67eae01 100644 GIT binary patch literal 15435 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 My2t-xV{rL@0CHU$od5s; literal 6487 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 diff --git a/examples/doc_svgLogo.hs b/examples/doc_svgLogo.hs index 6305b34..5c9d877 100755 --- a/examples/doc_svgLogo.hs +++ b/examples/doc_svgLogo.hs @@ -1,10 +1,16 @@ #!/usr/bin/env stack -- stack runghc --package reanimate + module Main (main) where -import Reanimate -import Reanimate.Builtin.Documentation -import Reanimate.Builtin.Images +import Codec.Picture.Types +import Reanimate +import Reanimate.Builtin.Documentation +import Reanimate.External main :: IO () -main = reanimate $ docEnv $ animate $ const svgLogo +main = + reanimate $ + docEnv $ + staticFrame 1 $ + withFillOpacity 1 $ svgLogo "cassandra" diff --git a/src/Reanimate/External.hs b/src/Reanimate/External.hs index fd3e788..ee9b63b 100644 --- a/src/Reanimate/External.hs +++ b/src/Reanimate/External.hs @@ -8,6 +8,8 @@ module Reanimate.External simpleIcon, simpleIconColor, simpleIcons, + svgLogo, + svgLogos, ) where @@ -133,7 +135,7 @@ simpleIconPath key = unsafePerformIO $ do then pure path else error $ "Key not found in simple-icons dataset: " ++ show key --- | Icons from . Version 3.11.0. License: CC0 +-- | Icons from . Version 3.11.0. License: CC0 -- -- @ -- let icon = "cplusplus" in `Reanimate.mkGroup` @@ -202,3 +204,38 @@ simpleIcons = unsafePerformIO $ do return $ sort [key | file <- files, let (key, ext) = splitExtension file, ext == ".svg"] + + +svgLogosFolder :: FilePath +svgLogosFolder = tarball + "https://github.com/gilbarbara/logos/archive/2018.01.tar.gz" + "kRRA0cF6sVOyqtfVW8EMew4OB4WJcY81DEGS3FLEY8Y=" + "logos-2018.01" "logos" + +{-# NOINLINE svgLogoPath #-} +svgLogoPath :: String -> FilePath +svgLogoPath key = unsafePerformIO $ do + let path = svgLogosFolder key <.> "svg" + hit <- doesFileExist path + if hit + then pure path + else error $ "Key not found in svg logos dataset: " ++ show key + +-- | Icons from . Version 3.11.0. License: CC0 +-- +-- @ +-- `svgLogo` "cassandra" +-- @ +-- +-- <> +svgLogo :: String -> SVG +svgLogo = mkImage screenWidth screenHeight . svgLogoPath + +{-# NOINLINE svgLogos #-} +-- | Complete list of all SVG Icons. +svgLogos :: [String] +svgLogos = unsafePerformIO $ do + files <- getDirectoryContents svgLogosFolder + return $ + sort + [key | file <- files, let (key, ext) = splitExtension file, ext == ".svg"] \ No newline at end of file From e7bce27d1249403f988cf3fbc43990060576f713 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sat, 10 Oct 2020 18:17:01 +0800 Subject: [PATCH 010/114] Switch back to stylish-haskell and enumerate imports. --- docs/gifs/doc_svgLogo.gif | Bin 15435 -> 7255 bytes docs/gifs/doc_svgLogo2.gif | Bin 0 -> 15435 bytes examples/doc_svgLogo.hs | 14 ++--- examples/doc_svgLogo2.hs | 15 ++++++ src/Reanimate/Animation.hs | 11 ++-- src/Reanimate/Blender.hs | 16 +++--- src/Reanimate/Builtin/CirclePlot.hs | 14 ++--- src/Reanimate/Builtin/Documentation.hs | 10 ++-- src/Reanimate/Builtin/Images.hs | 20 +++---- src/Reanimate/Builtin/Slide.hs | 8 +-- src/Reanimate/Builtin/TernaryPlot.hs | 6 +-- src/Reanimate/Cache.hs | 22 ++++---- src/Reanimate/ColorComponents.hs | 18 +++---- src/Reanimate/ColorMap.hs | 16 +++--- src/Reanimate/Constants.hs | 2 +- src/Reanimate/Debug.hs | 19 +++---- src/Reanimate/Driver/CLI.hs | 26 +++++---- src/Reanimate/Driver/Check.hs | 16 +++--- src/Reanimate/External.hs | 55 +++++++++---------- src/Reanimate/LaTeX.hs | 71 ++++++++++--------------- src/Reanimate/Memo.hs | 14 ++--- src/Reanimate/Misc.hs | 51 ++++++------------ src/Reanimate/Parameters.hs | 4 +- src/Reanimate/PolyShape.hs | 2 +- src/Reanimate/Povray.hs | 14 ++--- src/Reanimate/Raster.hs | 59 ++++++++++---------- src/Reanimate/Render.hs | 20 +++---- src/Reanimate/Scene/Core.hs | 10 ++-- src/Reanimate/Scene/Object.hs | 70 +++++++++++------------- src/Reanimate/Scene/Sprite.hs | 46 +++++----------- src/Reanimate/Scene/Var.hs | 22 ++++---- src/Reanimate/Svg.hs | 18 +++---- src/Reanimate/Svg/BoundingBox.hs | 22 ++++---- src/Reanimate/Svg/Constructors.hs | 10 ++-- src/Reanimate/Svg/LineCommand.hs | 53 +++++++++--------- src/Reanimate/Svg/Unuse.hs | 11 ++-- src/Reanimate/Transform.hs | 14 ++--- src/Reanimate/Transition.hs | 9 ++-- src/Reanimate/Voice.hs | 44 +++++++-------- 39 files changed, 404 insertions(+), 448 deletions(-) create mode 100644 docs/gifs/doc_svgLogo2.gif mode change 100755 => 100644 examples/doc_svgLogo.hs create mode 100755 examples/doc_svgLogo2.hs diff --git a/docs/gifs/doc_svgLogo.gif b/docs/gifs/doc_svgLogo.gif index 78b3ef1f833e2bfe2c36f3568aed7e99a67eae01..6c2fadafd8fbccc90df23454982ac6a185b28104 100644 GIT binary patch literal 7255 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 My2t-xV{rL@0CHU$od5s; diff --git a/docs/gifs/doc_svgLogo2.gif b/docs/gifs/doc_svgLogo2.gif new file mode 100644 index 0000000000000000000000000000000000000000..78b3ef1f833e2bfe2c36f3568aed7e99a67eae01 GIT binary patch literal 15435 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 My2t-xV{rL@0CHU$od5s; literal 0 HcmV?d00001 diff --git a/examples/doc_svgLogo.hs b/examples/doc_svgLogo.hs old mode 100755 new mode 100644 index 5c9d877..6305b34 --- a/examples/doc_svgLogo.hs +++ b/examples/doc_svgLogo.hs @@ -1,16 +1,10 @@ #!/usr/bin/env stack -- stack runghc --package reanimate - module Main (main) where -import Codec.Picture.Types -import Reanimate -import Reanimate.Builtin.Documentation -import Reanimate.External +import Reanimate +import Reanimate.Builtin.Documentation +import Reanimate.Builtin.Images main :: IO () -main = - reanimate $ - docEnv $ - staticFrame 1 $ - withFillOpacity 1 $ svgLogo "cassandra" +main = reanimate $ docEnv $ animate $ const svgLogo diff --git a/examples/doc_svgLogo2.hs b/examples/doc_svgLogo2.hs new file mode 100755 index 0000000..519fe24 --- /dev/null +++ b/examples/doc_svgLogo2.hs @@ -0,0 +1,15 @@ +#!/usr/bin/env stack +-- stack runghc --package reanimate + +module Main (main) where + +import Reanimate +import Reanimate.Builtin.Documentation +import Reanimate.External + +main :: IO () +main = + reanimate $ + docEnv $ + staticFrame 1 $ + withFillOpacity 1 $ svgLogo "cassandra" diff --git a/src/Reanimate/Animation.hs b/src/Reanimate/Animation.hs index 43e55c1..315c7b2 100644 --- a/src/Reanimate/Animation.hs +++ b/src/Reanimate/Animation.hs @@ -53,14 +53,13 @@ module Reanimate.Animation , renderSvg ) where -import Control.Arrow () import Data.Fixed (mod') import Graphics.SvgTree -import Graphics.SvgTree.Printer -import Reanimate.Constants -import Reanimate.Ease -import Reanimate.Svg.Constructors -import Text.XML.Light.Output +import Graphics.SvgTree.Printer (ppDocument) +import Reanimate.Constants (defaultStrokeWidth) +import Reanimate.Ease (Signal, reverseS) +import Reanimate.Svg.Constructors (mkGroup, scaleXY, withStrokeWidth) +import Text.XML.Light.Output (ppElement) -- | Duration of an animation or effect. Usually measured in seconds. type Duration = Double diff --git a/src/Reanimate/Blender.hs b/src/Reanimate/Blender.hs index 6935339..2e66375 100644 --- a/src/Reanimate/Blender.hs +++ b/src/Reanimate/Blender.hs @@ -36,17 +36,17 @@ module Reanimate.Blender , blender' ) where -import Data.Hashable +import Data.Hashable (Hashable (hash)) import Data.Text (Text) import qualified Data.Text.IO as T import Graphics.SvgTree (Tree) -import Reanimate.Animation -import Reanimate.Cache -import Reanimate.Constants -import Reanimate.Misc -import Reanimate.Parameters -import Reanimate.Raster -import Reanimate.Svg.Constructors +import Reanimate.Animation (SVG) +import Reanimate.Cache (cacheFile, encodeInt) +import Reanimate.Constants (screenHeight, screenWidth) +import Reanimate.Misc (requireExecutable, runCmd) +import Reanimate.Parameters (pNoExternals) +import Reanimate.Raster (mkImage) +import Reanimate.Svg.Constructors (mkText) import System.FilePath (replaceExtension, (<.>)) import System.IO.Unsafe (unsafePerformIO) diff --git a/src/Reanimate/Builtin/CirclePlot.hs b/src/Reanimate/Builtin/CirclePlot.hs index c736ea1..e95185c 100644 --- a/src/Reanimate/Builtin/CirclePlot.hs +++ b/src/Reanimate/Builtin/CirclePlot.hs @@ -9,13 +9,15 @@ Portability : POSIX Convenience module for rendering circle plots. -} -module Reanimate.Builtin.CirclePlot where +module Reanimate.Builtin.CirclePlot + ( circlePlot + ) where -import Codec.Picture -import Graphics.SvgTree (Tree) -import Reanimate.Raster -import Reanimate.Svg -import Reanimate.Constants +import Codec.Picture (PixelRGBA8 (..), generateImage) +import Graphics.SvgTree (Tree) +import Reanimate.Constants (screenHeight) +import Reanimate.Raster (embedImage) +import Reanimate.Svg (flipYAxis, scaleToHeight) -- | Circle plots are scaled to 'screenHeight'. -- diff --git a/src/Reanimate/Builtin/Documentation.hs b/src/Reanimate/Builtin/Documentation.hs index d708fcb..d4dba53 100644 --- a/src/Reanimate/Builtin/Documentation.hs +++ b/src/Reanimate/Builtin/Documentation.hs @@ -12,11 +12,11 @@ GIFs for a consistent look and feel. -} module Reanimate.Builtin.Documentation where -import Reanimate.Animation -import Reanimate.Svg -import Reanimate.Raster -import Reanimate.Constants -import Codec.Picture +import Codec.Picture (PixelRGB8, PixelRGBA8 (..), generateImage) +import Reanimate.Animation (Animation, SVG, mapA, mkAnimation) +import Reanimate.Constants (screenHeight, screenWidth) +import Reanimate.Raster (embedImage) +import Reanimate.Svg -- | Default environment for API documentation GIFs. docEnv :: Animation -> Animation diff --git a/src/Reanimate/Builtin/Images.hs b/src/Reanimate/Builtin/Images.hs index 70c2f7b..fc7bce1 100644 --- a/src/Reanimate/Builtin/Images.hs +++ b/src/Reanimate/Builtin/Images.hs @@ -16,21 +16,21 @@ module Reanimate.Builtin.Images ) where -import Codec.Picture -import qualified Data.ByteString as B -import qualified Data.Text.IO as T -import Graphics.SvgTree (parseSvgFile) -import Paths_reanimate -import Reanimate.Animation -import Reanimate.Svg -import System.IO.Unsafe +import Codec.Picture +import qualified Data.ByteString as B +import qualified Data.Text.IO as T +import Graphics.SvgTree (parseSvgFile) +import Paths_reanimate +import Reanimate.Animation +import Reanimate.Svg +import System.IO.Unsafe embedImage :: FilePath -> IO SVG embedImage key = do svg_file <- getDataFileName key svg_data <- T.readFile svg_file case parseSvgFile svg_file svg_data of - Nothing -> error "Malformed svg" + Nothing -> error "Malformed svg" Just svg -> return $ embedDocument svg loadJPG :: FilePath -> Image PixelRGBA8 @@ -38,7 +38,7 @@ loadJPG key = unsafePerformIO $ do jpg_file <- getDataFileName key dat <- B.readFile jpg_file case decodeJpeg dat of - Left err -> error err + Left err -> error err Right img -> return $ convertRGBA8 img {- HLINT ignore svgLogo -} diff --git a/src/Reanimate/Builtin/Slide.hs b/src/Reanimate/Builtin/Slide.hs index ffb5b2c..cd43c22 100644 --- a/src/Reanimate/Builtin/Slide.hs +++ b/src/Reanimate/Builtin/Slide.hs @@ -7,10 +7,10 @@ Portability : POSIX -} module Reanimate.Builtin.Slide where -import Reanimate.Transition -import Reanimate.Constants -import Reanimate.Svg -import Reanimate.Effect +import Reanimate.Constants (screenHeight, screenWidth) +import Reanimate.Effect (constE, translateE) +import Reanimate.Svg (translate) +import Reanimate.Transition (Transition, effectT) -- | <> slideLeftT :: Transition diff --git a/src/Reanimate/Builtin/TernaryPlot.hs b/src/Reanimate/Builtin/TernaryPlot.hs index 683330f..93db600 100644 --- a/src/Reanimate/Builtin/TernaryPlot.hs +++ b/src/Reanimate/Builtin/TernaryPlot.hs @@ -21,10 +21,10 @@ module Reanimate.Builtin.TernaryPlot , fromCartesianCoords ) where -import Codec.Picture +import Codec.Picture (PixelRGBA8 (..), generateImage) import Graphics.SvgTree (Tree) -import Reanimate.Raster -import Reanimate.Svg +import Reanimate.Raster (embedImage) +import Reanimate.Svg (flipYAxis, scaleToWidth, translate) -- a+b+c=1 -- | Left-most coordinate. diff --git a/src/Reanimate/Cache.hs b/src/Reanimate/Cache.hs index 91a6a23..e39800e 100644 --- a/src/Reanimate/Cache.hs +++ b/src/Reanimate/Cache.hs @@ -8,24 +8,24 @@ module Reanimate.Cache , encodeInt ) where -import Control.Exception +import Control.Exception (evaluate) import Control.Monad (unless) -import Data.Bits -import Data.Hashable -import Data.IORef +import Data.Bits (Bits (shiftR)) +import Data.Hashable (Hashable (hash)) +import Data.IORef (IORef, atomicModifyIORef, newIORef, readIORef) import Data.Map (Map) import qualified Data.Map as Map import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T -import Graphics.SvgTree (Tree, unparse, pattern None) +import Graphics.SvgTree (Tree, pattern None, unparse) import Reanimate.Animation (renderTree) -import Reanimate.Misc (renameOrCopyFile,getReanimateCacheDirectory) -import System.Directory -import System.FilePath -import System.IO -import System.IO.Temp -import System.IO.Unsafe +import Reanimate.Misc (getReanimateCacheDirectory, renameOrCopyFile) +import System.Directory (doesFileExist) +import System.FilePath ((<.>), ()) +import System.IO (hClose) +import System.IO.Temp (openTempFile, withSystemTempFile) +import System.IO.Unsafe (unsafePerformIO) import Text.XML.Light (Content (..), parseXML) -- Memory cache and disk cache diff --git a/src/Reanimate/ColorComponents.hs b/src/Reanimate/ColorComponents.hs index 456eb2c..203e653 100644 --- a/src/Reanimate/ColorComponents.hs +++ b/src/Reanimate/ColorComponents.hs @@ -22,16 +22,16 @@ module Reanimate.ColorComponents , fromRGB8 ) where -import Codec.Picture -import Codec.Picture.Types -import Data.Colour -import Data.Colour.CIE +import Codec.Picture (Pixel (pixelOpacity), PixelRGB8 (..), PixelRGBA8 (..)) +import Codec.Picture.Types (TransparentPixel (dropTransparency)) +import Data.Colour (Colour) +import Data.Colour.CIE (cieLAB, cieLABView, cieXYZ, cieXYZView) import Data.Colour.CIE.Illuminant (d65) -import Data.Colour.RGBSpace -import Data.Colour.RGBSpace.HSV -import Data.Colour.SRGB -import Data.Fixed -import Reanimate.Ease +import Data.Colour.RGBSpace (RGB (RGB), uncurryRGB) +import Data.Colour.RGBSpace.HSV (hsv, hsvView) +import Data.Colour.SRGB (sRGB, sRGB24, toSRGB, toSRGBBounded) +import Data.Fixed (mod') +import Reanimate.Ease (fromToS) -- | Constructor and destructor for color's three components. data ColorComponents = ColorComponents diff --git a/src/Reanimate/ColorMap.hs b/src/Reanimate/ColorMap.hs index f7f0226..72c7bef 100644 --- a/src/Reanimate/ColorMap.hs +++ b/src/Reanimate/ColorMap.hs @@ -19,15 +19,15 @@ module Reanimate.ColorMap , greyscale ) where -import Data.Text (Text) -import Data.Vector (Vector) -import qualified Data.Text as T -import qualified Data.Vector as V -import Codec.Picture -import Data.Char -import Data.Bits +import Codec.Picture (Pixel8, PixelRGB8 (..)) +import Data.Bits (Bits (shiftL)) +import Data.Char (digitToInt) +import Data.Colour.RGBSpace (RGB (RGB)) import qualified Data.Colour.RGBSpace.HSV as HSV -import Data.Colour.RGBSpace +import Data.Text (Text) +import qualified Data.Text as T +import Data.Vector (Vector) +import qualified Data.Vector as V -- | Given a number t in the range [0,1], returns the corresponding color from -- the “turbo” color scheme by Anton Mikhailov. diff --git a/src/Reanimate/Constants.hs b/src/Reanimate/Constants.hs index b12b125..3198cc4 100644 --- a/src/Reanimate/Constants.hs +++ b/src/Reanimate/Constants.hs @@ -14,7 +14,7 @@ module Reanimate.Constants , defaultStrokeWidth ) where -import Graphics.SvgTree +import Graphics.SvgTree (Dpi) -- | Number of units from the left-most point to the right-most point on the screen. screenWidth :: Fractional a => a diff --git a/src/Reanimate/Debug.hs b/src/Reanimate/Debug.hs index 91e7571..df8d60a 100644 --- a/src/Reanimate/Debug.hs +++ b/src/Reanimate/Debug.hs @@ -12,15 +12,16 @@ module Reanimate.Debug ) where -import Data.IORef -import System.IO.Unsafe -import Control.Exception -import Reanimate.Animation -import Reanimate.Svg -import Reanimate.LaTeX -import Reanimate.Constants -import Text.Printf -import qualified Data.Text as T +import Control.Exception (evaluate) +import Data.IORef (IORef, atomicModifyIORef', modifyIORef', newIORef) +import qualified Data.Text as T +import Reanimate.Animation (Animation, SVG, duration, parA, pause, seqA, staticFrame) +import Reanimate.Constants (defaultStrokeWidth) +import Reanimate.LaTeX (latex) +import Reanimate.Svg (center, mkGroup, translate, withFillColor, withStrokeColor, + withStrokeWidth) +import System.IO.Unsafe (unsafePerformIO) +import Text.Printf (printf) {-# NOINLINE traceBuffer #-} traceBuffer :: IORef [Animation] diff --git a/src/Reanimate/Driver/CLI.hs b/src/Reanimate/Driver/CLI.hs index 82ea0a1..4a5b16a 100644 --- a/src/Reanimate/Driver/CLI.hs +++ b/src/Reanimate/Driver/CLI.hs @@ -9,12 +9,10 @@ module Reanimate.Driver.CLI , showRaster ) where -import Data.Char -import Data.Monoid +import Data.Char (toLower) import Options.Applicative import Prelude -import Reanimate.Render (FPS, Format (..), Height, Raster (..), - Width) +import Reanimate.Render (FPS, Format (..), Height, Raster (..), Width) newtype Options = Options { optsCommand :: Command @@ -29,10 +27,10 @@ data Command | Test | Check | View - { viewVerbose :: Bool - , viewGHCPath :: Maybe FilePath - , viewGHCOpts :: [String] - , viewOrigin :: Maybe FilePath + { viewVerbose :: Bool + , viewGHCPath :: Maybe FilePath + , viewGHCOpts :: [String] + , viewOrigin :: Maybe FilePath } | Render { renderTarget :: Maybe String @@ -54,12 +52,12 @@ data Preset = Youtube | ExampleGif | Quick | MediumQ | HighQ | LowFPS readRaster :: String -> Maybe Raster readRaster raster = case map toLower raster of - "none" -> Just RasterNone - "auto" -> Just RasterAuto - "inkscape" -> Just RasterInkscape - "rsvg" -> Just RasterRSvg - "imagemagick" -> Just RasterMagick - _ -> Nothing + "none" -> Just RasterNone + "auto" -> Just RasterAuto + "inkscape" -> Just RasterInkscape + "rsvg" -> Just RasterRSvg + "imagemagick" -> Just RasterMagick + _ -> Nothing showRaster :: Raster -> String showRaster RasterNone = "none" diff --git a/src/Reanimate/Driver/Check.hs b/src/Reanimate/Driver/Check.hs index b738cba..ee19e8a 100644 --- a/src/Reanimate/Driver/Check.hs +++ b/src/Reanimate/Driver/Check.hs @@ -8,17 +8,17 @@ module Reanimate.Driver.Check ) where import Control.Exception (SomeException, handle) -import Control.Monad -import Data.Maybe -import Data.Version -import Reanimate.Misc (runCmd_) +import Control.Monad (forM_) +import Data.Maybe (fromMaybe, listToMaybe) +import Data.Version (Version (Version), parseVersion, showVersion) import Reanimate.Driver.Magick (magickCmd) +import Reanimate.Misc (runCmd_) import System.Console.ANSI.Codes import System.Directory (findExecutable) -import System.IO -import System.IO.Temp -import Text.ParserCombinators.ReadP -import Text.Printf +import System.IO (hClose, hPutStr) +import System.IO.Temp (withSystemTempDirectory, withTempFile) +import Text.ParserCombinators.ReadP (readP_to_S) +import Text.Printf (printf) -------------------------------------------------------------------------- -- Check environment diff --git a/src/Reanimate/External.hs b/src/Reanimate/External.hs index ee9b63b..ad2feb5 100644 --- a/src/Reanimate/External.hs +++ b/src/Reanimate/External.hs @@ -13,26 +13,27 @@ module Reanimate.External ) where -import Codec.Picture (PixelRGB8 (..)) -import Control.Monad (unless) -import Crypto.Hash.SHA256 (hash) -import Data.Aeson (decodeFileStrict) -import qualified Data.ByteString as B (readFile) -import Data.ByteString.Base64 (encode) -import qualified Data.ByteString.Char8 as B8 (unpack) -import Data.Char (isSpace, toLower) -import Data.List (sort) -import Data.Map (Map) -import qualified Data.Map as M -import Numeric (readHex) -import Reanimate.Animation (SVG) -import Reanimate.Constants (screenHeight, screenWidth) -import Reanimate.Misc (getReanimateCacheDirectory, withTempFile) -import Reanimate.Raster (mkImage) -import System.Directory (doesDirectoryExist, doesFileExist, findExecutable, getDirectoryContents) -import System.FilePath (splitExtension, (<.>), ()) -import System.IO.Unsafe (unsafePerformIO) -import System.Process (callProcess) +import Codec.Picture (PixelRGB8 (..)) +import Control.Monad (unless) +import Crypto.Hash.SHA256 (hash) +import Data.Aeson (decodeFileStrict) +import qualified Data.ByteString as B (readFile) +import Data.ByteString.Base64 (encode) +import qualified Data.ByteString.Char8 as B8 (unpack) +import Data.Char (isSpace, toLower) +import Data.List (sort) +import Data.Map (Map) +import qualified Data.Map as M +import Numeric (readHex) +import Reanimate.Animation (SVG) +import Reanimate.Constants (screenHeight, screenWidth) +import Reanimate.Misc (getReanimateCacheDirectory, withTempFile) +import Reanimate.Raster (mkImage) +import System.Directory (doesDirectoryExist, doesFileExist, findExecutable, + getDirectoryContents) +import System.FilePath (splitExtension, (<.>), ()) +import System.IO.Unsafe (unsafePerformIO) +import System.Process (callProcess) -- | Resource address type URL = String @@ -83,8 +84,8 @@ downloadFile url action = do mbCurl <- findExecutable "curl" mbWget <- findExecutable "wget" case (mbCurl, mbWget) of - (Just curl, _) -> downloadFileCurl curl url action - (_, Just wget) -> downloadFileWget wget url action + (Just curl, _) -> downloadFileCurl curl url action + (_, Just wget) -> downloadFileWget wget url action (Nothing, Nothing) -> error "curl/wget required to download files" downloadFileCurl :: FilePath -> URL -> (FilePath -> IO a) -> IO a @@ -151,7 +152,7 @@ simpleIcon = mkImage screenWidth screenHeight . simpleIconPath simpleIconColor :: String -> PixelRGB8 simpleIconColor key = case M.lookup key simpleIconColors of - Nothing -> error $ "Key not found in simple-icons dataset: " ++ show key + Nothing -> error $ "Key not found in simple-icons dataset: " ++ show key Just pixel -> pixel -- | Complete list of all Simple Icons. @@ -168,7 +169,7 @@ simpleIconColors = unsafePerformIO $ do ] case parsed of Nothing -> error "Invalid json in simpleIcons" - Just v -> pure v + Just v -> pure v where fromTitle :: String -> String fromTitle = replaceChars . map toLower @@ -194,7 +195,7 @@ simpleIconColors = unsafePerformIO $ do where p offset = case readHex (take 2 $ drop offset hex) of [(num, "")] -> num - _ -> error $ "Invalid hex: " ++ (take 2 $ drop offset hex) + _ -> error $ "Invalid hex: " ++ (take 2 $ drop offset hex) {-# NOINLINE simpleIcons #-} simpleIcons :: [String] @@ -227,7 +228,7 @@ svgLogoPath key = unsafePerformIO $ do -- `svgLogo` "cassandra" -- @ -- --- <> +-- <> svgLogo :: String -> SVG svgLogo = mkImage screenWidth screenHeight . svgLogoPath @@ -238,4 +239,4 @@ svgLogos = unsafePerformIO $ do files <- getDirectoryContents svgLogosFolder return $ sort - [key | file <- files, let (key, ext) = splitExtension file, ext == ".svg"] \ No newline at end of file + [key | file <- files, let (key, ext) = splitExtension file, ext == ".svg"] diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index e065c02..877a600 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -1,9 +1,8 @@ -{-# LANGUAGE DeriveAnyClass #-} -{-# LANGUAGE DeriveGeneric #-} -{-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ScopedTypeVariables #-} - -- | -- Copyright : Written by David Himmelstrup -- License : Unlicense @@ -35,37 +34,25 @@ module Reanimate.LaTeX ) where -import Control.Lens -import qualified Data.ByteString as B -import Data.Hashable -import Data.Monoid -import Data.Text (Text) -import qualified Data.Text as T -import qualified Data.Text.IO as T -import qualified Data.Text.Encoding as T -import GHC.Generics (Generic) -import Graphics.SvgTree - ( Tree, - clipPathRef, - clipRule, - mapTree, - parseSvgFile, - strokeColor, - pattern ClipPathTree, - pattern None, - ) -import Reanimate.Animation (SVG) -import Reanimate.Cache -import Reanimate.External -import Reanimate.Misc -import Reanimate.Parameters -import Reanimate.Svg -import System.FilePath - ( replaceExtension, - takeFileName, - (), - ) -import System.IO.Unsafe (unsafePerformIO) +import Control.Lens ((&), (.~)) +import qualified Data.ByteString as B +import Data.Hashable (Hashable) +import Data.Monoid (Last (Last)) +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.Encoding as T +import qualified Data.Text.IO as T +import GHC.Generics (Generic) +import Graphics.SvgTree (Tree, clipPathRef, clipRule, mapTree, parseSvgFile, + pattern ClipPathTree, pattern None, strokeColor) +import Reanimate.Animation (SVG) +import Reanimate.Cache (cacheDiskSvg, cacheMem) +import Reanimate.External (zipArchive) +import Reanimate.Misc (requireExecutable, runCmd, withTempDir, withTempFile) +import Reanimate.Parameters (pNoExternals) +import Reanimate.Svg +import System.FilePath (replaceExtension, takeFileName, ()) +import System.IO.Unsafe (unsafePerformIO) -- | TeX backends. They have different features and capabilities. data TexEngine = LaTeX | XeLaTeX | LuaLaTeX @@ -73,8 +60,8 @@ data TexEngine = LaTeX | XeLaTeX | LuaLaTeX -- | TeX configurations can load packages and set up environments for tex scripts. data TexConfig = TexConfig - { texConfigEngine :: TexEngine, - texConfigHeaders :: [T.Text], + { texConfigEngine :: TexEngine, + texConfigHeaders :: [T.Text], texConfigPostScript :: [T.Text] } deriving (Generic, Hashable, Read, Show, Eq, Ord) @@ -86,8 +73,8 @@ latexCfg (TexConfig engine headers postscript) = where gen = case engine of - LaTeX -> someTexWithHeaders engine "latex" "dvi" [] - XeLaTeX -> someTexWithHeaders engine "xelatex" "xdv" ["-no-pdf"] + LaTeX -> someTexWithHeaders engine "latex" "dvi" [] + XeLaTeX -> someTexWithHeaders engine "xelatex" "xdv" ["-no-pdf"] LuaLaTeX -> someTexWithHeaders engine "lualatex" "pdf" [] -- | Invoke latex and import the result as an SVG object. SVG objects are @@ -184,13 +171,13 @@ postprocess = enginePostprocess :: TexEngine -> Tree -> Tree enginePostprocess LuaLaTeX svg = translate 0 (svgHeight svg) svg -enginePostprocess _ svg = svg +enginePostprocess _ svg = svg removeClipPaths :: SVG -> SVG removeClipPaths = mapTree worker where worker ClipPathTree {} = None - worker t = t & clipRule .~ Last Nothing & clipPathRef .~ Last Nothing + worker t = t & clipRule .~ Last Nothing & clipPathRef .~ Last Nothing -- executable, arguments, header, tex latexToSVG :: TexEngine -> String -> String -> [String] -> Text -> IO Tree diff --git a/src/Reanimate/Memo.hs b/src/Reanimate/Memo.hs index 63ed926..92d2d22 100644 --- a/src/Reanimate/Memo.hs +++ b/src/Reanimate/Memo.hs @@ -23,13 +23,13 @@ module Reanimate.Memo , memo ) where -import Data.Dynamic -import Data.IORef -import qualified Data.Map as Map -import Data.Maybe -import Data.Typeable -import System.IO.Unsafe -import System.Mem.StableName +import Data.Dynamic (Dynamic, fromDynamic, toDyn) +import Data.IORef (IORef, atomicModifyIORef', newIORef) +import qualified Data.Map as Map +import Data.Maybe (fromMaybe) +import Data.Typeable (Typeable, cast, typeOf) +import System.IO.Unsafe (unsafePerformIO) +import System.Mem.StableName (StableName, eqStableName, hashStableName, makeStableName) data DynamicName = forall a. DynamicName !(StableName a) | forall a. (Eq a, Ord a, Typeable a) => DynamicKey a instance Eq DynamicName where diff --git a/src/Reanimate/Misc.hs b/src/Reanimate/Misc.hs index f802969..953f34b 100644 --- a/src/Reanimate/Misc.hs +++ b/src/Reanimate/Misc.hs @@ -10,46 +10,25 @@ module Reanimate.Misc ) where -import Control.Concurrent -import Control.Exception (catch, evaluate, finally, throw) -import qualified Data.Text as T -import qualified Data.Text.IO as T -import Foreign.C.Error -import GHC.IO.Exception -import System.Directory - ( XdgDirectory (XdgCache), - copyFile, - createDirectoryIfMissing, - findExecutable, - getXdgDirectory, - removeFile, - renameFile, - ) -import System.FilePath ((<.>), ()) -import System.IO - ( hClose, - hGetContents, - hIsEOF, - hPutStr, - stderr, - ) -import System.IO.Temp - ( withSystemTempDirectory, - withSystemTempFile, - ) -import System.Process - ( readProcessWithExitCode, - runInteractiveProcess, - showCommandForUser, - terminateProcess, - waitForProcess, - ) +import Control.Concurrent (forkIO) +import Control.Exception (catch, evaluate, finally, throw) +import qualified Data.Text as T +import qualified Data.Text.IO as T +import Foreign.C.Error (Errno (Errno), eXDEV) +import GHC.IO.Exception (ExitCode (ExitFailure, ExitSuccess), IOException (ioe_errno)) +import System.Directory (XdgDirectory (XdgCache), copyFile, createDirectoryIfMissing, + findExecutable, getXdgDirectory, removeFile, renameFile) +import System.FilePath ((<.>), ()) +import System.IO (hClose, hGetContents, hIsEOF, hPutStr, stderr) +import System.IO.Temp (withSystemTempDirectory, withSystemTempFile) +import System.Process (readProcessWithExitCode, runInteractiveProcess, + showCommandForUser, terminateProcess, waitForProcess) requireExecutable :: String -> IO FilePath requireExecutable exec = do mbPath <- findExecutable exec case mbPath of - Nothing -> error $ "Couldn't find executable: " ++ exec + Nothing -> error $ "Couldn't find executable: " ++ exec Just path -> return path runCmd :: FilePath -> [String] -> IO () @@ -96,7 +75,7 @@ runCmdLazy exec args handler = do _ <- evaluate (length errOutput) ret <- waitForProcess pid case ret of - ExitSuccess -> return (Left "") + ExitSuccess -> return (Left "") ExitFailure {} -> return (Left errOutput) else {-ExitFailure errMsg -> do return $ Left $ diff --git a/src/Reanimate/Parameters.hs b/src/Reanimate/Parameters.hs index a048ce4..62a4059 100644 --- a/src/Reanimate/Parameters.hs +++ b/src/Reanimate/Parameters.hs @@ -21,8 +21,8 @@ module Reanimate.Parameters , setRootDirectory ) where -import System.IO.Unsafe -import Data.IORef +import Data.IORef (IORef, newIORef, readIORef, writeIORef) +import System.IO.Unsafe (unsafePerformIO) -- | Width of animation in pixels. type Width = Int diff --git a/src/Reanimate/PolyShape.hs b/src/Reanimate/PolyShape.hs index 054469b..4faa29c 100644 --- a/src/Reanimate/PolyShape.hs +++ b/src/Reanimate/PolyShape.hs @@ -48,7 +48,7 @@ import qualified Data.Geometry.Point as Geo import qualified Data.Geometry.Polygon as Geo import Data.List (nub, partition, sortOn) import qualified Data.PlaneGraph as Geo -import Data.Proxy +import Data.Proxy (Proxy (Proxy)) import qualified Data.Vector as V import Geom2D.CubicBezier.Linear (ClosedPath (..), CubicBezier (..), diff --git a/src/Reanimate/Povray.hs b/src/Reanimate/Povray.hs index 6878c56..14b76eb 100644 --- a/src/Reanimate/Povray.hs +++ b/src/Reanimate/Povray.hs @@ -14,17 +14,17 @@ module Reanimate.Povray , povrayExtreme' ) where -import Data.Hashable +import Data.Hashable (Hashable (hash)) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T import Graphics.SvgTree (Tree) -import Reanimate.Cache -import Reanimate.Constants -import Reanimate.Misc -import Reanimate.Parameters -import Reanimate.Raster -import Reanimate.Svg.Constructors +import Reanimate.Cache (cacheFile, encodeInt) +import Reanimate.Constants (screenHeight, screenWidth) +import Reanimate.Misc (requireExecutable, runCmd) +import Reanimate.Parameters (pNoExternals) +import Reanimate.Raster (mkImage) +import Reanimate.Svg.Constructors (mkText) import System.FilePath (replaceExtension, (<.>)) import System.IO.Unsafe (unsafePerformIO) diff --git a/src/Reanimate/Raster.hs b/src/Reanimate/Raster.hs index ca0a7e0..f468ad5 100644 --- a/src/Reanimate/Raster.hs +++ b/src/Reanimate/Raster.hs @@ -26,36 +26,35 @@ module Reanimate.Raster ) where -import Codec.Picture -import Control.Lens ( (&) - , (.~) - ) -import Control.Monad -import qualified Data.ByteString as B -import qualified Data.ByteString.Base64.Lazy as Base64 -import qualified Data.ByteString.Lazy.Char8 as LBS -import Data.Hashable -import qualified Data.Text as T -import qualified Data.Text.IO as T -import Graphics.SvgTree ( Number(..) - , defaultSvg - , parseSvgFile - ) -import qualified Graphics.SvgTree as Svg -import Reanimate.Animation -import Reanimate.Cache -import Reanimate.Driver.Magick -import Reanimate.Misc -import Reanimate.Render -import Reanimate.Parameters -import Reanimate.Constants -import Reanimate.Svg.Constructors -import Reanimate.Svg.Unuse -import System.Directory -import System.FilePath -import System.IO -import System.IO.Temp -import System.IO.Unsafe +import Codec.Picture (DynamicImage, Image (imageHeight, imageWidth), + PngSavable (encodePng), decodePng, dynamicMap, + encodeDynamicPng, writePng) +import Control.Lens ((&), (.~)) +import Control.Monad (unless) +import qualified Data.ByteString as B +import qualified Data.ByteString.Base64.Lazy as Base64 +import qualified Data.ByteString.Lazy.Char8 as LBS +import Data.Hashable (Hashable (hash)) +import qualified Data.Text as T +import qualified Data.Text.IO as T +import Graphics.SvgTree (Number (..), defaultSvg, parseSvgFile) +import qualified Graphics.SvgTree as Svg +import Reanimate.Animation (SVG, renderSvg) +import Reanimate.Cache (cacheFile, encodeInt) +import Reanimate.Constants (screenHeight, screenWidth) +import Reanimate.Driver.Magick (magickCmd) +import Reanimate.Misc (getReanimateCacheDirectory, renameOrCopyFile, + requireExecutable, runCmd) +import Reanimate.Parameters (Height, Raster (RasterNone), Width, pHeight, + pNoExternals, pRaster, pRootDirectory, pWidth) +import Reanimate.Render (applyRaster, requireRaster) +import Reanimate.Svg.Constructors (flipYAxis, mkText, scaleXY) +import Reanimate.Svg.Unuse (replaceUses, unbox, unboxFit) +import System.Directory (copyFile, doesFileExist, removeFile) +import System.FilePath (replaceExtension, takeExtension, (<.>), ()) +import System.IO (hClose) +import System.IO.Temp (withSystemTempFile) +import System.IO.Unsafe (unsafePerformIO) -- | Load an external image. Width and height must be specified, -- ignoring the image's aspect ratio. The center of the image is diff --git a/src/Reanimate/Render.hs b/src/Reanimate/Render.hs index a7bf75d..bfb0629 100644 --- a/src/Reanimate/Render.hs +++ b/src/Reanimate/Render.hs @@ -26,22 +26,22 @@ module Reanimate.Render import Control.Concurrent import Control.Exception import Control.Monad (forM_, forever, unless, void, when) -import Data.Either -import Data.Function +import Data.Either (isRight) +import Data.Function (fix) import qualified Data.Text as T import qualified Data.Text.IO as T import Data.Time import Graphics.SvgTree (Number (..)) -import Numeric -import Reanimate.Animation -import Reanimate.Driver.Check -import Reanimate.Driver.Magick +import Numeric (showFFloat) +import Reanimate.Animation (Animation, duration, frameAt, renderSvg) +import Reanimate.Driver.Check (hasInkscape, hasMagick, hasRSvg) +import Reanimate.Driver.Magick (magickCmd) import Reanimate.Misc import Reanimate.Parameters -import System.Console.ANSI.Codes -import System.Exit -import System.FileLock (withTryFileLock, SharedExclusive(..), unlockFile) -import System.Directory +import System.Console.ANSI.Codes (clearFromCursorToLineEndCode) +import System.Directory (doesFileExist, removeFile) +import System.Exit (ExitCode (ExitFailure), exitWith) +import System.FileLock (SharedExclusive (..), unlockFile, withTryFileLock) import System.FilePath (replaceExtension, (<.>), ()) import System.IO import Text.Printf (printf) diff --git a/src/Reanimate/Scene/Core.hs b/src/Reanimate/Scene/Core.hs index 20f717b..1c2dba5 100644 --- a/src/Reanimate/Scene/Core.hs +++ b/src/Reanimate/Scene/Core.hs @@ -2,11 +2,11 @@ module Reanimate.Scene.Core where -import Control.Monad.Fix (MonadFix (..)) -import Control.Monad.ST -import Data.List -import Reanimate.Animation -import Reanimate.Svg.Constructors +import Control.Monad.Fix (MonadFix (..)) +import Control.Monad.ST (ST, runST) +import Data.List (sortOn) +import Reanimate.Animation (Animation, Duration, SVG, Time, mkAnimation) +import Reanimate.Svg.Constructors (mkGroup) -- | The ZIndex property specifies the stack order of sprites and animations. Elements -- with a higher ZIndex will be drawn on top of elements with a lower index. diff --git a/src/Reanimate/Scene/Object.hs b/src/Reanimate/Scene/Object.hs index 4d33d85..4f2bd60 100644 --- a/src/Reanimate/Scene/Object.hs +++ b/src/Reanimate/Scene/Object.hs @@ -1,32 +1,26 @@ -{-# LANGUAGE ApplicativeDo #-} +{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE RecordWildCards #-} module Reanimate.Scene.Object where -import Linear.V2 -import Linear.Vector -import Control.Lens -import Control.Monad (forM_, void) -import Control.Monad.State (State, execState) -import Data.Monoid ( Last(getLast) ) -import Graphics.SvgTree - ( Number (..), - Tree, - strokeWidth, - toUserUnit, - pattern None, - ) -import Reanimate.Animation -import Reanimate.Constants (defaultDPI, defaultStrokeWidth) -import Reanimate.Ease (Signal, curveS, fromToS) -import Reanimate.Effect ( applyE, fadeLineOutE, overEnding ) -import Reanimate.Math.Balloon ( balloon ) -import Reanimate.Morph.Common (morph) -import Reanimate.Morph.Linear (linear) -import Reanimate.Svg +import Control.Lens +import Control.Monad (forM_, void) +import Control.Monad.State (State, execState) +import Data.Monoid (Last (getLast)) +import Graphics.SvgTree (Number (..), Tree, pattern None, strokeWidth, toUserUnit) +import Linear.V2 (R1 (_x), R2 (_y), V2 (..)) +import Linear.Vector (Additive (lerp), (^*)) +import Reanimate.Animation +import Reanimate.Constants (defaultDPI, defaultStrokeWidth) +import Reanimate.Ease (Signal, curveS, fromToS) +import Reanimate.Effect (applyE, fadeLineOutE, overEnding) +import Reanimate.Math.Balloon (balloon) +import Reanimate.Morph.Common (morph) +import Reanimate.Morph.Linear (linear) +import Reanimate.Svg -import Reanimate.Scene.Core -import Reanimate.Scene.Sprite -import Reanimate.Scene.Var +import Reanimate.Scene.Core (Scene, fork, scene, wait) +import Reanimate.Scene.Sprite (Sprite, newSprite, newSpriteA', play, spriteModify, unVar) +import Reanimate.Scene.Var (Var, modifyVar, newVar, readVar, tweenVar) ------------------------------------------------------- -- Objects @@ -43,23 +37,23 @@ instance Renderable Tree where -- change over time. data Object s a = Object { objectSprite :: Sprite s, - objectData :: Var s (ObjectData a) + objectData :: Var s (ObjectData a) } -- | Container for object properties. data ObjectData a = ObjectData - { _oTranslate :: V2 Double, - _oValueRef :: a, - _oSVG :: SVG, - _oContext :: SVG -> SVG, + { _oTranslate :: V2 Double, + _oValueRef :: a, + _oSVG :: SVG, + _oContext :: SVG -> SVG, -- | Top, right, bottom, left - _oMargin :: (Double, Double, Double, Double), - _oBB :: (Double, Double, Double, Double), - _oOpacity :: Double, - _oShown :: Bool, - _oZIndex :: Int, - _oEasing :: Signal, - _oScale :: Double, + _oMargin :: (Double, Double, Double, Double), + _oBB :: (Double, Double, Double, Double), + _oOpacity :: Double, + _oShown :: Bool, + _oZIndex :: Int, + _oEasing :: Signal, + _oScale :: Double, _oScaleOrigin :: V2 Double } @@ -508,7 +502,7 @@ oDraw = oStagger $ \svg -> scene $ let sWidth = case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of Just (Num d) -> max defaultStrokeWidth d - _ -> defaultStrokeWidth + _ -> defaultStrokeWidth -- wait 1 play $ mapA ctx $ diff --git a/src/Reanimate/Scene/Sprite.hs b/src/Reanimate/Scene/Sprite.hs index 8fda6dc..a25d398 100644 --- a/src/Reanimate/Scene/Sprite.hs +++ b/src/Reanimate/Scene/Sprite.hs @@ -1,39 +1,21 @@ -{-# LANGUAGE ApplicativeDo #-} +{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE PatternSynonyms #-} -{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE RankNTypes #-} module Reanimate.Scene.Sprite where -import Control.Monad (void) -import Control.Monad.ST (ST) -import Data.Bifunctor (Bifunctor (first)) -import Data.STRef (STRef, modifySTRef, newSTRef, readSTRef) -import Graphics.SvgTree - ( pattern None, - ) -import Reanimate.Animation - ( Animation, - Duration, - SVG, - Sync (SyncStretch), - Time, - dropA, - duration, - getAnimationFrame, - ) -import Reanimate.Effect (Effect, delayE) -import Reanimate.Scene.Core - ( Scene (M), - ZIndex, - addGen, - fork, - liftST, - queryNow, - scene, - wait, - ) -import Reanimate.Scene.Var (unpackVar, Var (..), newVar, readVar) -import Reanimate.Transition (Transition, overlapT) +import Control.Monad (void) +import Control.Monad.ST (ST) +import Data.Bifunctor (Bifunctor (first)) +import Data.STRef (STRef, modifySTRef, newSTRef, readSTRef) +import Graphics.SvgTree (pattern None) +import Reanimate.Animation (Animation, Duration, SVG, Sync (SyncStretch), Time, dropA, + duration, getAnimationFrame) +import Reanimate.Effect (Effect, delayE) +import Reanimate.Scene.Core (Scene (M), ZIndex, addGen, fork, liftST, queryNow, scene, + wait) +import Reanimate.Scene.Var (Var (..), newVar, readVar, unpackVar) +import Reanimate.Transition (Transition, overlapT) -- | Create and render a variable. The rendering will be born at the current timestamp -- and will persist until the end of the scene. diff --git a/src/Reanimate/Scene/Var.hs b/src/Reanimate/Scene/Var.hs index 64a659f..65f7c3d 100644 --- a/src/Reanimate/Scene/Var.hs +++ b/src/Reanimate/Scene/Var.hs @@ -1,13 +1,13 @@ -{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE RecordWildCards #-} module Reanimate.Scene.Var where -import Control.Monad.ST (ST) -import qualified Data.Map as M -import Data.STRef -import Reanimate.Animation (Duration, Time) -import Reanimate.Scene.Core (Scene, liftST, queryNow, wait) +import Control.Monad.ST (ST) +import qualified Data.Map as M +import Data.STRef (STRef, modifySTRef, newSTRef, readSTRef) +import Reanimate.Animation (Duration, Time) +import Reanimate.Scene.Core (Scene, liftST, queryNow, wait) -- | Time dependent variable. newtype Var s a = Var (STRef s (VarData a)) @@ -18,9 +18,9 @@ newtype Var s a = Var (STRef s (VarData a)) -- it shouldn't be Nothing again. -- 3. isNothing (evarLastTime var) => M.null (evarTimeline var) data VarData a = VarData - { evarDefault :: a, - evarTimeline :: Timeline a, - evarLastTime :: Maybe Time, + { evarDefault :: a, + evarTimeline :: Timeline a, + evarLastTime :: Maybe Time, evarLastValue :: a } @@ -103,7 +103,7 @@ modifyVarData now fn var = let before = keepBefore now var after = keepFrom now var timeline = flip M.map (evarTimeline after) $ \case - StaticValue s -> StaticValue $ fn s + StaticValue s -> StaticValue $ fn s TweenValue dur f -> TweenValue dur $ \a t -> fn (f a t) in after {evarTimeline = timeline, evarLastValue = fn $ evarLastValue after} `elseVar` before @@ -165,5 +165,5 @@ keepBefore nd var@VarData {..} = _ -> timeline' lastTime = case lastModifier of Just (t, TweenValue dur _) -> Just $ min nd (t + dur) - _ -> min nd <$> evarLastTime + _ -> min nd <$> evarLastTime in VarData evarDefault timeline'' lastTime (maybe evarDefault (readVarData var) lastTime) diff --git a/src/Reanimate/Svg.hs b/src/Reanimate/Svg.hs index 13dbfef..e890d37 100644 --- a/src/Reanimate/Svg.hs +++ b/src/Reanimate/Svg.hs @@ -14,17 +14,17 @@ module Reanimate.Svg , module Reanimate.Svg.Unuse ) where -import Control.Lens ((%~), (&), (.~), (^.), (?~)) +import Control.Lens ((%~), (&), (.~), (?~), (^.)) import Control.Monad.State import Graphics.SvgTree -import Linear.V2 hiding (angle) -import Reanimate.Constants -import Reanimate.Animation (SVG) +import Linear.V2 (V2 (V2)) +import Reanimate.Animation (SVG) +import Reanimate.Constants (defaultDPI) +import Reanimate.Svg.BoundingBox (boundingBox, svgHeight, svgWidth) import Reanimate.Svg.Constructors import Reanimate.Svg.LineCommand -import Reanimate.Svg.BoundingBox -import Reanimate.Svg.Unuse -import qualified Reanimate.Transform as Transform +import Reanimate.Svg.Unuse (embedDocument, replaceUses, unbox, unboxFit) +import qualified Reanimate.Transform as Transform -- | Remove transformations (such as translations, rotations, scaling) -- and apply them directly to the SVG nodes. Note, this function @@ -343,9 +343,9 @@ mapSvgLines fn = mapSvgPaths (lineToPath . fn . toLineCommands) mapSvgPoints :: (RPoint -> RPoint) -> SVG -> SVG mapSvgPoints fn = mapSvgLines (map worker) where - worker (LineMove p) = LineMove (fn p) + worker (LineMove p) = LineMove (fn p) worker (LineBezier ps) = LineBezier (map fn ps) - worker (LineEnd p) = LineEnd (fn p) + worker (LineEnd p) = LineEnd (fn p) -- | Convert coordinate system from degrees to radians. svgPointsToRadians :: SVG -> SVG diff --git a/src/Reanimate/Svg/BoundingBox.hs b/src/Reanimate/Svg/BoundingBox.hs index 52c6a66..a152ca9 100644 --- a/src/Reanimate/Svg/BoundingBox.hs +++ b/src/Reanimate/Svg/BoundingBox.hs @@ -11,18 +11,18 @@ module Reanimate.Svg.BoundingBox , svgWidth ) where -import Control.Arrow ((***)) -import Control.Lens ((^.)) -import Data.List -import Data.Maybe (mapMaybe) -import qualified Data.Vector.Unboxed as V +import Control.Arrow ((***)) +import Control.Lens ((^.)) +import Data.List (foldl') +import Data.Maybe (mapMaybe) +import qualified Data.Vector.Unboxed as V import qualified Geom2D.CubicBezier.Linear as Bezier import Graphics.SvgTree -import Linear.V2 hiding (angle) -import Linear.Vector -import Reanimate.Constants -import Reanimate.Svg.LineCommand -import qualified Reanimate.Transform as Transform +import Linear.V2 (V2 (V2)) +import Linear.Vector (Additive (zero)) +import Reanimate.Constants (defaultDPI) +import Reanimate.Svg.LineCommand (LineCommand (..), toLineCommands) +import qualified Reanimate.Transform as Transform -- | Return bounding box of SVG tree. -- The four numbers returned are (minimal X-coordinate, minimal Y-coordinate, width, height) @@ -114,7 +114,7 @@ svgBoundingPoints t = map (Transform.transformPoint m) $ rnum = circ ^. circleRadius in case mapMaybe unpackNumber [xnum, ynum, rnum] of [x, y, r] -> [ V2 (x + r * cos angle) (y + r * sin angle) | angle <- [0, pi/10 .. 2 * pi]] - _ -> [] + _ -> [] ellipseBoundingPoints e = let (xnum,ynum) = e ^. ellipseCenter diff --git a/src/Reanimate/Svg/Constructors.hs b/src/Reanimate/Svg/Constructors.hs index fe4b287..aa57091 100644 --- a/src/Reanimate/Svg/Constructors.hs +++ b/src/Reanimate/Svg/Constructors.hs @@ -63,11 +63,11 @@ import Data.Attoparsec.Text (parseOnly) import qualified Data.Map as Map import qualified Data.Text as T import Graphics.SvgTree -import Graphics.SvgTree.NamedColors -import Graphics.SvgTree.PathParser -import Linear.V2 hiding (angle) -import Reanimate.Constants -import Reanimate.Svg.BoundingBox +import Graphics.SvgTree.NamedColors (svgNamedColors) +import Graphics.SvgTree.PathParser (pathParser) +import Linear.V2 (V2 (V2)) +import Reanimate.Constants (screenHeight, screenWidth) +import Reanimate.Svg.BoundingBox (boundingBox) -- | Apply list of transformations to given image. withTransformations :: [Transformation] -> Tree -> Tree diff --git a/src/Reanimate/Svg/LineCommand.hs b/src/Reanimate/Svg/LineCommand.hs index bd8470d..d928ce5 100644 --- a/src/Reanimate/Svg/LineCommand.hs +++ b/src/Reanimate/Svg/LineCommand.hs @@ -15,17 +15,20 @@ module Reanimate.Svg.LineCommand ) where -import Control.Lens ((%~), (&), (.~)) -import Control.Monad.Fix -import Control.Monad.State -import Data.Functor -import Data.Maybe -import qualified Data.Vector.Unboxed as V +import Control.Lens ((%~), (&), (.~)) +import Control.Monad.Fix (MonadFix (mfix)) +import Control.Monad.State (MonadState (get, put), State, evalState, forM, gets, + modify) +import Data.Functor (($>)) +import Data.Maybe (mapMaybe) +import qualified Data.Vector.Unboxed as V import qualified Geom2D.CubicBezier.Linear as Bezier -import Graphics.SvgTree -import Linear.Metric -import Linear.V2 hiding (angle) -import Linear.Vector +import Graphics.SvgTree (Coord, Origin (OriginAbsolute, OriginRelative), + PathCommand (..), RPoint, Tree, mapTree, pathDefinition, + pattern PathTree) +import Linear.Metric (Metric (distance)) +import Linear.V2 (R1 (_x), R2 (_y), V2 (V2)) +import Linear.Vector (Additive (lerp, zero)) -- | Line command monad used for keeping track of the current location. type CmdM a = State RPoint a @@ -42,13 +45,13 @@ data LineCommand lineToPath :: [LineCommand] -> [PathCommand] lineToPath = map worker where - worker (LineMove p) = MoveTo OriginAbsolute [p] + worker (LineMove p) = MoveTo OriginAbsolute [p] -- worker (LineDraw p) = LineTo OriginAbsolute [p] worker (LineBezier [a, b, c]) = CurveTo OriginAbsolute [(a, b, c)] - worker (LineBezier [a, b]) = QuadraticBezier OriginAbsolute [(a, b)] - worker (LineBezier [a]) = LineTo OriginAbsolute [a] - worker LineBezier {} = error "Reanimate.Svg.lineToPath: invalid bezier curve" - worker LineEnd {} = EndPath + worker (LineBezier [a, b]) = QuadraticBezier OriginAbsolute [(a, b)] + worker (LineBezier [a]) = LineTo OriginAbsolute [a] + worker LineBezier {} = error "Reanimate.Svg.lineToPath: invalid bezier curve" + worker LineEnd {} = EndPath -- | Using @n@ control points, approximate the path of the curves. lineToPoints :: Int -> [LineCommand] -> [RPoint] @@ -56,9 +59,9 @@ lineToPoints nPoints cmds = mapMaybe lineEnd lineSegments where lineSegments = [partialLine (fromIntegral n / fromIntegral nPoints) cmds | n <- [0 .. nPoints -1]] - lineEnd [] = Nothing + lineEnd [] = Nothing lineEnd [LineBezier pts] = Just (last pts) - lineEnd (_ : xs) = lineEnd xs + lineEnd (_ : xs) = lineEnd xs partialLine :: Double -> [LineCommand] -> [LineCommand] partialLine alpha cmds = evalState (worker 0 cmds) zero @@ -78,9 +81,9 @@ adjustLineLength :: Double -> RPoint -> LineCommand -> LineCommand adjustLineLength alpha from cmd = case cmd of LineBezier points -> LineBezier $ drop 1 $ partialBezierPoints (from : points) 0 alpha - LineMove p -> LineMove p + LineMove p -> LineMove p -- LineDraw t -> LineDraw (lerp alpha t from) - LineEnd p -> LineBezier [lerp alpha p from] + LineEnd p -> LineBezier [lerp alpha p from] -- | Estimated length of all segments in a line. lineLength :: LineCommand -> CmdM Double @@ -101,10 +104,10 @@ lineLength cmd = rpointsToBezier :: [RPoint] -> Bezier.CubicBezier Double rpointsToBezier lst = case lst of - [a, b] -> Bezier.CubicBezier a a b b - [a, b, c] -> Bezier.quadToCubic (Bezier.QuadBezier a b c) + [a, b] -> Bezier.CubicBezier a a b b + [a, b, c] -> Bezier.quadToCubic (Bezier.QuadBezier a b c) [a, b, c, d] -> Bezier.CubicBezier a b c d - _ -> error $ "rpointsToBezier: Invalid list of points: " ++ show lst + _ -> error $ "rpointsToBezier: Invalid list of points: " ++ show lst -- | Convert from path commands to line commands. toLineCommands :: [PathCommand] -> [LineCommand] @@ -116,12 +119,12 @@ toLineCommands ps = evalState (worker zero Nothing ps) zero let startPos' = case lcmds of [LineMove pos] -> pos - _ -> startPos + _ -> startPos (lcmds ++) <$> worker startPos' (cmdToControlPoint $ last lcmds) cmds cmdToControlPoint :: LineCommand -> Maybe RPoint cmdToControlPoint (LineBezier points) = Just (last (init points)) -cmdToControlPoint _ = Nothing +cmdToControlPoint _ = Nothing mkStraightLine :: RPoint -> LineCommand mkStraightLine p = LineBezier [p] @@ -180,7 +183,7 @@ toLineCommand startPos mbPrevControlPt cmd = adjustPosition OriginRelative p = modify (+ p) adjustPosition OriginAbsolute p = put p makeAbsolute OriginAbsolute _from p = p - makeAbsolute OriginRelative from p = from + p + makeAbsolute OriginRelative from p = from + p calculateVectorAngle :: Double -> Double -> Double -> Double -> Double calculateVectorAngle ux uy vx vy diff --git a/src/Reanimate/Svg/Unuse.hs b/src/Reanimate/Svg/Unuse.hs index 6d9435b..220ef0c 100644 --- a/src/Reanimate/Svg/Unuse.hs +++ b/src/Reanimate/Svg/Unuse.hs @@ -14,18 +14,19 @@ module Reanimate.Svg.Unuse import Control.Lens ((%~), (&), (.~), (?~), (^.)) import qualified Data.Map as Map -import Data.Maybe +import Data.Maybe (fromMaybe) import Graphics.SvgTree -import Reanimate.Constants -import Reanimate.Svg.Constructors +import Reanimate.Constants (defaultDPI, screenHeight, screenWidth) +import Reanimate.Svg.Constructors (flipYAxis, mkGroup, scaleXY, translate, + withFillOpacity, withStrokeWidth) -- | Replace all @@ nodes with their definition. replaceUses :: Document -> Document replaceUses doc = doc & documentElements %~ map (mapTree replace) where - replaceDefinition PathTree{} = None + replaceDefinition PathTree{} = None replaceDefinition SymbolTree{} = None - replaceDefinition t = t + replaceDefinition t = t replace t@DefinitionTree{} = mapTree replaceDefinition t replace (UseTree _ Just{}) = error "replaceUses: subtree in use?" diff --git a/src/Reanimate/Transform.hs b/src/Reanimate/Transform.hs index 9eef5cd..c4e69cb 100644 --- a/src/Reanimate/Transform.hs +++ b/src/Reanimate/Transform.hs @@ -1,4 +1,4 @@ -{-# LANGUAGE BangPatterns #-} +{-# LANGUAGE BangPatterns #-} {-| 2D transformation matrices capable of translating, scaling, rotating, and skewing. @@ -11,12 +11,12 @@ module Reanimate.Transform ) where -- XXX: Use Linear.Matrix instead of Data.Matrix to drop the 'matrix' dependency. -import Data.List -import Data.Matrix (Matrix) -import qualified Data.Matrix as M -import Data.Maybe -import Graphics.SvgTree -import Linear.V2 +import Data.List (foldl') +import Data.Matrix (Matrix) +import qualified Data.Matrix as M +import Data.Maybe (fromMaybe) +import Graphics.SvgTree (Coord, RPoint, Transformation (..)) +import Linear.V2 (V2 (V2)) -- | Identity matrix. -- diff --git a/src/Reanimate/Transition.hs b/src/Reanimate/Transition.hs index 0e92554..dc78895 100644 --- a/src/Reanimate/Transition.hs +++ b/src/Reanimate/Transition.hs @@ -15,9 +15,10 @@ module Reanimate.Transition , fadeT ) where -import Reanimate.Animation -import Reanimate.Ease -import Reanimate.Effect +import Reanimate.Animation (Animation, dropA, duration, lastA, parA, pause, seqA, signalA, + takeA) +import Reanimate.Ease (Signal) +import Reanimate.Effect (Effect, applyE, fadeInE, fadeOutE) -- | A transition transforms one animation into another. type Transition = Animation -> Animation -> Animation @@ -66,7 +67,7 @@ effectT eA eB a b = applyE eA a `parA` applyE eB b -- -- <> chainT :: Transition -> [Animation] -> Animation -chainT _ [] = pause 0 +chainT _ [] = pause 0 chainT t (x:xs) = foldl t x xs -- | Fade out left-hand-side animation while fading in right-hand-side animation. diff --git a/src/Reanimate/Voice.hs b/src/Reanimate/Voice.hs index dd98c60..865ad22 100644 --- a/src/Reanimate/Voice.hs +++ b/src/Reanimate/Voice.hs @@ -1,6 +1,6 @@ +{-# LANGUAGE ApplicativeDo #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ApplicativeDo #-} -{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE RecordWildCards #-} {-| Reanimate can automatically synchronize animations to your voice if you have a transcript and an audio recording. This works with the help of Gentle @@ -20,27 +20,27 @@ module Reanimate.Voice ) where +import Control.Monad (forM_) import Data.Aeson -import Data.Char -import System.IO.Unsafe ( unsafePerformIO ) -import System.Directory -import System.FilePath -import System.Process -import System.Exit -import Control.Monad -import Data.List -import Data.Maybe -import qualified Data.Map as Map -import Data.Map ( Map ) -import Data.Text ( Text ) -import qualified Data.Text as T -import qualified Data.Text.IO as T -import Reanimate.Misc -import Reanimate.LaTeX -import Reanimate.Scene -import Reanimate.Animation -import Reanimate.Svg -import Reanimate.Constants +import Data.Char (isAlphaNum, isSpace) +import Data.List (sortOn) +import Data.Map (Map) +import qualified Data.Map as Map +import Data.Maybe (listToMaybe) +import Data.Text (Text) +import qualified Data.Text as T +import qualified Data.Text.IO as T +import Reanimate.Animation (SVG, staticFrame) +import Reanimate.Constants (defaultStrokeWidth, screenHeight, screenWidth) +import Reanimate.LaTeX (latex, latexChunks) +import Reanimate.Misc (withTempFile) +import Reanimate.Scene (Scene, play, waitUntil) +import Reanimate.Svg (mkGroup, scale, translate, withStrokeColor, withStrokeWidth) +import System.Directory (doesFileExist) +import System.Exit (ExitCode (ExitFailure, ExitSuccess)) +import System.FilePath (replaceExtension) +import System.IO.Unsafe (unsafePerformIO) +import System.Process (rawSystem, showCommandForUser) -- | Aligned transcript. Contains the transcript text as well as -- timing data for each word. From 53793fcf1bd389c837d9d6dc7d639adaa9d1a8dd Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sat, 10 Oct 2020 21:43:42 +0800 Subject: [PATCH 011/114] Bump version to 1.1.1.0 and update changelog. --- ChangeLog.md | 13 +++++++++++++ reanimate.cabal | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ChangeLog.md b/ChangeLog.md index c0ace79..07e2811 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and the project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org) +## 1.1.1.0 -- 2020-10-10 + +### Added + + * External icon sets. + * Font configurations. + +### Other/Non-visible + + * Improved unicode support. + * Improved support for filter effects. + * Bug fix in the path parser. + ## 1.1.0.0 -- 2020-10-07 ### Added diff --git a/reanimate.cabal b/reanimate.cabal index 0ac331b..5382df0 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.0.0 +version: 1.1.1.0 -- synopsis: -- description: license: PublicDomain From dec92f2299b617472326815871b885204cdf1654 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 12 Oct 2020 08:58:02 +0800 Subject: [PATCH 012/114] Fix documentation for external data sets. --- src/Reanimate/External.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Reanimate/External.hs b/src/Reanimate/External.hs index ad2feb5..9475748 100644 --- a/src/Reanimate/External.hs +++ b/src/Reanimate/External.hs @@ -155,7 +155,6 @@ simpleIconColor key = Nothing -> error $ "Key not found in simple-icons dataset: " ++ show key Just pixel -> pixel --- | Complete list of all Simple Icons. simpleIconColors :: Map String PixelRGB8 simpleIconColors = unsafePerformIO $ do let path = simpleIconsFolder "_data" "simple-icons.json" @@ -198,6 +197,7 @@ simpleIconColors = unsafePerformIO $ do _ -> error $ "Invalid hex: " ++ (take 2 $ drop offset hex) {-# NOINLINE simpleIcons #-} +-- | Complete list of all Simple Icons. simpleIcons :: [String] simpleIcons = unsafePerformIO $ do let folder = simpleIconsFolder "icons" @@ -222,7 +222,7 @@ svgLogoPath key = unsafePerformIO $ do then pure path else error $ "Key not found in svg logos dataset: " ++ show key --- | Icons from . Version 3.11.0. License: CC0 +-- | Icons from . Version 2018.01. License: CC0 -- -- @ -- `svgLogo` "cassandra" From e266f5454c6529e6d6f8a590f4cc0f4f243b2ea9 Mon Sep 17 00:00:00 2001 From: Krantz-XRF Date: Sun, 11 Oct 2020 15:52:14 +0800 Subject: [PATCH 013/114] fix Reanimate.LaTeX.xelatex --- src/Reanimate/LaTeX.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index 877a600..52788cd 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -43,8 +43,8 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import GHC.Generics (Generic) -import Graphics.SvgTree (Tree, clipPathRef, clipRule, mapTree, parseSvgFile, - pattern ClipPathTree, pattern None, strokeColor) +import Graphics.SvgTree (pattern ClipPathTree, pattern None, Tree, clipPathRef, + clipRule, mapTree, parseSvgFile, strokeColor) import Reanimate.Animation (SVG) import Reanimate.Cache (cacheDiskSvg, cacheMem) import Reanimate.External (zipArchive) @@ -128,7 +128,7 @@ xelatex = xelatexWithHeaders [] -- | Invoke xelatex with extra script headers. xelatexWithHeaders :: [T.Text] -> T.Text -> Tree -xelatexWithHeaders = someTexWithHeaders XeLaTeX "xelatex" "xdv" [] ["-no-pdf"] +xelatexWithHeaders = someTexWithHeaders XeLaTeX "xelatex" "xdv" ["-no-pdf"] [] -- | Invoke xelatex with "\usepackage[UTF8]{ctex}" and import the result as an -- SVG object. SVG objects are cached to improve performance. Xelatex has From 9944af167e16905c63c67284033a37da50ff97b0 Mon Sep 17 00:00:00 2001 From: Krantz-XRF Date: Sun, 11 Oct 2020 16:40:17 +0800 Subject: [PATCH 014/114] add latexCfgChunks --- src/Reanimate/LaTeX.hs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index 52788cd..1972ae9 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -109,17 +109,23 @@ someTexWithHeaders engine exec dvi args headers postscript tex = where script = mkTexScript exec args headers (T.unlines (postscript ++ [tex])) --- | Invoke latex and separate results. -latexChunks :: [T.Text] -> [Tree] -latexChunks chunks | pNoExternals = map mkText chunks -latexChunks chunks = worker (svgGlyphs $ latex $ T.concat chunks) chunks +-- | Invoke latex using a given configuration and separate results. +latexCfgChunks :: TexConfig -> [T.Text] -> [Tree] +latexCfgChunks _cfg chunks | pNoExternals = map mkText chunks +latexCfgChunks cfg chunks = worker chunks $ svgGlyphs $ tex $ T.concat chunks where + tex = latexCfg cfg merge lst = mkGroup [fmt svg | (fmt, _, svg) <- lst] worker [] [] = [] - worker _ [] = error "latex chunk mismatch" - worker everything (x : xs) = - let width = length $ svgGlyphs (latex x) - in merge (take width everything) : worker (drop width everything) xs + worker [] _ = error "latex chunk mismatch" + worker (x : xs) everything = + let width = length $ svgGlyphs (tex x) + (first, rest) = splitAt width everything + in merge first : worker xs rest + +-- | Invoke latex and separate results. +latexChunks :: [T.Text] -> [Tree] +latexChunks = latexCfgChunks (TexConfig LaTeX [] []) -- | Invoke xelatex and import the result as an SVG object. SVG objects are -- cached to improve performance. Xelatex has support for non-western scripts. From 04c3fd6baf3b8b466b220a6aa3683bbbea5adaf9 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Tue, 27 Oct 2020 17:10:11 +0800 Subject: [PATCH 015/114] Drop chalkduster from fonts example. --- ChangeLog.md | 11 +++++++++++ playground/snippets/10_Fonts.hs | 3 +-- reanimate.cabal | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 07e2811..4a62969 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and the project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org) +## 1.1.2.0 -- 2020-10-27 + +### Added + + * Reanimate.LaTeX.latexCfgChunks. + +### Other/Non-visible + + * xeLaTeX bug fixes. + * Documentation for external data sets. + ## 1.1.1.0 -- 2020-10-10 ### Added diff --git a/playground/snippets/10_Fonts.hs b/playground/snippets/10_Fonts.hs index 4fd22d5..4f99afe 100644 --- a/playground/snippets/10_Fonts.hs +++ b/playground/snippets/10_Fonts.hs @@ -4,8 +4,7 @@ fonts = , ("Calligra", calligra) , ("Noto", noto) , ("Helvetica", helvet) - , ("Liberine", libertine) - , ("Chalkduster", chalkduster) ] + , ("Liberine", libertine) ] animation :: Animation animation = env $ diff --git a/reanimate.cabal b/reanimate.cabal index 5382df0..26e5ff0 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.1.0 +version: 1.1.2.0 -- synopsis: -- description: license: PublicDomain From 5da40eda1bf579d9f6da7d41d13dddace2b9fb84 Mon Sep 17 00:00:00 2001 From: Xie Ruifeng Date: Tue, 27 Oct 2020 16:43:12 +0800 Subject: [PATCH 016/114] fix LaTeX: headers and postscripts got swapped --- src/Reanimate/LaTeX.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index 1972ae9..ea68595 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -69,7 +69,7 @@ data TexConfig = TexConfig -- | Render TeX script using a given configuration. latexCfg :: TexConfig -> T.Text -> SVG latexCfg (TexConfig engine headers postscript) = - gen headers postscript + gen postscript headers where gen = case engine of @@ -101,9 +101,9 @@ someTexWithHeaders :: [T.Text] -> T.Text -> Tree -someTexWithHeaders _engine _exec _dvi _args _headers _postscript tex +someTexWithHeaders _engine _exec _dvi _args _postscript _headers tex | pNoExternals = mkText tex -someTexWithHeaders engine exec dvi args headers postscript tex = +someTexWithHeaders engine exec dvi args postscript headers tex = (unsafePerformIO . (cacheMem . cacheDiskSvg) (latexToSVG engine dvi exec args)) script where From 4e38c3249f212bd4fc91536cd0ae7f1661cce845 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Tue, 27 Oct 2020 19:00:23 +0800 Subject: [PATCH 017/114] Bump version to 1.1.2.1 --- reanimate.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reanimate.cabal b/reanimate.cabal index 26e5ff0..75c04d2 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.2.0 +version: 1.1.2.1 -- synopsis: -- description: license: PublicDomain From eca9226126203302ffc88836b806357d0052ecf7 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Wed, 28 Oct 2020 16:49:36 +0800 Subject: [PATCH 018/114] Add shared docker image for discord-bot and playground. --- Dockerfile.base | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Dockerfile.base diff --git a/Dockerfile.base b/Dockerfile.base new file mode 100644 index 0000000..d37791d --- /dev/null +++ b/Dockerfile.base @@ -0,0 +1,34 @@ +FROM haskell:8.8.4 + +ENV LANG=C.UTF-8 \ + LC_ALL=C.UTF-8 \ + PATH=/root/.local/bin:$PATH \ + CUDA_PATH=/usr/local/cuda-$CUDA_VERSION \ + CPATH=$JVM_PATH/include:$JVM_PATH/include/linux:$LLVM_PATH/include \ + DEBIAN_FRONTEND=noninteractive + + +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + libblas-dev liblapack-dev ffmpeg \ + curl blender povray texlive texlive-latex-base texlive-latex-extra \ + texlive-fonts-extra texlive-science texlive-xetex \ + texlive-latex-recommended texlive-lang-english \ + texlive-lang-chinese texlive-plain-generic \ + unzip + +WORKDIR /src + +# Install reanimate dependencies and cache the layer +ADD reanimate.cabal stack.yaml ./ +RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock + +# Add source after dependencies have been installed as to not invalidate the caches +ADD data data +ADD src src +ADD .git .git +ADD viewer-elm viewer-elm +ADD Setup.hs ./ + +# Build reanimate +RUN stack build --no-install-ghc --system-ghc From fce34e92b27ee3eead8e791ead8b818ffab1462c Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Wed, 28 Oct 2020 17:03:09 +0800 Subject: [PATCH 019/114] Simplify base docker image. --- Dockerfile.base | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/Dockerfile.base b/Dockerfile.base index d37791d..f05e6e6 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -11,24 +11,8 @@ ENV LANG=C.UTF-8 \ RUN apt-get update && \ apt-get install -y --no-install-recommends \ libblas-dev liblapack-dev ffmpeg \ - curl blender povray texlive texlive-latex-base texlive-latex-extra \ + curl texlive texlive-latex-base texlive-latex-extra \ texlive-fonts-extra texlive-science texlive-xetex \ texlive-latex-recommended texlive-lang-english \ texlive-lang-chinese texlive-plain-generic \ unzip - -WORKDIR /src - -# Install reanimate dependencies and cache the layer -ADD reanimate.cabal stack.yaml ./ -RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock - -# Add source after dependencies have been installed as to not invalidate the caches -ADD data data -ADD src src -ADD .git .git -ADD viewer-elm viewer-elm -ADD Setup.hs ./ - -# Build reanimate -RUN stack build --no-install-ghc --system-ghc From 47dcf6471cb19e4e00c52ae005b686c80b83ca14 Mon Sep 17 00:00:00 2001 From: lemmih Date: Fri, 30 Oct 2020 20:19:42 +0800 Subject: [PATCH 020/114] Correct documentation for 'parDropA'. --- src/Reanimate/Animation.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Reanimate/Animation.hs b/src/Reanimate/Animation.hs index 315c7b2..ffe2378 100644 --- a/src/Reanimate/Animation.hs +++ b/src/Reanimate/Animation.hs @@ -148,7 +148,7 @@ parLoopA (Animation d1 f1) (Animation d2 f2) = -- -- Example: -- --- @'Reanimate.Builtin.Documentation.drawBox' `'parLoopA'` 'adjustDuration' (*2) 'Reanimate.Builtin.Documentation.drawCircle'@ +-- @'Reanimate.Builtin.Documentation.drawBox' `'parDropA'` 'adjustDuration' (*2) 'Reanimate.Builtin.Documentation.drawCircle'@ -- -- <> parDropA :: Animation -> Animation -> Animation From 81bf85bea8aed656699cab78d2296ab88544952d Mon Sep 17 00:00:00 2001 From: Xie Ruifeng Date: Sun, 8 Nov 2020 14:52:41 +0800 Subject: [PATCH 021/114] LaTeX: extend latex[Cfg]Chunks to use Traversable --- src/Reanimate/LaTeX.hs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index ea68595..50c6380 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -35,7 +35,9 @@ module Reanimate.LaTeX where import Control.Lens ((&), (.~)) +import Control.Monad.State (runState, state) import qualified Data.ByteString as B +import Data.Foldable (Foldable (fold)) import Data.Hashable (Hashable) import Data.Monoid (Last (Last)) import Data.Text (Text) @@ -43,8 +45,8 @@ import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import GHC.Generics (Generic) -import Graphics.SvgTree (pattern ClipPathTree, pattern None, Tree, clipPathRef, - clipRule, mapTree, parseSvgFile, strokeColor) +import Graphics.SvgTree (Tree, clipPathRef, clipRule, mapTree, parseSvgFile, + pattern ClipPathTree, pattern None, strokeColor) import Reanimate.Animation (SVG) import Reanimate.Cache (cacheDiskSvg, cacheMem) import Reanimate.External (zipArchive) @@ -110,21 +112,22 @@ someTexWithHeaders engine exec dvi args postscript headers tex = script = mkTexScript exec args headers (T.unlines (postscript ++ [tex])) -- | Invoke latex using a given configuration and separate results. -latexCfgChunks :: TexConfig -> [T.Text] -> [Tree] -latexCfgChunks _cfg chunks | pNoExternals = map mkText chunks -latexCfgChunks cfg chunks = worker chunks $ svgGlyphs $ tex $ T.concat chunks +latexCfgChunks :: Traversable t => TexConfig -> t T.Text -> t Tree +latexCfgChunks _cfg chunks | pNoExternals = fmap mkText chunks +latexCfgChunks cfg chunks = worker $ svgGlyphs $ tex $ fold chunks where tex = latexCfg cfg merge lst = mkGroup [fmt svg | (fmt, _, svg) <- lst] - worker [] [] = [] - worker [] _ = error "latex chunk mismatch" - worker (x : xs) everything = + checkResult (r, []) = r + checkResult (_, _) = error "latex chunk mismatch" + worker = checkResult . runState (mapM (state . workerSingle) chunks) + workerSingle x everything = let width = length $ svgGlyphs (tex x) (first, rest) = splitAt width everything - in merge first : worker xs rest + in (merge first, rest) -- | Invoke latex and separate results. -latexChunks :: [T.Text] -> [Tree] +latexChunks :: Traversable t => t T.Text -> t Tree latexChunks = latexCfgChunks (TexConfig LaTeX [] []) -- | Invoke xelatex and import the result as an SVG object. SVG objects are From aed68fe34ab9fd9f3e73f925ee493ae66afdc23e Mon Sep 17 00:00:00 2001 From: Xie Ruifeng Date: Sun, 8 Nov 2020 18:25:04 +0800 Subject: [PATCH 022/114] export latexCfgChunks --- src/Reanimate/LaTeX.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index 50c6380..e0fdc5f 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -16,6 +16,7 @@ module Reanimate.LaTeX latex, latexWithHeaders, latexChunks, + latexCfgChunks, xelatex, xelatexWithHeaders, ctex, From 828b0335047f7a1a2c915bb97a4e0c1b3110123c Mon Sep 17 00:00:00 2001 From: Xie Ruifeng Date: Sun, 8 Nov 2020 18:25:50 +0800 Subject: [PATCH 023/114] add mathChunks/latexCfgChunksTrans --- src/Reanimate/LaTeX.hs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index e0fdc5f..97338e9 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -17,6 +17,8 @@ module Reanimate.LaTeX latexWithHeaders, latexChunks, latexCfgChunks, + latexCfgChunksTrans, + mathChunks, xelatex, xelatexWithHeaders, ctex, @@ -69,6 +71,9 @@ data TexConfig = TexConfig } deriving (Generic, Hashable, Read, Show, Eq, Ord) +defaultTexConfig :: TexConfig +defaultTexConfig = TexConfig LaTeX [] [] + -- | Render TeX script using a given configuration. latexCfg :: TexConfig -> T.Text -> SVG latexCfg (TexConfig engine headers postscript) = @@ -113,23 +118,33 @@ someTexWithHeaders engine exec dvi args postscript headers tex = script = mkTexScript exec args headers (T.unlines (postscript ++ [tex])) -- | Invoke latex using a given configuration and separate results. -latexCfgChunks :: Traversable t => TexConfig -> t T.Text -> t Tree -latexCfgChunks _cfg chunks | pNoExternals = fmap mkText chunks -latexCfgChunks cfg chunks = worker $ svgGlyphs $ tex $ fold chunks +-- Apply the transformation to the LaTeX segments. +-- See also 'mathChunks', the transformation is @(\s -> "$" <> s <> "$")@. +latexCfgChunksTrans :: Traversable t => TexConfig -> (T.Text -> T.Text) -> t T.Text -> t Tree +latexCfgChunksTrans _cfg f chunks | pNoExternals = fmap (mkText . f) chunks +latexCfgChunksTrans cfg f chunks = worker $ svgGlyphs $ tex $ f $ fold chunks where tex = latexCfg cfg merge lst = mkGroup [fmt svg | (fmt, _, svg) <- lst] checkResult (r, []) = r checkResult (_, _) = error "latex chunk mismatch" - worker = checkResult . runState (mapM (state . workerSingle) chunks) + worker = checkResult . runState (mapM (state . workerSingle) (fmap f chunks)) workerSingle x everything = let width = length $ svgGlyphs (tex x) (first, rest) = splitAt width everything in (merge first, rest) +-- | Render math formula and separate results. +mathChunks :: Traversable t => t T.Text -> t Tree +mathChunks = latexCfgChunksTrans defaultTexConfig (\s -> "$" <> s <> "$") + +-- | Invoke latex using a given configuration and separate results. +latexCfgChunks :: Traversable t => TexConfig -> t T.Text -> t Tree +latexCfgChunks cfg = latexCfgChunksTrans cfg id + -- | Invoke latex and separate results. latexChunks :: Traversable t => t T.Text -> t Tree -latexChunks = latexCfgChunks (TexConfig LaTeX [] []) +latexChunks = latexCfgChunksTrans defaultTexConfig id -- | Invoke xelatex and import the result as an SVG object. SVG objects are -- cached to improve performance. Xelatex has support for non-western scripts. From ccc69c0d834b821ec6469c1ecee9cb88c39c1704 Mon Sep 17 00:00:00 2001 From: Xie Ruifeng Date: Sun, 8 Nov 2020 18:31:43 +0800 Subject: [PATCH 024/114] add an example for using mathChunks with non-trivial Traversable --- examples/expression.hs | 101 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 examples/expression.hs diff --git a/examples/expression.hs b/examples/expression.hs new file mode 100644 index 0000000..ed090ad --- /dev/null +++ b/examples/expression.hs @@ -0,0 +1,101 @@ +#!/usr/bin/env stack +-- stack runghc --package reanimate +{-# LANGUAGE OverloadedStrings #-} +module Main (main) where + +import Codec.Picture (PixelRGBA8 (PixelRGBA8)) +import Control.Arrow ((&&&)) +import Control.Lens ((.~)) +import Control.Monad (when) +import Data.Foldable (forM_) +import qualified Data.Text as T +import Reanimate +import Reanimate.Builtin.Documentation (docEnv) +import Reanimate.LaTeX (mathChunks) +import Reanimate.Scene + +import Data.Bifoldable (Bifoldable (..), biforM_) +import Data.Bifunctor (Bifunctor (..)) +import Data.Bitraversable (Bitraversable (..)) + +data Expr op v + = Var v + | BinOp (Expr op v) op (Expr op v) + | Paren op (Expr op v) op + deriving (Show, Eq) + +data Op = Add | Minus | LeftParen | RightParen deriving (Show, Eq) + +oNewExpr :: Scene s (Expr (Op, Object s SVG) (T.Text, Object s SVG)) +oNewExpr = bothAlongside (mapM (oNew . translate (-4) 0 . scale 2) . mathChunks) + $ bimap (id &&& op2LaTeX) (id &&& id) expr + where bothAlongside f = fmap runBiAlongside . fmap runBoth . f . Both . BiAlongside + expr = Var "x" `minus` paren (Var "y" `add` Var "x") + +main :: IO () +main = reanimate $ docEnv $ mapA (withFillOpacity 1 . withStrokeWidth 0) $ scene $ do + expr <- oNewExpr + forM_ (Both $ BiAlongside expr) (`oShowWith` oDraw) + let changeColor t = oContext .~ withFillColorPixel (PixelRGBA8 (round (t * 255)) 0 0 255) + let changeColorRev t = changeColor (1 - t) + waitOn $ biforM_ expr pure $ \(x, o) -> + when (x == "x") $ fork $ do + oTween o 1 changeColor + oTween o 1 changeColorRev + forM_ (Both $ BiAlongside expr) (fork . (`oHideWith` oFadeOut)) + +-- Some supportive functions. + +add, minus :: Expr Op v -> Expr Op v -> Expr Op v +add x y = BinOp x Add y +minus x y = BinOp x Minus y + +paren :: Expr Op v -> Expr Op v +paren x = Paren LeftParen x RightParen + +op2LaTeX :: Op -> T.Text +op2LaTeX Add = "+" +op2LaTeX Minus = "-" +op2LaTeX LeftParen = "(" +op2LaTeX RightParen = ")" + +-- Some supportive types and instances. + +instance Bifunctor Expr where + bimap _ g (Var x) = Var (g x) + bimap f g (BinOp x op y) = BinOp (bimap f g x) (f op) (bimap f g y) + bimap f g (Paren l x r) = Paren (f l) (bimap f g x) (f r) + +instance Bifoldable Expr where + bifoldMap _ g (Var x) = g x + bifoldMap f g (BinOp x op y) = bifoldMap f g x <> f op <> bifoldMap f g y + bifoldMap f g (Paren l x r) = f l <> bifoldMap f g x <> f r + +instance Bitraversable Expr where + bitraverse _ g (Var x) = Var <$> g x + bitraverse f g (BinOp x op y) = BinOp <$> bitraverse f g x <*> f op <*> bitraverse f g y + bitraverse f g (Paren l x r) = Paren <$> f l <*> bitraverse f g x <*> f r + +-- | Given a bifunctor @f@, make a functor @Both f@ where @Both f a ~ f a a@. +newtype Both f a = Both { runBoth :: f a a } + +instance Bifunctor p => Functor (Both p) where + fmap f = Both . bimap f f . runBoth + +instance Bifoldable p => Foldable (Both p) where + foldMap f = bifoldMap f f . runBoth + +instance Bitraversable p => Traversable (Both p) where + traverse f = fmap Both . bitraverse f f . runBoth + +-- | Make a bifunctor @f (a, -) (b, -)@ (namely @BiAlongside a b f@) out of @f@. +newtype BiAlongside a b f x y = BiAlongside { runBiAlongside :: f (a, x) (b, y) } + +instance Bifunctor p => Bifunctor (BiAlongside a b p) where + bimap f g = BiAlongside . bimap (second f) (second g) . runBiAlongside + +instance Bifoldable p => Bifoldable (BiAlongside a b p) where + bifoldMap f g = bifoldMap (f . snd) (g . snd) . runBiAlongside + +instance Bitraversable p => Bitraversable (BiAlongside a b p) where + bitraverse f g = fmap BiAlongside . bitraverse (traverse f) (traverse g) . runBiAlongside From acbaefd723f49734305d787bda556640acd7a2bb Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Wed, 28 Oct 2020 20:52:35 +0800 Subject: [PATCH 025/114] Increase shared storage between playground and discord-bot images. --- Dockerfile.base | 7 +++++++ Dockerfile.discord | 23 ++--------------------- Dockerfile.playground | 26 +++----------------------- 3 files changed, 12 insertions(+), 44 deletions(-) diff --git a/Dockerfile.base b/Dockerfile.base index f05e6e6..50951ab 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -16,3 +16,10 @@ RUN apt-get update && \ texlive-latex-recommended texlive-lang-english \ texlive-lang-chinese texlive-plain-generic \ unzip + +WORKDIR /src + +# Install reanimate dependencies and cache the layer +ADD reanimate.cabal stack.yaml ./ +RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock +RUN rm reanimate.cabal stack.yaml diff --git a/Dockerfile.discord b/Dockerfile.discord index dbb12c8..f90fc55 100644 --- a/Dockerfile.discord +++ b/Dockerfile.discord @@ -1,29 +1,10 @@ -FROM haskell:8.8.4 - -ENV LANG=C.UTF-8 \ - LC_ALL=C.UTF-8 \ - PATH=/root/.local/bin:$PATH \ - CUDA_PATH=/usr/local/cuda-$CUDA_VERSION \ - CPATH=$JVM_PATH/include:$JVM_PATH/include/linux:$LLVM_PATH/include \ - DEBIAN_FRONTEND=noninteractive - - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - libblas-dev liblapack-dev ffmpeg \ - curl blender povray texlive texlive-latex-base texlive-latex-extra \ - texlive-fonts-extra texlive-science texlive-xetex \ - texlive-latex-recommended texlive-lang-english \ - texlive-lang-chinese texlive-plain-generic +FROM reanimate/base WORKDIR /src # Install reanimate dependencies and cache the layer ADD reanimate.cabal stack.yaml ./ -RUN for i in 1 2 3; \ - do \ - stack build --only-dependencies --no-install-ghc --system-ghc --haddock && break; \ - done +RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock # Install discord-bot dependencies and cache the layer ADD discord-bot/discord-bot.cabal discord-bot/stack.yaml ./discord-bot/ diff --git a/Dockerfile.playground b/Dockerfile.playground index c52800e..bbc3ea2 100644 --- a/Dockerfile.playground +++ b/Dockerfile.playground @@ -1,32 +1,12 @@ -FROM haskell:8.8.4 - -ENV LANG=C.UTF-8 \ - LC_ALL=C.UTF-8 \ - PATH=/root/.local/bin:$PATH \ - CUDA_PATH=/usr/local/cuda-$CUDA_VERSION \ - CPATH=$JVM_PATH/include:$JVM_PATH/include/linux:$LLVM_PATH/include \ - DEBIAN_FRONTEND=noninteractive - - -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - libblas-dev liblapack-dev ffmpeg \ - curl blender povray texlive texlive-latex-base texlive-latex-extra \ - texlive-fonts-extra texlive-science texlive-xetex \ - texlive-latex-recommended texlive-lang-english \ - texlive-lang-chinese texlive-plain-generic \ - unzip +FROM reanimate/base WORKDIR /src # Install reanimate dependencies and cache the layer ADD reanimate.cabal stack.yaml ./ -RUN for i in 1 2 3; \ - do \ - stack build --only-dependencies --no-install-ghc --system-ghc --haddock && break || echo "retry"; \ - done +RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock -# Install discord-bot dependencies and cache the layer +# Install playground dependencies and cache the layer ADD playground/playground.cabal playground/stack.yaml ./playground/ RUN cd playground && \ stack build --only-dependencies --no-install-ghc --system-ghc From 1181e0f802e00c969594f1ebfc84da1d1ce8e9ea Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 14 Dec 2020 12:05:20 +0800 Subject: [PATCH 026/114] Bump deployment script version. --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 2416609..a3414d3 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -101,7 +101,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@3.5.9 + uses: JamesIves/github-pages-deploy-action@3.7.1 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From 16fd952c9ad6cb39e43996856ad744f1494e1036 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 13:17:34 +0800 Subject: [PATCH 027/114] Rework live reloading. (#191) --- .azure/azure-linux-template.yml | 3 - .azure/azure-osx-template.yml | 3 - .azure/azure-windows-template.yml | 4 - reanimate.cabal | 13 +- src/Reanimate.hs | 2 + src/Reanimate/Driver.hs | 92 ++++---- src/Reanimate/Driver/CLI.hs | 16 +- src/Reanimate/Driver/Compile.hs | 35 --- src/Reanimate/Driver/Daemon.hs | 154 ++++++++++++ src/Reanimate/Driver/Server.hs | 376 ++++++++++-------------------- src/Reanimate/Render.hs | 24 ++ stack-lts-13.yaml | 23 -- stack-lts-14.yaml | 1 + stack.yaml | 2 +- unix/Detach.hs | 19 ++ windows/Detach.hs | 10 + 16 files changed, 385 insertions(+), 392 deletions(-) delete mode 100644 src/Reanimate/Driver/Compile.hs create mode 100644 src/Reanimate/Driver/Daemon.hs delete mode 100644 stack-lts-13.yaml create mode 100644 unix/Detach.hs create mode 100644 windows/Detach.hs diff --git a/.azure/azure-linux-template.yml b/.azure/azure-linux-template.yml index a343c5a..76a9748 100644 --- a/.azure/azure-linux-template.yml +++ b/.azure/azure-linux-template.yml @@ -17,9 +17,6 @@ jobs: stack-lts-14: BUILD: stack STACK_YAML: stack-lts-14.yaml - stack-lts-13: - BUILD: stack - STACK_YAML: stack-lts-13.yaml stack-nightly: BUILD: stack ARGS: --resolver nightly --no-run-tests diff --git a/.azure/azure-osx-template.yml b/.azure/azure-osx-template.yml index 0484a91..14d5ef6 100644 --- a/.azure/azure-osx-template.yml +++ b/.azure/azure-osx-template.yml @@ -17,9 +17,6 @@ jobs: stack-lts-14: BUILD: stack STACK_YAML: stack-lts-14.yaml - stack-lts-13: - BUILD: stack - STACK_YAML: stack-lts-13.yaml maxParallel: 6 steps: - task: Cache@2 diff --git a/.azure/azure-windows-template.yml b/.azure/azure-windows-template.yml index f4429e2..eca3764 100644 --- a/.azure/azure-windows-template.yml +++ b/.azure/azure-windows-template.yml @@ -20,10 +20,6 @@ jobs: BUILD: stack STACK_YAML: stack-lts-14.yaml ARGS: --no-run-tests - stack-lts-13: - BUILD: stack - STACK_YAML: stack-lts-13.yaml - ARGS: --no-run-tests maxParallel: 6 steps: - task: Cache@2 diff --git a/reanimate.cabal b/reanimate.cabal index 75c04d2..90bd567 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -39,6 +39,11 @@ Source-Repository head library hs-source-dirs: src + if os(windows) + hs-source-dirs: windows + else + hs-source-dirs: unix + build-depends: unix default-language: Haskell2010 default-extensions: PackageImports, PatternSynonyms exposed-modules: Reanimate @@ -91,13 +96,14 @@ library Reanimate.Driver.CLI Reanimate.Driver.Magick Reanimate.Driver.Server - Reanimate.Driver.Compile + Reanimate.Driver.Daemon Reanimate.Misc Paths_reanimate Reanimate.Scene.Core Reanimate.Scene.Var Reanimate.Scene.Sprite Reanimate.Scene.Object + Detach autogen-modules: Paths_reanimate build-depends: base >=4.10 && <5, @@ -119,7 +125,6 @@ library fingertree >=0.1.0.0, fsnotify >=0.3.0.1, geojson >=3.0.4, - ghcid >=0.7, hashable >=1.3.0.0, hgeometry >=0.11.0.0, hgeometry-combinatorial >=0.11.0.0, @@ -145,9 +150,11 @@ library websockets >=0.12.7.0, xml >=1.3.14, cryptohash-sha256, - base64-bytestring + base64-bytestring, + network >=3.1.0.0 ghc-options: -Wall -fno-ignore-asserts + test-suite spec type: exitcode-stdio-1.0 main-is: Spec.hs diff --git a/src/Reanimate.hs b/src/Reanimate.hs index 28de64b..ee8dfd2 100644 --- a/src/Reanimate.hs +++ b/src/Reanimate.hs @@ -35,6 +35,7 @@ no other parameters are given. Key features: -} module Reanimate ( reanimate, + reanimateLive, -- * Animations SVG, Time, @@ -196,6 +197,7 @@ import Reanimate.Blender import Reanimate.ColorMap import Reanimate.Constants import Reanimate.Driver +import Reanimate.Driver.Daemon import Reanimate.LaTeX import Reanimate.Parameters import Reanimate.Povray diff --git a/src/Reanimate/Driver.hs b/src/Reanimate/Driver.hs index a25e793..36fd2a5 100644 --- a/src/Reanimate/Driver.hs +++ b/src/Reanimate/Driver.hs @@ -5,16 +5,16 @@ module Reanimate.Driver where import Control.Applicative ((<|>)) +import Control.Concurrent import Control.Monad -import Data.Maybe import Data.Either -import Reanimate.Animation (Animation) -import Reanimate.Driver.Check +import Data.Maybe +import Reanimate.Animation (Animation, duration) import Reanimate.Driver.CLI -import Reanimate.Driver.Compile -import Reanimate.Driver.Server +import Reanimate.Driver.Check +import Reanimate.Driver.Daemon import Reanimate.Parameters -import Reanimate.Render (render, renderSnippets, renderSvgs, +import Reanimate.Render (render, renderSnippets, renderSvgs, renderSvgs_, selectRaster) import System.Directory import System.Exit @@ -116,7 +116,7 @@ reanimate animation = do -- hSetBinaryMode stdout True renderSnippets animation Check -> checkEnvironment - View {..} -> serve viewVerbose viewGHCPath viewGHCOpts viewOrigin + View {..} -> viewAnimation viewDetach animation Render {..} -> do let fmt = guessParameter renderFormat (fmap presetFormat renderPreset) @@ -132,7 +132,7 @@ reanimate animation = do target <- case renderTarget of Nothing -> do - mbSelf <- findOwnSource + mbSelf <- pure Nothing let ext = formatExtension fmt self = fromMaybe "output" mbSelf pure $ replaceExtension self ext @@ -161,47 +161,26 @@ reanimate animation = do exitWith (ExitFailure 1) return raster else selectRaster renderRaster + setRaster raster + setFPS fps + setWidth width + setHeight height + printf + "Animation options:\n\ + \ fps: %d\n\ + \ width: %d\n\ + \ height: %d\n\ + \ fmt: %s\n\ + \ target: %s\n\ + \ raster: %s\n" + fps + width + height + (showFormat fmt) + target + (show raster) - if renderCompile - then compile $ - [ "render" - , "--fps" - , show fps - , "--width" - , show width - , "--height" - , show height - , "--format" - , showFormat fmt - , "--raster" - , showRaster raster - , "--target" - , target - , "+RTS" - , "-N" - , "-RTS" - ] ++ [ "--partial" | renderPartial ] - else do - setRaster raster - setFPS fps - setWidth width - setHeight height - printf - "Animation options:\n\ - \ fps: %d\n\ - \ width: %d\n\ - \ height: %d\n\ - \ fmt: %s\n\ - \ target: %s\n\ - \ raster: %s\n" - fps - width - height - (showFormat fmt) - target - (show raster) - - render animation target raster fmt width height fps renderPartial + render animation target raster fmt width height fps renderPartial guessParameter :: Maybe a -> Maybe a -> a -> a guessParameter a b def = fromMaybe def (a <|> b) @@ -220,3 +199,20 @@ userPreferredDimensions Nothing Nothing = Nothing makeEven :: Int -> Int makeEven x | even x = x | otherwise = x - 1 + + +-- serve viewVerbose viewGHCPath viewGHCOpts viewOrigin +viewAnimation :: Bool -> Animation -> IO () +viewAnimation _detach animation = do + detached <- ensureDaemon + + let rate = 60 + count = round (duration animation * rate) :: Int + sendCommand $ DaemonCount count + renderSvgs_ animation $ \nth path -> do + sendCommand $ DaemonFrame nth path + + unless detached $ do + putStrLn "Daemon mode. Hit ctrl-c to terminate." + forever $ threadDelay (10^(6::Int)) + diff --git a/src/Reanimate/Driver/CLI.hs b/src/Reanimate/Driver/CLI.hs index 4a5b16a..f8976ec 100644 --- a/src/Reanimate/Driver/CLI.hs +++ b/src/Reanimate/Driver/CLI.hs @@ -27,10 +27,7 @@ data Command | Test | Check | View - { viewVerbose :: Bool - , viewGHCPath :: Maybe FilePath - , viewGHCOpts :: [String] - , viewOrigin :: Maybe FilePath + { viewDetach :: Bool } | Render { renderTarget :: Maybe String @@ -154,16 +151,7 @@ viewCommand = info parse where parse = View <$> switch - (long "verbose" <> short 'v') - <*> optional (strOption (long "ghc" - <> metavar "PATH" - <> help "Path to GHC binary")) - <*> many (strOption (long "ghc-opt" - <> short 'G' - <> help "Additional option to pass to ghc")) - <*> optional (strOption (long "self" - <> metavar "PATH" - <> help "Source file used for live-reloading")) + (long "detach" <> short 'd') renderCommand :: ParserInfo Command renderCommand = info parse diff --git a/src/Reanimate/Driver/Compile.hs b/src/Reanimate/Driver/Compile.hs deleted file mode 100644 index 272766d..0000000 --- a/src/Reanimate/Driver/Compile.hs +++ /dev/null @@ -1,35 +0,0 @@ -module Reanimate.Driver.Compile ( compile ) where - -import Reanimate.Driver.Server (findOwnSource) -import System.Directory -import System.Exit -import System.FilePath -import System.Process -import System.IO - -compile :: [String] -> IO () -compile opts = do - mbSelf <- findOwnSource - case mbSelf of - Nothing -> do - hPutStrLn stderr - "Failed to find source code. Did you already compile the animations?\n\ - \Try running again without the --compile flag." - exitFailure - Just self -> do - let selfDir = takeDirectory self - selfName = takeBaseName self - outDir = selfDir ".reanimate" selfName - target = outDir selfName - ghcOptions = - ["-rtsopts", "--make", "-threaded", "-O2"] ++ - ["-odir", outDir, "-hidir", outDir] ++ - [self, "-o", target] - createDirectoryIfMissing True outDir - withCurrentDirectory selfDir $ do - checkExitCode =<< rawSystem "stack" (["ghc", "--"] ++ ghcOptions) - checkExitCode =<< rawSystem target opts - -checkExitCode :: ExitCode -> IO () -checkExitCode ExitSuccess = return () -checkExitCode (ExitFailure n) = exitWith (ExitFailure n) diff --git a/src/Reanimate/Driver/Daemon.hs b/src/Reanimate/Driver/Daemon.hs new file mode 100644 index 0000000..c876273 --- /dev/null +++ b/src/Reanimate/Driver/Daemon.hs @@ -0,0 +1,154 @@ +module Reanimate.Driver.Daemon where + +import Control.Concurrent +import Control.Exception as E +import Control.Monad +import qualified Data.ByteString.Char8 as BS +import Network.Socket +import Network.Socket.ByteString +import qualified Reanimate.Driver.Server as Server +import System.FSNotify +import System.FilePath +import System.Environment + +import Detach + +{- +Main run message: + + Reanimate has gone into daemon mode and will block until you hit + ctrl-c. While Reanimate is in daemon mode, you can open a new + console or terminal and execute your animation code again. It'll + automatically send the new animation to the browser window. + + Linux users can pass --daemon to reanimate to run the process in + the background. Windows users have to use PowerShell and explicitly + fork the process: + Start-Process -NoNewWindow ./reanimate_exe + + Connection to the browser window will be lost if you hit ctrl-c. + + +Executing with daemon: + Send animation to daemon and exit. +Executing without daemon: + Run daemon locally. + Render animation once. + Wait without exiting. + Detach if given --daemon flag. Only for Linux. + +Executing on Linux: + Running 'main' will start the daemon if it isn't already running. + Then it'll render the animation and send it to the daemon. + The daemon will open a browser window. + Daemon stops after 30 minutes of inactivity. + +Executing on Windows: + 'main' will act as daemon and not return. + Powershell command for running in the background: + Start-Process -NoNewWindow ./reanimate_exe + + Subsequent runs will send animation to daemon and quit. + +In GHCi: + Start local daemon thread if necessary. + :cmd reanimateLive + 1. wait for changes + 2. ":r" + 3. ":main" + 4. ":cmd Reanimate.reanimateLive" + + + +Web port: 9161 +Daemon port: 9162? + +-} + +{- + Improvements over previous infrastructure: + - Multiple browser windows can be open. + - Browser window won't get stuck trying to open a connection. + - GHCi is robust and works with both cabal and stack. + - Refreshing the code will re-open closed browser windows. +-} + +reanimateLive :: IO String +reanimateLive = do + void ensureDaemon + args <- getArgs + case args of + ["primed"] -> waitForChanges + _ -> return () + return $ unlines + [ ":r" + , ":main" + , ":cmd System.Environment.withArgs [\"primed\"] Reanimate.reanimateLive" ] + +waitForChanges :: IO () +waitForChanges = withManager $ \mgr -> do + lock <- newEmptyMVar + stop <- watchTree mgr "." check (const $ putMVar lock ()) + takeMVar lock + stop + where + check event = + takeExtension (eventPath event) `elem` sourceExtensions || + takeExtension (eventPath event) `elem` dataExtensions + sourceExtensions = [".hs", ".lhs"] + dataExtensions = [".jpg", ".png", ".bmp", ".pov", ".tex", ".csv"] + + +data DaemonCommand + = DaemonCount Int + | DaemonFrame Int FilePath + | DaemonStop + deriving (Show) + +sendCommand :: DaemonCommand -> IO () +sendCommand cmd = withSocketsDo $ handle (\SomeException{} -> return ()) $ do + addr <- resolve + E.bracket (open addr) close $ \sock -> do + void $ send sock $ case cmd of + DaemonCount count -> BS.pack $ unwords ["frame_count", show count] + DaemonFrame nth path -> BS.pack $ unwords ["frame", show nth, path] + DaemonStop -> BS.pack $ unwords ["stop"] + return () + where + resolve = do + let hints = defaultHints { addrSocketType = Stream } + head <$> getAddrInfo (Just hints) (Just "127.0.0.1") (Just "9162") + open addr = E.bracketOnError (oSocket addr) close $ \sock -> do + connect sock $ addrAddress addr + return sock + +hasDaemon :: IO Bool +hasDaemon = withSocketsDo $ handle (\SomeException{} -> return False) $ do + addr <- resolve + E.bracket (open addr) close (const $ return True) + where + resolve = do + let hints = defaultHints { addrSocketType = Stream } + head <$> getAddrInfo (Just hints) (Just "127.0.0.1") (Just "9162") + open addr = E.bracketOnError (oSocket addr) close $ \sock -> do + connect sock $ addrAddress addr + return sock + +oSocket :: AddrInfo -> IO Socket +oSocket addr = socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) + +ensureDaemon :: IO Bool +ensureDaemon = do + daemon <- hasDaemon + if daemon + then pure True + else localDaemon + +killDaemon :: IO () +killDaemon = sendCommand DaemonStop + +localDaemon :: IO Bool +localDaemon = do + killDaemon + detach Server.daemon + diff --git a/src/Reanimate/Driver/Server.hs b/src/Reanimate/Driver/Server.hs index 9f97d96..acd0727 100644 --- a/src/Reanimate/Driver/Server.hs +++ b/src/Reanimate/Driver/Server.hs @@ -1,286 +1,146 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ScopedTypeVariables #-} module Reanimate.Driver.Server - ( serve - , findOwnSource + ( daemon ) where import Control.Concurrent -import Control.Exception (SomeException, catch, finally) -import Control.Monad -import Data.IORef -import Data.Text (Text) -import qualified Data.Text as T -import qualified Data.Text.Read as T -import Data.Time -import GHC.Environment (getFullArgs) -import Language.Haskell.Ghcid +import Control.Exception (finally) +import qualified Control.Exception as E +import Control.Monad (forM_, forever, unless, void, when) +import qualified Data.ByteString.Char8 as BS +import qualified Data.Foldable as F +import qualified Data.Map as Map +import qualified Data.Text as T +import Network.Socket (AddrInfo (..), AddrInfoFlag (..), SocketOption (..), + SocketType (Stream), accept, bind, close, defaultHints, + getAddrInfo, gracefulClose, listen, socket, + setCloseOnExecIfNeeded, setSocketOption, withFdSocket, + withSocketsDo) +import Network.Socket.ByteString (recv) import Network.WebSockets -import Paths_reanimate -import Reanimate.Misc (runCmdLazy, runCmd_) -import System.Directory (createDirectoryIfMissing, - doesFileExist, findFile, listDirectory, - makeAbsolute, - withCurrentDirectory) -import System.Environment (getProgName) -import System.Exit -import System.FilePath -import System.FSNotify -import System.IO -import System.IO.Temp -import System.Process -import Web.Browser (openBrowser) +import Paths_reanimate (getDataFileName) +import System.IO (hPutStrLn, stderr) +import Web.Browser (openBrowser) opts :: ConnectionOptions opts = defaultConnectionOptions { connectionCompressionOptions = PermessageDeflateCompression defaultPermessageDeflate } -serve :: Bool -> Maybe FilePath -> [String] -> Maybe FilePath -> IO () -serve verbose mbGHCPath extraGHCOpts mbSelfPath = withManager $ \watch -> do - hSetBuffering stdin NoBuffering - self <- maybe requireOwnSource pure mbSelfPath - when verbose $ - logMsg $ "Found own source code at: " ++ self - hasConnectionVar <- newMVar False - ghci <- ghciBackend mbGHCPath self - -- There might already browser window open. Wait 2s to see if that window - -- connects to us. If not, open a new window. - _ <- forkIO $ do - threadDelay (2*10^(6::Int)) - hasConn <- readMVar hasConnectionVar - unless hasConn openViewer - logMsg "Listening..." +daemon :: IO () +daemon = do + state <- newMVar (0, Map.empty) + connsRef <- newMVar Map.empty + + self <- myThreadId + + dTid <- daemonReceive self $ \msg -> + case msg of + WebStatus _status -> return () + WebError _err -> return () + WebFrameCount count -> do + void $ swapMVar state (count, Map.empty) + conns <- readMVar connsRef + F.forM_ conns $ \(conn) -> do + sendWebMessage conn (WebFrameCount count) + when (Map.null conns) openViewer + WebFrame nth path -> do + modifyMVar_ state $ \(count, frames) -> + pure (count, Map.insert nth path frames) + conns <- readMVar connsRef + F.forM_ conns $ \conn -> do + sendWebMessage conn (WebFrame nth path) + + openViewer + let options = ServerOptions { serverHost = "127.0.0.1" , serverPort = 9161 , serverConnectionOptions = opts , serverRequirePong = Nothing } - withSystemTempDirectory "reanimate-svgs" $ \tmpDir -> - runServerWithOptions options $ \pending -> do - logMsg "New connection received." - hasConn <- swapMVar hasConnectionVar True - if hasConn - then do - logMsg "Already connected to browser. Rejecting." - rejectRequestWith pending defaultRejectRequest - else do - createDirectoryIfMissing True tmpDir - conn <- acceptRequest pending - slave <- newEmptyMVar - let handler = modifyMVar_ slave $ \tid -> do - logMsg "Reloading code..." - killThread tid - forkIO $ ignoreErrors $ slaveHandler verbose mbGHCPath extraGHCOpts conn ghci self tmpDir - killSlave = do - tid <- takeMVar slave - killThread tid - stop <- watchFile watch self handler - putMVar slave =<< forkIO (return ()) - handler - let loop = do - -- FIXME: We don't use msg here. - _msg <- receiveData conn :: IO T.Text - handler - loop - cleanup = do - stop - killSlave - _ <- swapMVar hasConnectionVar False - return () - loop `finally` cleanup -ignoreErrors :: IO () -> IO () -ignoreErrors action = action `catch` \(_::SomeException) -> return () + logMsg "WS server is running." + + + runServerWithOptions options (\pending -> do + tid <- myThreadId + + conn <- acceptRequest pending + + modifyMVar_ connsRef $ pure . Map.insert tid conn + + conns <- readMVar connsRef + logMsg $ "Browser connections: " ++ show (Map.size conns) + + (count, frames) <- readMVar state + when (count > 0) $ do + sendWebMessage conn (WebFrameCount count) + forM_ (Map.toList frames) $ \(nth, path) -> + sendWebMessage conn (WebFrame nth path) + + let loop = do + -- FIXME: We don't use msg here. + _msg <- receiveData conn :: IO T.Text + loop + cleanup = do + modifyMVar_ connsRef $ pure . Map.delete tid + nConns <- Map.size <$> readMVar connsRef + logMsg $ "Browser connections: " ++ show nConns + when (nConns == 0) $ do + threadDelay (second * 5) + nConns' <- Map.size <$> readMVar connsRef + logMsg $ "Browser connections (check): " ++ show nConns' + when (nConns'==0) $ killThread self + loop `finally` cleanup) + `finally` (killThread dTid >> logMsg "daemon server quit") + `E.catch` (\e@E.SomeException{} -> logMsg $ "Exception: " ++ show e) + +second :: Int +second = 10^(6::Int) + +logMsg :: String -> IO () +logMsg msg = appendFile "log" (msg++"\n") + +daemonReceive :: ThreadId -> (WebMessage -> IO ()) -> IO ThreadId +daemonReceive parent cb = withSocketsDo $ do + addr <- resolve + sock <- open addr + logMsg "daemon sock is open" + forkIO $ handler sock `finally` close sock + where + handler sock = forever $ E.bracketOnError (accept sock) (close . fst) $ \(conn, _peer) -> do + inp <- BS.unpack <$> recv conn 4096 + case words inp of + ["frame_count", n] -> cb $ WebFrameCount (read n) + ["frame", nth, path] -> cb $ WebFrame (read nth) path + ["stop"] -> do + logMsg "Received STOP" + killThread parent + [] -> return () + _ -> error $ "Bad message: " ++ inp + gracefulClose conn 5000 + resolve = do + let hints = defaultHints { + addrFlags = [AI_PASSIVE] + , addrSocketType = Stream + } + head <$> getAddrInfo (Just hints) (Just "127.0.0.1") (Just "9162") + oSocket addr = socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr) + open addr = E.bracketOnError (oSocket addr) close $ \sock -> do + setSocketOption sock ReuseAddr 1 + withFdSocket sock setCloseOnExecIfNeeded + bind sock $ addrAddress addr + listen sock 1024 + return sock openViewer :: IO () openViewer = do url <- getDataFileName "viewer-elm/dist/index.html" - logMsg "Opening browser..." bSucc <- openBrowser url - if bSucc - then logMsg "Browser opened." - else hPutStrLn stderr $ "Failed to open browser. Manually visit: " ++ url - -slaveHandler :: Bool -> Maybe FilePath -> [String] -> Connection -> GhciBackend - -> FilePath -> FilePath -> IO () -slaveHandler verbose mbGHCPath extraGHCOpts conn ghci self svgDir = - withCurrentDirectory (takeDirectory self) $ - withSystemTempDirectory "reanimate" $ \tmpDir -> - withTempFile tmpDir "reanimate.exe" $ \tmpExecutable handle -> do - outputFolder <- createTempDirectory svgDir "svgs" - let frameFileName frameIdx = - outputFolder show frameIdx <.> "svg" - - sentFrameCount <- newMVar False - hClose handle - lock <- newMVar () - sendWebMessage conn $ WebStatus "Compiling" - ghciThread <- forkIO $ do - firstFrame <- newIORef True - ghciReload ghci - logMsg "GHCi reload done." - ghciGenerate ghci outputFolder $ \frameIdx -> do - first <- readIORef firstFrame - writeIORef firstFrame False - if first - then - modifyMVar_ sentFrameCount $ \sent -> do - unless sent $ - sendWebMessage conn $ WebFrameCount frameIdx - logMsg "Framecount sent." - return True - else - withMVar lock $ \_ -> - sendWebMessage conn $ WebFrame frameIdx (frameFileName frameIdx) - logMsg "GHCi render done." - ret <- case mbGHCPath of - Nothing -> do - let args = ["ghc", "--"] ++ ghcOptions tmpDir ++ extraGHCOpts ++ [takeFileName self, "-o", tmpExecutable] - when verbose $ - logMsg $ "Running: " ++ showCommandForUser "stack" args - runCmd_ "stack" args - Just ghc -> do - let args = ghcOptions tmpDir ++ extraGHCOpts ++ [takeFileName self, "-o", tmpExecutable] - when verbose $ - logMsg $ "Running: " ++ showCommandForUser ghc args - runCmd_ ghc args - logMsg "Compile done." - case ret of - Left err -> - sendWebMessage conn $ WebError $ unlines (lines err) - Right{} -> runCmdLazy tmpExecutable (execOpts outputFolder) $ \getFrame -> do - frameCount <- expectFrame =<< getFrame - modifyMVar_ sentFrameCount $ \sent -> do - unless sent $ - sendWebMessage conn $ WebFrameCount frameCount - return True - replicateM_ frameCount $ do - frameIdx <- expectFrame =<< getFrame - withMVar lock $ \_ -> - sendWebMessage conn $ WebFrame frameIdx (frameFileName frameIdx) - logMsg "Optimized render done." - killThread ghciThread - where - execOpts output = - [ "raw", "--output", output, "--offset", "1" - , "+RTS", "-N", "-M2G", "-RTS"] - expectFrame :: Either String Text -> IO Int - expectFrame (Left "") = do - sendWebMessage conn $ WebStatus "Done" - exitSuccess - expectFrame (Left err) = do - sendWebMessage conn $ WebError err - exitWith (ExitFailure 1) - expectFrame (Right frame) = - case T.decimal frame of - Left err -> do - hPutStrLn stderr (T.unpack frame) - raiseError conn err - Right (frameNumber, "") -> - pure frameNumber - Right {} -> do - let err = "Unexpected output" - hPutStrLn stderr (T.unpack frame) - raiseError conn err - -raiseError :: Connection -> String -> IO a -raiseError conn err = do - hPutStrLn stderr $ "expectFrame: " ++ err - sendWebMessage conn $ WebError err - exitWith (ExitFailure 1) - -watchFile :: WatchManager -> FilePath -> IO () -> IO StopListening -watchFile watch file action = watchTree watch (takeDirectory file) check (const action) - where - check event = - takeFileName (eventPath event) == takeFileName file || - takeExtension (eventPath event) `elem` sourceExtensions || - takeExtension (eventPath event) `elem` dataExtensions - sourceExtensions = [".hs", ".lhs"] - dataExtensions = [".jpg", ".png", ".bmp", ".pov", ".tex", ".csv"] - -ghcOptions :: FilePath -> [String] -ghcOptions tmpDir = - ["-rtsopts", "--make", "-threaded", "-O2"] ++ - ["-odir", tmpDir, "-hidir", tmpDir] - --- FIXME: Move to a different module -requireOwnSource :: IO FilePath -requireOwnSource = do - mbSelf <- findOwnSource - case mbSelf of - Nothing -> do - hPutStrLn stderr - "Rendering in browser window is only available when interpreting.\n\ - \To render a video file, use the 'render' command or run again with --help\n\ - \to see all available options." - exitFailure - Just self -> pure self - -findOwnSource :: IO (Maybe FilePath) -findOwnSource = do - fullArgs <- getFullArgs - stackSource <- makeAbsolute (last fullArgs) - exist <- doesFileExist stackSource - if exist && isHaskellFile stackSource - then return (Just stackSource) - else do - prog <- getProgName - let hsProg - | isHaskellFile prog = prog - | otherwise = replaceExtension prog "hs" - lst <- listDirectory "." - findFile ("." : lst) hsProg - -isHaskellFile :: FilePath -> Bool -isHaskellFile path = takeExtension path `elem` [".hs", ".lhs"] - -logMsg :: String -> IO () -logMsg msg = do - now <- getCurrentTime - putStrLn $ formatTime defaultTimeLocale fmt now ++ ": " ++ msg - where - fmt = "%F %T%2Q" - -------------------------------------------------------------------------------- --- Ghci interface - --- stack --- cabal --- raw --- none? -newtype GhciBackend = GhciBackend (MVar Ghci) - -ghciBackend :: Maybe FilePath -> FilePath -> IO GhciBackend -ghciBackend mbGHCPath self = do - let ghciProc = - case mbGHCPath of - Just ghcPath -> - proc ghcPath $ ["--interactive", "+RTS"] ++ words memoryLimit ++ ["-RTS"] - Nothing -> - proc "stack" ["exec", "ghci", "--rts-options="++memoryLimit] - (ghci, _loads) <- startGhciProcess ghciProc $ \_stream _msg -> return () - void $ exec ghci $ ":load " ++ self - ref <- newMVar ghci - return $ GhciBackend ref - -ghciReload :: GhciBackend -> IO () -ghciReload (GhciBackend ref) = - withMVar ref $ \ghci -> - void $ reload ghci - -ghciGenerate :: GhciBackend -> FilePath -> (Int -> IO ()) -> IO () -ghciGenerate (GhciBackend ref) target cb = withMVar ref $ \ghci -> - execStream ghci (":main raw --output=" ++ target ++ " --offset=1") - $ \_ msg -> - case reads msg of - [(frameIdx,"")] -> cb frameIdx - _ -> return () - -memoryLimit :: String -memoryLimit = "-M1G" + unless bSucc $ + hPutStrLn stderr $ "Failed to open browser. Manually visit: " ++ url ------------------------------------------------------------------------------- -- Websocket API diff --git a/src/Reanimate/Render.hs b/src/Reanimate/Render.hs index bfb0629..ce62cd9 100644 --- a/src/Reanimate/Render.hs +++ b/src/Reanimate/Render.hs @@ -13,6 +13,7 @@ to ever directly use the functions in this module. module Reanimate.Render ( render , renderSvgs + , renderSvgs_ , renderSnippets -- :: Animation -> IO () , renderLimitedFrames , Format(..) @@ -44,6 +45,7 @@ import System.Exit (ExitCode (ExitFailure), exitWith) import System.FileLock (SharedExclusive (..), unlockFile, withTryFileLock) import System.FilePath (replaceExtension, (<.>), ()) import System.IO +import System.IO.Temp (createTempDirectory, getCanonicalTemporaryDirectory) import Text.Printf (printf) idempotentFile :: FilePath -> IO () -> IO () @@ -82,6 +84,28 @@ renderSvgs folder offset _prettyPrint ani = do hPutStrLn stderr msg exitWith (ExitFailure 1) +renderSvgs_ :: Animation -> (Int -> FilePath -> IO ()) -> IO () +renderSvgs_ ani cb = do + tmp <- getCanonicalTemporaryDirectory + tmpDir <- createTempDirectory tmp "reanimate" + lock <- newMVar () + handle errHandler $ concurrentForM_ (frameOrder rate frameCount) $ \nth' -> do + let nth = (nth') `mod` frameCount + now = (duration ani / (fromIntegral frameCount - 1)) * fromIntegral nth + frame = frameAt (if frameCount <= 1 then 0 else now) ani + path = tmpDir show nth <.> "svg" + svg = renderSvg Nothing Nothing frame + + idempotentFile path $ + writeFile path svg + withMVar lock $ \_ -> cb nth path + where + rate = 60 + frameCount = round (duration ani * fromIntegral rate) :: Int + errHandler (ErrorCall msg) = do + hPutStrLn stderr msg + exitWith (ExitFailure 1) + -- | Render as many frames as possible in 2 seconds. Limited to 20 frames. renderLimitedFrames :: FilePath -> Int -> Bool -> Int -> Animation -> IO () renderLimitedFrames folder offset _prettyPrint rate ani = do diff --git a/stack-lts-13.yaml b/stack-lts-13.yaml deleted file mode 100644 index 695e158..0000000 --- a/stack-lts-13.yaml +++ /dev/null @@ -1,23 +0,0 @@ -resolver: lts-13.19 - -allow-newer: true - -packages: -- . - -extra-deps: -- reanimate-svg-0.13.0.0 -- chiphunk-0.1.2.1 -- cubicbezier-0.6.0.6@sha256:2191ff47144d9a13a2784651a33d340cd31be1926a6c188925143103eb3c8db3 -- fast-math-1.0.2@sha256:91181eb836e54413cc5a841e797c42b2264954e893ea530b6fc4da0dccf6a8b7 -- matrices-0.5.0@sha256:b2761813f6a61c84224559619cc60a16a858ac671c8436bbac8ec89e85473058 -- hmatrix-0.20.0.0@sha256:d79a9218e314f1a2344457c3851bd1d2536518ecb5f1a2fcd81daa45e46cd025,4870 -- websockets-0.12.7.0@sha256:fc96169cc8268d3efb93bdc1e0b060dd88ce932237b837904118777a90d6db80,7863 -- clock-0.8@sha256:b4ae207e2d3761450060a0d0feb873269233898039c76fceef9cc1a544067767,4113 -- earcut-0.1.0.4@sha256:d5118b3eecf24d130263d81fb30f1ff56b1db43036582bfd1d8cc9ba3adae8be,1010 -- tasty-rerun-1.1.17@sha256:d4a3ccb0f63f499f36edc71b33c0f91c850eddb22dd92b928aa33b8459f3734a,1373 -- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 -- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 -- vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 -- data-clist-0.1.2.3@sha256:1e26251c8921821c8a1c7e168955449822f1bacf03d056cc59c84fd2863a0f8e,983 -- hashable-1.3.0.0@sha256:4c70f1407881059e93550d3742191254296b2737b793a742bd901348fb3e1fb1,5206 diff --git a/stack-lts-14.yaml b/stack-lts-14.yaml index 2b39b0a..ac962ee 100644 --- a/stack-lts-14.yaml +++ b/stack-lts-14.yaml @@ -18,3 +18,4 @@ extra-deps: - hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 - hashable-1.3.0.0@sha256:4c70f1407881059e93550d3742191254296b2737b793a742bd901348fb3e1fb1,5206 +- network-3.1.2.1@sha256:188d6daea8cd91bc3553efd5a90a1e7c6d0425fa66a53baa74db5b6d9fd75c8b,4968 diff --git a/stack.yaml b/stack.yaml index addd26d..6056cb6 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-16.12 +resolver: lts-16.27 allow-newer: false diff --git a/unix/Detach.hs b/unix/Detach.hs new file mode 100644 index 0000000..c38ba8f --- /dev/null +++ b/unix/Detach.hs @@ -0,0 +1,19 @@ +module Detach (detach) where + +import Control.Concurrent +import Control.Monad +import System.Posix.IO +import System.Posix.Process (createSession, forkProcess) + +detach :: IO () -> IO Bool +detach daemon = do + void $ forkProcess $ do + devnull <- openFd "/dev/null" ReadWrite Nothing defaultFileFlags + void $ dupTo devnull stdInput + void $ dupTo devnull stdOutput + void $ dupTo devnull stdError + closeFd devnull + void createSession + void $ forkProcess daemon + threadDelay (10^(6::Int)) + return True diff --git a/windows/Detach.hs b/windows/Detach.hs new file mode 100644 index 0000000..90b3a10 --- /dev/null +++ b/windows/Detach.hs @@ -0,0 +1,10 @@ +module Detach (detach) where + +import Control.Monad +import Control.Concurrent + +detach :: IO () -> IO Bool +detach action = do + void $ forkIO action + threadDelay (10^(6::Int)) + return False From fb4bdf73ed0e43d97aed231c10eb73cb9fae5319 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 13:54:21 +0800 Subject: [PATCH 028/114] Clean-up and documentation. --- src/Reanimate.hs | 1 + src/Reanimate/Driver/Daemon.hs | 22 ++++++++++++++++++++++ src/Reanimate/Driver/Server.hs | 19 ++----------------- 3 files changed, 25 insertions(+), 17 deletions(-) diff --git a/src/Reanimate.hs b/src/Reanimate.hs index ee8dfd2..9a17215 100644 --- a/src/Reanimate.hs +++ b/src/Reanimate.hs @@ -36,6 +36,7 @@ no other parameters are given. Key features: module Reanimate ( reanimate, reanimateLive, + reanimateLiveEntry, -- * Animations SVG, Time, diff --git a/src/Reanimate/Driver/Daemon.hs b/src/Reanimate/Driver/Daemon.hs index c876273..cfb503a 100644 --- a/src/Reanimate/Driver/Daemon.hs +++ b/src/Reanimate/Driver/Daemon.hs @@ -73,6 +73,11 @@ Daemon port: 9162? - Refreshing the code will re-open closed browser windows. -} +-- | Load a reanimate program in GHCi and make sure 'main' is available. +-- Then run: +-- @ +-- :cmd reanimateLive +-- @ reanimateLive :: IO String reanimateLive = do void ensureDaemon @@ -85,6 +90,23 @@ reanimateLive = do , ":main" , ":cmd System.Environment.withArgs [\"primed\"] Reanimate.reanimateLive" ] +-- | Load an animation in GHCi. Anything of type 'Animation' can be live reloaded. +-- +-- @ +-- :cmd reanimateLiveEntry "drawCircle" +-- @ +reanimateLiveEntry :: String -> IO String +reanimateLiveEntry animation = do + void ensureDaemon + args <- getArgs + case args of + ["primed"] -> waitForChanges + _ -> return () + return $ unlines + [ ":r" + , "Reanimate.reanimate (" ++ animation ++ ")" + , ":cmd System.Environment.withArgs [\"primed\"] Reanimate.reanimateLive" ] + waitForChanges :: IO () waitForChanges = withManager $ \mgr -> do lock <- newEmptyMVar diff --git a/src/Reanimate/Driver/Server.hs b/src/Reanimate/Driver/Server.hs index acd0727..d600b51 100644 --- a/src/Reanimate/Driver/Server.hs +++ b/src/Reanimate/Driver/Server.hs @@ -61,9 +61,6 @@ daemon = do , serverConnectionOptions = opts , serverRequirePong = Nothing } - logMsg "WS server is running." - - runServerWithOptions options (\pending -> do tid <- myThreadId @@ -71,9 +68,6 @@ daemon = do modifyMVar_ connsRef $ pure . Map.insert tid conn - conns <- readMVar connsRef - logMsg $ "Browser connections: " ++ show (Map.size conns) - (count, frames) <- readMVar state when (count > 0) $ do sendWebMessage conn (WebFrameCount count) @@ -87,27 +81,20 @@ daemon = do cleanup = do modifyMVar_ connsRef $ pure . Map.delete tid nConns <- Map.size <$> readMVar connsRef - logMsg $ "Browser connections: " ++ show nConns when (nConns == 0) $ do threadDelay (second * 5) nConns' <- Map.size <$> readMVar connsRef - logMsg $ "Browser connections (check): " ++ show nConns' when (nConns'==0) $ killThread self loop `finally` cleanup) - `finally` (killThread dTid >> logMsg "daemon server quit") - `E.catch` (\e@E.SomeException{} -> logMsg $ "Exception: " ++ show e) + `finally` (killThread dTid) second :: Int second = 10^(6::Int) -logMsg :: String -> IO () -logMsg msg = appendFile "log" (msg++"\n") - daemonReceive :: ThreadId -> (WebMessage -> IO ()) -> IO ThreadId daemonReceive parent cb = withSocketsDo $ do addr <- resolve sock <- open addr - logMsg "daemon sock is open" forkIO $ handler sock `finally` close sock where handler sock = forever $ E.bracketOnError (accept sock) (close . fst) $ \(conn, _peer) -> do @@ -115,9 +102,7 @@ daemonReceive parent cb = withSocketsDo $ do case words inp of ["frame_count", n] -> cb $ WebFrameCount (read n) ["frame", nth, path] -> cb $ WebFrame (read nth) path - ["stop"] -> do - logMsg "Received STOP" - killThread parent + ["stop"] -> killThread parent [] -> return () _ -> error $ "Bad message: " ++ inp gracefulClose conn 5000 From 717808f3dcdf101163becd81279a3201fceef4d1 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 14:35:33 +0800 Subject: [PATCH 029/114] Update documentation. --- src/Reanimate/Driver/Daemon.hs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Reanimate/Driver/Daemon.hs b/src/Reanimate/Driver/Daemon.hs index cfb503a..572fb3c 100644 --- a/src/Reanimate/Driver/Daemon.hs +++ b/src/Reanimate/Driver/Daemon.hs @@ -78,6 +78,9 @@ Daemon port: 9162? -- @ -- :cmd reanimateLive -- @ +-- +-- This works by sending the commands ':r' and ':main' to your GHCi instance +-- when any source file is changed. reanimateLive :: IO String reanimateLive = do void ensureDaemon @@ -95,6 +98,9 @@ reanimateLive = do -- @ -- :cmd reanimateLiveEntry "drawCircle" -- @ +-- +-- This works by sending the commands ':r' and 'Reanimate.reanimate {entry}' to your +-- GHCi instance when any source file is changed. reanimateLiveEntry :: String -> IO String reanimateLiveEntry animation = do void ensureDaemon From 300178d10192ac4b866d5f586c9574c84a781e0c Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 14:35:42 +0800 Subject: [PATCH 030/114] Bump version to 1.1.3.0 --- reanimate.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reanimate.cabal b/reanimate.cabal index 90bd567..77057b4 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.2.1 +version: 1.1.3.0 -- synopsis: -- description: license: PublicDomain From f320f5cfdf005bdde127651c5c00bad3e651e572 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 15:07:40 +0800 Subject: [PATCH 031/114] Fix docker build. --- Dockerfile.playground | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile.playground b/Dockerfile.playground index bbc3ea2..c3984c5 100644 --- a/Dockerfile.playground +++ b/Dockerfile.playground @@ -14,6 +14,8 @@ RUN cd playground && \ # Add source after dependencies have been installed as to not invalidate the caches ADD data data ADD src src +ADD unix unix +ADD windows windows ADD .git .git ADD viewer-elm viewer-elm ADD Setup.hs ./ From 7003c13bace6ef476e323d4a7e310cc307b48f92 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 16:33:57 +0800 Subject: [PATCH 032/114] Fix TCP windows issue, fix Firefox on windows. --- src/Reanimate/Driver/Server.hs | 4 ++-- viewer-elm/README.md | 2 +- viewer-elm/dist/elm.js | 2 +- viewer-elm/src/Main.elm | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Reanimate/Driver/Server.hs b/src/Reanimate/Driver/Server.hs index d600b51..0ca8a31 100644 --- a/src/Reanimate/Driver/Server.hs +++ b/src/Reanimate/Driver/Server.hs @@ -14,7 +14,7 @@ import qualified Data.Map as Map import qualified Data.Text as T import Network.Socket (AddrInfo (..), AddrInfoFlag (..), SocketOption (..), SocketType (Stream), accept, bind, close, defaultHints, - getAddrInfo, gracefulClose, listen, socket, + getAddrInfo, listen, socket, setCloseOnExecIfNeeded, setSocketOption, withFdSocket, withSocketsDo) import Network.Socket.ByteString (recv) @@ -105,7 +105,7 @@ daemonReceive parent cb = withSocketsDo $ do ["stop"] -> killThread parent [] -> return () _ -> error $ "Bad message: " ++ inp - gracefulClose conn 5000 + close conn resolve = do let hints = defaultHints { addrFlags = [AI_PASSIVE] diff --git a/viewer-elm/README.md b/viewer-elm/README.md index a6c5ac6..b7686f2 100644 --- a/viewer-elm/README.md +++ b/viewer-elm/README.md @@ -2,7 +2,7 @@ ## Build it ```bash -cd reanimate/elm-viewer +cd reanimate/viewer-elm npm install npm run build npm run minify diff --git a/viewer-elm/dist/elm.js b/viewer-elm/dist/elm.js index 8f4ba65..63c9718 100644 --- a/viewer-elm/dist/elm.js +++ b/viewer-elm/dist/elm.js @@ -1 +1 @@ -!function(n){"use strict";function r(n,r,t){return t.a=n,t.f=r,t}function o(t){return r(2,t,function(r){return function(n){return t(r,n)}})}function b(e){return r(3,e,function(t){return function(r){return function(n){return e(t,r,n)}}})}function v(u){return r(4,u,function(e){return function(t){return function(r){return function(n){return u(e,t,r,n)}}}})}function t(a){return r(5,a,function(u){return function(e){return function(t){return function(r){return function(n){return a(u,e,t,r,n)}}}}})}function e(i){return r(6,i,function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return i(a,u,e,t,r,n)}}}}}})}function u(o){return r(7,o,function(i){return function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return o(i,a,u,e,t,r,n)}}}}}}})}function g(n,r,t){return 2===n.a?n.f(r,t):n(r)(t)}function p(n,r,t,e){return 3===n.a?n.f(r,t,e):n(r)(t)(e)}function w(n,r,t,e,u){return 4===n.a?n.f(r,t,e,u):n(r)(t)(e)(u)}function s(n,r,t,e,u,a){return 5===n.a?n.f(r,t,e,u,a):n(r)(t)(e)(u)(a)}function l(n,r,t,e,u,a,i){return 6===n.a?n.f(r,t,e,u,a,i):n(r)(t)(e)(u)(a)(i)}function f(n,r,t,e,u,a,i,o){return 7===n.a?n.f(r,t,e,u,a,i,o):n(r)(t)(e)(u)(a)(i)(o)}function k(n,r){for(var t,e=[],u=a(n,r,0,e);u&&(t=e.pop());u=a(t.a,t.b,0,e));return u}function a(n,r,t,e){if(n===r)return!0;if("object"!=typeof n||null===n||null===r)return"function"==typeof n&&R(5),!1;if(100i)return u}var l=t.$;if(4===l){for(var d=t.k;4===d.$;)d=d.k;return n(r,d,e,u,a+1,i,r.elm_event_node_ref)}var $=t.e;var h=r.childNodes;for(var m=0;m<$.length;m++){var g=1===l?$[m]:$[m].b,p=++a+(g.b||0);if(a<=c&&c<=p&&(u=n(h[m],g,e,u,a,p,o),!(f=e[u])||(c=f.r)>i))return u;a=p}return u}(n,r,t,0,0,r.b,e)}function mr(n,r,t,e){return 0===t.length?n:(hr(n,r,t,e),gr(n,t))}function gr(n,r){for(var t=0;t>1,A(r,r),1&n?A(t,r):t):t}),Oa=o(function(n,r){return p(Ma,n,r,"")}),Fa=b(function(n,r,t){return A(g(Oa,n-zt(t),function(n){return g(Ra,n,"")}(r)),t)}),Pa=an,xa=o(function(n,r){return g(Kn,n,Pa(r))})("disabled"),za=$a("id"),Sa=$a("title"),Ba=Jn("pre"),Ia=Jn("label"),qa=$a("max"),Ga=Jn("progress"),Ja=Jn("span"),Ua=$a("value"),Wa=o(function(n,r){return g(Ia,j,N([g(Ja,j,N([Ta(" | Loading frames ")])),g(Ga,N([Ua(Vr(n)),qa(Vr(r))]),j)]))}),Ka=v(function(n,r,t,e){for(;;){if(!e.b)return t/r;var u=n+r,a=e.a*n+t;n=.9*n,r=u,t=a,e=e.b}}),Ha=P,Va=o(function(n,r){for(;;){if(-2===r.$)return n;var t=r.d;n=g(Va,n+1,r.e),r=t}}),Ya=u(function(n,r,t,e,u,a,i){var o,f,c,v,s,b=k(o=g(Va,0,e),t)?Ta(""):g(Wa,o,t),l=n.$?Ta(""):g(La,N([(f=n.a,g($a,"src",/^\s*(javascript:|data:text\/html)/i.test(c=f)?"":c))]),j),d=u?Da:g(pa,N([ha("help-button"),ja(ga)]),N([Ta("?")])),$=Vr(t),h=zt($),m=g(Ba,N([ha("bar")]),N([(s=i,g(ma,N([ha("media-controls")]),N([g(pa,N([ja(Cu(-10)),xa(!s),Sa("10 frames back")]),N([Ta("<<")])),g(pa,N([ja(Cu(-1)),xa(!s),Sa("1 frame back")]),N([Ta("<")])),s?g(pa,N([ja(Tu),za("play-or-pause")]),N([Ta("Play")])):g(pa,N([ja(Nu),za("play-or-pause")]),N([Ta("Pause")])),g(pa,N([ja(Cu(1)),xa(!s),Sa("1 frame forward")]),N([Ta(">")])),g(pa,N([ja(Cu(10)),xa(!s),Sa("10 frames forward")]),N([Ta(">>")]))]))),g(Ja,j,N([Ta(" Frame: "+p(Fa,h,"0",Vr(r+1))+" / "+$+(i?" ":(v=a," @ "+Vr(Ha(1e3/w(Ka,1,0,0,v)))+" FPS")))])),b,d]));return g(ma,N([ha("viewer")]),N([l,m]))}),Za=Jn("h1"),Qa=Jn("li"),Xa=Jn("ul"),ni=re({aD:function(){return $(te,ae)},aK:function(n){return se(N([du((t=fe,function(n){return t(g(lu,bu,n))})),(r=oe,Se(g(Rt,r,de))),function(){n:for(;;)switch(n.$){case 3:return 1===n.a.j.$?vu(ce):ru;case 4:if(1!==n.a.$)break n;return g(nu,2e3,ve(ie));default:break n}return ru}()]));var r,t},aM:da,aN:function(i){return g(ma,N([ha("app")]),N([function(){switch(i.$){case 0:return Ta("Disconnected");case 1:return Ta("Connected");case 2:return Ta("Compiling ...");case 4:return function(n){switch(n.$){case 0:var r=n.a;return g(ma,j,N([g(Za,j,N([Ta("Compilation failed")])),g(Ba,j,N([Ta(r)]))]));case 1:return g(ma,j,N([Ta("Failed to establish connection. Possible causes include: "),g(Xa,j,N([g(Qa,j,N([Ta("The reanimate script is not running")])),g(Qa,j,N([Ta("At most one viewer window can connect at time. Maybe there's another browser window/tab already connected?")]))]))]));case 2:return Ta("Failed to decode Port message. The error was: "+lt(n.a));default:return Ta("Unexpected message: "+n.a)}}(i.a);default:var n=i.a.z,r=i.a.u,t=i.a.p,e=i.a.D,u=i.a.G,a=i.a.E;return f(Ya,e,t,n,r,u,a,!i.a.j.$)}}()]))}});fu={Main:{init:ni(Ot(0))(0)}},n.Elm?function n(r,t){for(var e in t)e in r?"init"==e?R(6):n(r[e],t[e]):r[e]=t[e]}(n.Elm,fu):n.Elm=fu}(this); \ No newline at end of file +!function(n){"use strict";function r(n,r,t){return t.a=n,t.f=r,t}function o(t){return r(2,t,function(r){return function(n){return t(r,n)}})}function b(e){return r(3,e,function(t){return function(r){return function(n){return e(t,r,n)}}})}function s(u){return r(4,u,function(e){return function(t){return function(r){return function(n){return u(e,t,r,n)}}}})}function t(a){return r(5,a,function(u){return function(e){return function(t){return function(r){return function(n){return a(u,e,t,r,n)}}}}})}function e(i){return r(6,i,function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return i(a,u,e,t,r,n)}}}}}})}function u(o){return r(7,o,function(i){return function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return o(i,a,u,e,t,r,n)}}}}}}})}function a(f){return r(8,f,function(o){return function(i){return function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return f(o,i,a,u,e,t,r,n)}}}}}}}})}function i(c){return r(9,c,function(f){return function(o){return function(i){return function(a){return function(u){return function(e){return function(t){return function(r){return function(n){return c(f,o,i,a,u,e,t,r,n)}}}}}}}}})}function $(n,r,t){return 2===n.a?n.f(r,t):n(r)(t)}function g(n,r,t,e){return 3===n.a?n.f(r,t,e):n(r)(t)(e)}function p(n,r,t,e,u){return 4===n.a?n.f(r,t,e,u):n(r)(t)(e)(u)}function l(n,r,t,e,u,a){return 5===n.a?n.f(r,t,e,u,a):n(r)(t)(e)(u)(a)}function d(n,r,t,e,u,a,i){return 6===n.a?n.f(r,t,e,u,a,i):n(r)(t)(e)(u)(a)(i)}function f(n,r,t,e,u,a,i,o){return 7===n.a?n.f(r,t,e,u,a,i,o):n(r)(t)(e)(u)(a)(i)(o)}function m(n,r){for(var t,e=[],u=c(n,r,0,e);u&&(t=e.pop());u=c(t.a,t.b,0,e));return u}function c(n,r,t,e){if(n===r)return!0;if("object"!=typeof n||null===n||null===r)return"function"==typeof n&&F(5),!1;if(100"}function F(n){throw Error("https://github.com/elm/core/blob/1.0.0/hints/"+n+".md")}o(function(n,r){return n+r}),o(function(n,r){return n-r}),o(function(n,r){return n*r}),o(function(n,r){return n/r}),o(function(n,r){return n/r|0}),o(Math.pow),o(function(n,r){return r%n});var S=o(function(n,r){var t=r%n;return 0===n?F(11):0i)return u}var l=t.$;if(4===l){for(var d=t.k;4===d.$;)d=d.k;return n(r,d,e,u,a+1,i,r.elm_event_node_ref)}var h=t.e;var $=r.childNodes;for(var g=0;gi))return u;a=m}return u}(n,r,t,0,0,r.b,e)}function _r(n,r,t,e){return 0===t.length?n:(Nr(n,r,t,e),Cr(n,t))}function Cr(n,r){for(var t=0;t>n}),o(function(n,r){return r>>>n});function Gr(n){return $($t,"\n ",$(gt,"\n",n))}function Jr(n){return g(pt,o(function(n,r){return r+1}),0,n)}function Wr(n){var r=kt(n);return 97<=r&&r<=122}function Ur(n){var r=kt(n);return r<=90&&65<=r}function Kr(n){return Wr(n)||Ur(n)}function Qr(n){return Wr(n)||Ur(n)||function(n){var r=kt(n);return r<=57&&48<=r}(n)}function Yr(n){return n}function Hr(n){return""===n}function Vr(n){return g(be,$e(rt),ce(N),n)}var Zr=1,Xr=2,nt=0,rt=C,tt=b(function(n,r,t){for(;;){if(-2===t.$)return r;var e=t.d,u=n,a=g(n,t.b,t.c,g(tt,n,r,t.e));n=u,r=a,t=e}}),et=function(n){return g(tt,b(function(n,r,t){return $(rt,y(n,r),t)}),N,n)},ut=R,at=(b(function(t,n,r){var e=r.c,u=r.d,a=o(function(n,r){return g(ut,n.$?t:a,r,n.a)});return g(ut,a,g(ut,t,n,u),e)}),function(n){return{$:1,a:n}}),it=o(function(n,r){return{$:3,a:n,b:r}}),ot=o(function(n,r){return{$:0,a:n,b:r}}),ft=o(function(n,r){return{$:1,a:n,b:r}}),ct=function(n){return{$:0,a:n}},vt=function(n){return{$:2,a:n}},st=function(n){return{$:0,a:n}},bt={$:1},lt=U,dt=bn,ht=function(n){return n+""},$t=o(function(n,r){return $(J,n,O(r))}),gt=o(function(n,r){return T($(G,n,r))}),pt=b(function(n,r,t){for(;;){if(!t.b)return r;var e=t.b,u=n,a=$(n,t.a,r);n=u,r=a,t=e}}),mt=L,wt=b(function(n,r,t){for(;;){if(1<=h(n,r))return t;var e=n,u=r-1,a=$(rt,r,t);n=e,r=u,t=a}}),yt=o(function(n,r){return g(wt,n,r,N)}),At=o(function(n,r){return g(mt,n,$(yt,0,Jr(r)-1),r)}),kt=function(n){var r=n.charCodeAt(0);return r<55296||56319>1,E(r,r),1&n?E(t,r):t):t}),si=o(function(n,r){return g(vi,n,r,"")}),bi=b(function(n,r,t){return E($(si,n-Xt(t),function(n){return $(ci,n,"")}(r)),t)}),li=ln,di=o(function(n,r){return $(rr,n,li(r))})("disabled"),hi=Ka("id"),$i=Ka("title"),gi=Vn("pre"),pi=Vn("label"),mi=Ka("max"),wi=Vn("progress"),yi=Vn("span"),Ai=Ka("value"),ki=o(function(n,r){return $(pi,N,T([$(yi,N,T([ai(" | Loading frames ")])),$(wi,T([Ai(ht(n)),mi(ht(r))]),N)]))}),ji=s(function(n,r,t,e){for(;;){if(!e.b)return t/r;var u=n+r,a=e.a*n+t;n=.9*n,r=u,t=a,e=e.b}}),Ei=B,Ni=o(function(n,r){for(;;){if(-2===r.$)return n;var t=r.d;n=$(Ni,n+1,r.e),r=t}}),_i=u(function(n,r,t,e,u,a,i){var o,f,c,v=m(o=$(Ni,0,e),t)?ai(""):$(ki,o,t),s=n.$?ai(""):$(fi,T([$(Ka,"src",/^\s*(javascript:|data:text\/html)/i.test(f="file://"+n.a)?"":f)]),N),b=u?oi:$(Va,T([Qa("help-button"),Uu(Ha)]),T([ai("?")])),l=ht(t),d=Xt(l),h=$(gi,T([Qa("bar")]),T([(c=i,$(Ya,T([Qa("media-controls")]),T([$(Va,T([Uu(zu(-10)),di(!c),$i("10 frames back")]),T([ai("<<")])),$(Va,T([Uu(zu(-1)),di(!c),$i("1 frame back")]),T([ai("<")])),c?$(Va,T([Uu(la),hi("play-or-pause")]),T([ai("Play")])):$(Va,T([Uu(ba),hi("play-or-pause")]),T([ai("Pause")])),$(Va,T([Uu(zu(1)),di(!c),$i("1 frame forward")]),T([ai(">")])),$(Va,T([Uu(zu(10)),di(!c),$i("10 frames forward")]),T([ai(">>")]))]))),$(yi,N,T([ai(" Frame: "+g(bi,d,"0",ht(r+1))+" / "+l+(i?" ":" @ "+ht(Ei(1e3/p(ji,1,0,0,a)))+" FPS"))])),v,b]));return $(Ya,T([Qa("viewer")]),T([s,h]))}),Ci=Vn("h1"),Ti=Vn("li"),Oi=Vn("ul"),Li=De({aD:function(){return y(Me,xe)},aK:function(n){return Pe(T([na((r=je,function(n){return r($(Xu,Zu,n))})),bu($(Ut,ke,Ie)),function(){n:for(;;)switch(n.$){case 3:return 1===n.a.j.$?Hu(Ee):Ou;case 4:if(1!==n.a.$)break n;return $(Tu,2e3,Se(Fe));default:break n}return Ou}()]));var r},aM:Ua,aN:function(i){return $(Ya,T([Qa("app")]),T([function(){switch(i.$){case 0:return ai("Disconnected");case 1:return ai("Connected");case 2:return ai("Compiling ...");case 4:return function(n){switch(n.$){case 0:var r=n.a;return $(Ya,N,T([$(Ci,N,T([ai("Compilation failed")])),$(gi,N,T([ai(r)]))]));case 1:return $(Ya,N,T([ai("Failed to establish connection. Possible causes include: "),$(Oi,N,T([$(Ti,N,T([ai("The reanimate script is not running")])),$(Ti,N,T([ai("At most one viewer window can connect at time. Maybe there's another browser window/tab already connected?")]))]))]));case 2:return ai("Failed to decode Port message. The error was: "+_t(n.a));default:return ai("Unexpected message: "+n.a)}}(i.a);default:var n=i.a.z,r=i.a.u,t=i.a.p,e=i.a.D,u=i.a.G,a=i.a.E;return f(_i,e,t,n,r,u,a,!i.a.j.$)}}()]))}});Qu={Main:{init:Li(Qt(0))(0)}},n.Elm?function n(r,t){for(var e in t)e in r?"init"==e?F(6):n(r[e],t[e]):r[e]=t[e]}(n.Elm,Qu):n.Elm=Qu}(this); \ No newline at end of file diff --git a/viewer-elm/src/Main.elm b/viewer-elm/src/Main.elm index 798581d..2a3b5cc 100644 --- a/viewer-elm/src/Main.elm +++ b/viewer-elm/src/Main.elm @@ -378,7 +378,7 @@ frameView bestFrame frameIndex frameCount frames showingHelp frameDeltas isPause image = case bestFrame of Just svgUrl -> - Html.img [ src svgUrl ] [] + Html.img [ src ("file://" ++ svgUrl) ] [] Nothing -> Html.text "" From 4187a6562e0fa0c6a5017df86973ae3ca9e2bd16 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 16:40:02 +0800 Subject: [PATCH 033/114] Update Changelog. --- ChangeLog.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ChangeLog.md b/ChangeLog.md index 4a62969..27811a3 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and the project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org) +## 1.1.3.1 -- 2020-01-04 + + * Fixed performance issue on Windows. + * Fixed live viewer with Firefox. + +## 1.1.3.0 -- 2020-01-04 + +## Added + * Reanimate.reanimateLive + * Reanimate.reanimateLiveEntry + ## 1.1.2.0 -- 2020-10-27 ### Added From 62666f0a2451d2a39686a9e8c0c7cc40b73126a4 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 16:40:20 +0800 Subject: [PATCH 034/114] Bump to 1.1.3.1 --- reanimate.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reanimate.cabal b/reanimate.cabal index 77057b4..b46c5c5 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.3.0 +version: 1.1.3.1 -- synopsis: -- description: license: PublicDomain From 5795a59d4481e5b506210cdf16ed9adec62f0ebf Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 4 Jan 2021 21:37:13 +0800 Subject: [PATCH 035/114] Fix discord docker build. --- Dockerfile.discord | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile.discord b/Dockerfile.discord index f90fc55..0f81584 100644 --- a/Dockerfile.discord +++ b/Dockerfile.discord @@ -14,6 +14,8 @@ RUN cd discord-bot && \ # Add source after dependencies have been installed as to not invalidate the caches ADD data data ADD src src +ADD unix unix +ADD windows windows ADD .git .git ADD viewer-elm viewer-elm ADD Setup.hs ./ From 091f065e362799d6cf9963d19c2b794b33f49177 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 14 Jan 2021 16:17:21 +0800 Subject: [PATCH 036/114] Create flag for toggling hgeometry dependency. (#192) --- reanimate.cabal | 15 +++++++++++++-- src/Reanimate/Math/Triangulate.hs | 29 +++++++++++++++++++++++++++++ src/Reanimate/PolyShape.hs | 23 ++++++++++++++++------- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/reanimate.cabal b/reanimate.cabal index b46c5c5..135fe35 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -37,6 +37,13 @@ Source-Repository head Type: git Location: git://github.com/lemmih/reanimate.git +flag no-hgeometry + description: + Disable all features that depend on hgeometry. Should only + be used when developing new hgeometry algorithms. + default: False + manual: True + library hs-source-dirs: src if os(windows) @@ -105,6 +112,12 @@ library Reanimate.Scene.Object Detach autogen-modules: Paths_reanimate + if flag(no-hgeometry) + ghc-options: -DNO_HGEOMETRY + else + build-depends: + hgeometry >=0.11.0.0, + hgeometry-combinatorial >=0.11.0.0 build-depends: base >=4.10 && <5, JuicyPixels >=3.3.3, @@ -126,8 +139,6 @@ library fsnotify >=0.3.0.1, geojson >=3.0.4, hashable >=1.3.0.0, - hgeometry >=0.11.0.0, - hgeometry-combinatorial >=0.11.0.0, lens >=4.16.1, linear >=1.20.8, matrix >=0.3.6.1, diff --git a/src/Reanimate/Math/Triangulate.hs b/src/Reanimate/Math/Triangulate.hs index 3cdc57d..8883988 100644 --- a/src/Reanimate/Math/Triangulate.hs +++ b/src/Reanimate/Math/Triangulate.hs @@ -1,5 +1,6 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE CPP #-} {-# OPTIONS_HADDOCK hide #-} module Reanimate.Math.Triangulate ( Triangulation @@ -11,6 +12,32 @@ module Reanimate.Math.Triangulate ) where +#if NO_HGEOMETRY + +import qualified Data.Vector as V +import Control.Monad.ST +import Reanimate.Math.Common + +type Triangulation = V.Vector [Int] + +edgesToTriangulation :: Int -> [(Int, Int)] -> Triangulation +edgesToTriangulation = error "no hgeometry" + +edgesToTriangulationM :: Int -> [(Int, Int)] -> ST s (V.MVector s [Int]) +edgesToTriangulationM = error "no hgeometry" + +trianglesToTriangulation :: Int -> V.Vector (Int, Int, Int) -> Triangulation +trianglesToTriangulation = error "no hgeometry" + +trianglesToTriangulationM + :: Int -> V.Vector (Int, Int, Int) -> ST s (V.MVector s [Int]) +trianglesToTriangulationM = error "no hgeometry" + +triangulate :: forall a. (Fractional a, Ord a) => Ring a -> Triangulation +triangulate = error "no hgeometry" + +#else + import Algorithms.Geometry.PolygonTriangulation.Triangulate (triangulate') import Algorithms.Geometry.PolygonTriangulation.Types import Control.Lens @@ -83,3 +110,5 @@ triangulate r = edgesToTriangulation (ringSize r) ds [ Point2 x y :+ n | (n,V2 x y) <- zip [0..] (V.toList (ringUnpack r)) ] -- ringUnpack + +#endif diff --git a/src/Reanimate/PolyShape.hs b/src/Reanimate/PolyShape.hs index 4faa29c..9d6b2b3 100644 --- a/src/Reanimate/PolyShape.hs +++ b/src/Reanimate/PolyShape.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-| Module : Reanimate.PolyShape Copyright : Written by David Himmelstrup @@ -40,15 +41,8 @@ module Reanimate.PolyShape , plGroupTouching ) where -import Algorithms.Geometry.PolygonTriangulation.Triangulate (triangulate') import Control.Lens ((&), (.~), (^.)) -import Data.Ext -import Data.Geometry.PlanarSubdivision (PolygonFaceData (..)) -import qualified Data.Geometry.Point as Geo -import qualified Data.Geometry.Polygon as Geo import Data.List (nub, partition, sortOn) -import qualified Data.PlaneGraph as Geo -import Data.Proxy (Proxy (Proxy)) import qualified Data.Vector as V import Geom2D.CubicBezier.Linear (ClosedPath (..), CubicBezier (..), @@ -72,6 +66,17 @@ import Reanimate.Math.Polygon (Polygon, pIsCCW) import Reanimate.Svg +#if !defined(NO_HGEOMETRY) +import Algorithms.Geometry.PolygonTriangulation.Triangulate (triangulate') + +import Data.Ext +import Data.Geometry.PlanarSubdivision (PolygonFaceData (..)) +import qualified Data.Geometry.Point as Geo +import qualified Data.Geometry.Polygon as Geo +import qualified Data.PlaneGraph as Geo +import Data.Proxy (Proxy (Proxy)) +#endif + -- | Shape drawn by continuous line. May have overlap, may be convex. newtype PolyShape = PolyShape { unPolyShape :: ClosedPath Double } deriving (Show) @@ -201,6 +206,9 @@ plDecompose' tol = -- | Split polygon into smaller, convex polygons. decomposePolygon :: [RPoint] -> [[RPoint]] +#if defined(NO_HGEOMETRY) +decomposePolygon = error "no hgeometry" +#else decomposePolygon poly = [ [ V2 x y | v <- V.toList (Geo.boundaryVertices f pg) @@ -212,6 +220,7 @@ decomposePolygon poly = p = Geo.fromPoints $ [ Geo.Point2 x y :+ () | V2 x y <- poly ] +#endif plPolygonify :: Double -> PolyShape -> [RPoint] plPolygonify tol shape = From 4e79d3da1e9d158b0f3ae3bec00b664b3e26d795 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 14 Jan 2021 16:19:28 +0800 Subject: [PATCH 037/114] Bump version to 1.1.3.2 --- ChangeLog.md | 8 ++++++-- reanimate.cabal | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 27811a3..8d38c58 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -6,12 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and the project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org) -## 1.1.3.1 -- 2020-01-04 +## 1.1.3.2 -- 2021-01-14 + + * Add flag for disabling the HGeometry dependency. + +## 1.1.3.1 -- 2021-01-04 * Fixed performance issue on Windows. * Fixed live viewer with Firefox. -## 1.1.3.0 -- 2020-01-04 +## 1.1.3.0 -- 2021-01-04 ## Added * Reanimate.reanimateLive diff --git a/reanimate.cabal b/reanimate.cabal index 135fe35..53c653e 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.3.1 +version: 1.1.3.2 -- synopsis: -- description: license: PublicDomain From d321b1781897600b4b2ffaacc9d9a7c3dcce168d Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 14 Jan 2021 16:23:17 +0800 Subject: [PATCH 038/114] Fix cabal file. --- reanimate.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reanimate.cabal b/reanimate.cabal index 53c653e..389258b 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -113,7 +113,7 @@ library Detach autogen-modules: Paths_reanimate if flag(no-hgeometry) - ghc-options: -DNO_HGEOMETRY + cpp-options: -DNO_HGEOMETRY else build-depends: hgeometry >=0.11.0.0, From f75196825bbbcd2cc5715e821b7f3052f435aa56 Mon Sep 17 00:00:00 2001 From: kunberg <66102480+kunberg@users.noreply.github.com> Date: Sun, 17 Jan 2021 08:39:42 +0100 Subject: [PATCH 039/114] Change mkRect definition So that the RectangleNode does not get wrapped in an unnecessary GroupNode. --- src/Reanimate/Svg/Constructors.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Reanimate/Svg/Constructors.hs b/src/Reanimate/Svg/Constructors.hs index aa57091..23e0386 100644 --- a/src/Reanimate/Svg/Constructors.hs +++ b/src/Reanimate/Svg/Constructors.hs @@ -250,8 +250,8 @@ withId idTag = attrId ?~ idTag -- | @mkRect width height@ creates a rectangle with given @with@ and @height@, centered at @(0, 0)@. -- See mkRect :: Double -> Double -> Tree -mkRect width height = translate (-width/2) (-height/2) $ rectangleTree $ defaultSvg - & rectUpperLeftCorner .~ (Num 0, Num 0) +mkRect width height = rectangleTree $ defaultSvg + & rectUpperLeftCorner .~ (Num (-width/2), Num (-height/2)) & rectWidth ?~ Num width & rectHeight ?~ Num height From 33056d4372abe9593321d0c11e690af4dd925190 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sat, 6 Feb 2021 18:44:58 +0800 Subject: [PATCH 040/114] Update test suite. --- examples/golden/bug_play2.golden | 20 ++++++++++---------- examples/golden/bug_play3.golden | 20 ++++++++++---------- examples/golden/bug_quad.golden | 20 ++++++++++---------- examples/golden/doc_addStatic.golden | 20 ++++++++++---------- examples/golden/doc_andThen.golden | 20 ++++++++++---------- examples/golden/doc_applyVar.golden | 20 ++++++++++---------- examples/golden/doc_bellS.golden | 20 ++++++++++---------- examples/golden/doc_chainT.golden | 20 ++++++++++---------- examples/golden/doc_cividis.golden | 20 ++++++++++---------- examples/golden/doc_constantS.golden | 20 ++++++++++---------- examples/golden/doc_cubicBezierS.golden | 20 ++++++++++---------- examples/golden/doc_curveS.golden | 20 ++++++++++---------- examples/golden/doc_destroySprite.golden | 20 ++++++++++---------- examples/golden/doc_drawBox.golden | 20 ++++++++++---------- examples/golden/doc_drawCircle.golden | 20 ++++++++++---------- examples/golden/doc_drawProgress.golden | 20 ++++++++++---------- examples/golden/doc_fadeT.golden | 20 ++++++++++---------- examples/golden/doc_fork.golden | 20 ++++++++++---------- examples/golden/doc_fromToS.golden | 20 ++++++++++---------- examples/golden/doc_githubIcon.golden | 20 ++++++++++---------- examples/golden/doc_greyscale.golden | 20 ++++++++++---------- examples/golden/doc_haskellLogo.golden | 20 ++++++++++---------- examples/golden/doc_hsv.golden | 20 ++++++++++---------- examples/golden/doc_hsvComponents.golden | 20 ++++++++++---------- examples/golden/doc_hsvMatlab.golden | 20 ++++++++++---------- examples/golden/doc_inferno.golden | 20 ++++++++++---------- examples/golden/doc_jet.golden | 20 ++++++++++---------- examples/golden/doc_labComponents.golden | 20 ++++++++++---------- examples/golden/doc_latex.golden | 20 ++++++++++---------- examples/golden/doc_latexAlign.golden | 20 ++++++++++---------- examples/golden/doc_lchComponents.golden | 20 ++++++++++---------- examples/golden/doc_magma.golden | 20 ++++++++++---------- examples/golden/doc_mapA.golden | 20 ++++++++++---------- examples/golden/doc_mkBackground.golden | 20 ++++++++++---------- examples/golden/doc_mkText.golden | 20 ++++++++++---------- examples/golden/doc_newSprite.golden | 20 ++++++++++---------- examples/golden/doc_newSpriteA'.golden | 20 ++++++++++---------- examples/golden/doc_newSpriteA.golden | 20 ++++++++++---------- examples/golden/doc_newSpriteSVG.golden | 20 ++++++++++---------- examples/golden/doc_oscillateS.golden | 20 ++++++++++---------- examples/golden/doc_overlapT.golden | 20 ++++++++++---------- examples/golden/doc_parA.golden | 20 ++++++++++---------- examples/golden/doc_parDropA.golden | 20 ++++++++++---------- examples/golden/doc_parLoopA.golden | 20 ++++++++++---------- examples/golden/doc_parula.golden | 20 ++++++++++---------- examples/golden/doc_pathify.golden | 20 ++++++++++---------- examples/golden/doc_pause.golden | 20 ++++++++++---------- examples/golden/doc_pauseAround.golden | 20 ++++++++++---------- examples/golden/doc_pauseAtBeginning.golden | 20 ++++++++++---------- examples/golden/doc_pauseAtEnd.golden | 20 ++++++++++---------- examples/golden/doc_plasma.golden | 20 ++++++++++---------- examples/golden/doc_play.golden | 20 ++++++++++---------- examples/golden/doc_playThenReverseA.golden | 20 ++++++++++---------- examples/golden/doc_queryNow.golden | 20 ++++++++++---------- examples/golden/doc_repeatA.golden | 20 ++++++++++---------- examples/golden/doc_reverseA.golden | 20 ++++++++++---------- examples/golden/doc_reverseS.golden | 20 ++++++++++---------- examples/golden/doc_rgbComponents.golden | 20 ++++++++++---------- examples/golden/doc_seqA.golden | 20 ++++++++++---------- examples/golden/doc_signalA.golden | 20 ++++++++++---------- examples/golden/doc_simpleVar.golden | 20 ++++++++++---------- examples/golden/doc_sinebow.golden | 20 ++++++++++---------- examples/golden/doc_slideDownT.golden | 20 ++++++++++---------- examples/golden/doc_slideLeftT.golden | 20 ++++++++++---------- examples/golden/doc_slideUpT.golden | 20 ++++++++++---------- examples/golden/doc_spriteE.golden | 20 ++++++++++---------- examples/golden/doc_spriteMap.golden | 20 ++++++++++---------- examples/golden/doc_spriteTween.golden | 20 ++++++++++---------- examples/golden/doc_spriteVar.golden | 20 ++++++++++---------- examples/golden/doc_spriteZ.golden | 20 ++++++++++---------- examples/golden/doc_svgLogo.golden | 20 ++++++++++---------- examples/golden/doc_turbo.golden | 20 ++++++++++---------- examples/golden/doc_unVar.golden | 20 ++++++++++---------- examples/golden/doc_viridis.golden | 20 ++++++++++---------- examples/golden/doc_wait.golden | 20 ++++++++++---------- examples/golden/doc_waitOn.golden | 20 ++++++++++---------- examples/golden/doc_withViewBox.golden | 20 ++++++++++---------- examples/golden/doc_writeVar.golden | 20 ++++++++++---------- examples/golden/doc_xyzComponents.golden | 20 ++++++++++---------- examples/golden/goo.golden | 20 ++++++++++---------- examples/golden/intro_canvas.golden | 20 ++++++++++---------- examples/golden/intro_canvas_square.golden | 20 ++++++++++---------- examples/golden/intro_hello.golden | 20 ++++++++++---------- examples/golden/latex_basic.golden | 20 ++++++++++---------- examples/golden/raster.golden | 20 ++++++++++---------- 85 files changed, 850 insertions(+), 850 deletions(-) diff --git a/examples/golden/bug_play2.golden b/examples/golden/bug_play2.golden index 5f6b3d7..67e6df8 100644 --- a/examples/golden/bug_play2.golden +++ b/examples/golden/bug_play2.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/bug_play3.golden b/examples/golden/bug_play3.golden index 5f6b3d7..67e6df8 100644 --- a/examples/golden/bug_play3.golden +++ b/examples/golden/bug_play3.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/bug_quad.golden b/examples/golden/bug_quad.golden index 5b42cc1..b78508b 100644 --- a/examples/golden/bug_quad.golden +++ b/examples/golden/bug_quad.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_addStatic.golden b/examples/golden/doc_addStatic.golden index daef1e9..10cdbf1 100644 --- a/examples/golden/doc_addStatic.golden +++ b/examples/golden/doc_addStatic.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_andThen.golden b/examples/golden/doc_andThen.golden index 9ec648d..14d72ab 100644 --- a/examples/golden/doc_andThen.golden +++ b/examples/golden/doc_andThen.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_applyVar.golden b/examples/golden/doc_applyVar.golden index 4064f8e..d67944a 100644 --- a/examples/golden/doc_applyVar.golden +++ b/examples/golden/doc_applyVar.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_bellS.golden b/examples/golden/doc_bellS.golden index a6edf6a..4af9bb4 100644 --- a/examples/golden/doc_bellS.golden +++ b/examples/golden/doc_bellS.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_chainT.golden b/examples/golden/doc_chainT.golden index 8b2fe0f..8b9fc53 100644 --- a/examples/golden/doc_chainT.golden +++ b/examples/golden/doc_chainT.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_cividis.golden b/examples/golden/doc_cividis.golden index 2a61337..67e3d13 100644 --- a/examples/golden/doc_cividis.golden +++ b/examples/golden/doc_cividis.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_constantS.golden b/examples/golden/doc_constantS.golden index d0e5437..94d3a67 100644 --- a/examples/golden/doc_constantS.golden +++ b/examples/golden/doc_constantS.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_cubicBezierS.golden b/examples/golden/doc_cubicBezierS.golden index d8c3aa2..7b89f86 100644 --- a/examples/golden/doc_cubicBezierS.golden +++ b/examples/golden/doc_cubicBezierS.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_curveS.golden b/examples/golden/doc_curveS.golden index 7a9f5f3..94ad79c 100644 --- a/examples/golden/doc_curveS.golden +++ b/examples/golden/doc_curveS.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_destroySprite.golden b/examples/golden/doc_destroySprite.golden index 71036d6..b90da20 100644 --- a/examples/golden/doc_destroySprite.golden +++ b/examples/golden/doc_destroySprite.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_drawBox.golden b/examples/golden/doc_drawBox.golden index b9eaaa5..77bd964 100644 --- a/examples/golden/doc_drawBox.golden +++ b/examples/golden/doc_drawBox.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_drawCircle.golden b/examples/golden/doc_drawCircle.golden index 348e1bf..3007b89 100644 --- a/examples/golden/doc_drawCircle.golden +++ b/examples/golden/doc_drawCircle.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_drawProgress.golden b/examples/golden/doc_drawProgress.golden index e5e8ccd..4e399ac 100644 --- a/examples/golden/doc_drawProgress.golden +++ b/examples/golden/doc_drawProgress.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_fadeT.golden b/examples/golden/doc_fadeT.golden index d45b7ff..b1b1d17 100644 --- a/examples/golden/doc_fadeT.golden +++ b/examples/golden/doc_fadeT.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_fork.golden b/examples/golden/doc_fork.golden index 86778d4..8dd954b 100644 --- a/examples/golden/doc_fork.golden +++ b/examples/golden/doc_fork.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_fromToS.golden b/examples/golden/doc_fromToS.golden index 4e84b31..352ac21 100644 --- a/examples/golden/doc_fromToS.golden +++ b/examples/golden/doc_fromToS.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_githubIcon.golden b/examples/golden/doc_githubIcon.golden index 452ca37..79dc46d 100644 --- a/examples/golden/doc_githubIcon.golden +++ b/examples/golden/doc_githubIcon.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_greyscale.golden b/examples/golden/doc_greyscale.golden index e20f1e2..ca009e8 100644 --- a/examples/golden/doc_greyscale.golden +++ b/examples/golden/doc_greyscale.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_haskellLogo.golden b/examples/golden/doc_haskellLogo.golden index 0d9a773..c5725b3 100644 --- a/examples/golden/doc_haskellLogo.golden +++ b/examples/golden/doc_haskellLogo.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_hsv.golden b/examples/golden/doc_hsv.golden index c83286b..11ba77d 100644 --- a/examples/golden/doc_hsv.golden +++ b/examples/golden/doc_hsv.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_hsvComponents.golden b/examples/golden/doc_hsvComponents.golden index 44d1898..229a007 100644 --- a/examples/golden/doc_hsvComponents.golden +++ b/examples/golden/doc_hsvComponents.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_hsvMatlab.golden b/examples/golden/doc_hsvMatlab.golden index bfaf290..17d187d 100644 --- a/examples/golden/doc_hsvMatlab.golden +++ b/examples/golden/doc_hsvMatlab.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_inferno.golden b/examples/golden/doc_inferno.golden index 28f0705..26b2183 100644 --- a/examples/golden/doc_inferno.golden +++ b/examples/golden/doc_inferno.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_jet.golden b/examples/golden/doc_jet.golden index 81e85bd..58ac93a 100644 --- a/examples/golden/doc_jet.golden +++ b/examples/golden/doc_jet.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_labComponents.golden b/examples/golden/doc_labComponents.golden index eb4a66b..6afc8bf 100644 --- a/examples/golden/doc_labComponents.golden +++ b/examples/golden/doc_labComponents.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_latex.golden b/examples/golden/doc_latex.golden index 00cef20..184056f 100644 --- a/examples/golden/doc_latex.golden +++ b/examples/golden/doc_latex.golden @@ -1,10 +1,10 @@ -0$e^{i\pi}+1=0$ -1$e^{i\pi}+1=0$ -2$e^{i\pi}+1=0$ -3$e^{i\pi}+1=0$ -4$e^{i\pi}+1=0$ -5$e^{i\pi}+1=0$ -6$e^{i\pi}+1=0$ -7$e^{i\pi}+1=0$ -8$e^{i\pi}+1=0$ -9$e^{i\pi}+1=0$ +0$e^{i\pi}+1=0$ +1$e^{i\pi}+1=0$ +2$e^{i\pi}+1=0$ +3$e^{i\pi}+1=0$ +4$e^{i\pi}+1=0$ +5$e^{i\pi}+1=0$ +6$e^{i\pi}+1=0$ +7$e^{i\pi}+1=0$ +8$e^{i\pi}+1=0$ +9$e^{i\pi}+1=0$ diff --git a/examples/golden/doc_latexAlign.golden b/examples/golden/doc_latexAlign.golden index b6c83db..2c428ff 100644 --- a/examples/golden/doc_latexAlign.golden +++ b/examples/golden/doc_latexAlign.golden @@ -1,10 +1,10 @@ -0\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -1\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -2\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -3\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -4\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -5\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -6\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -7\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -8\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} -9\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +0\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +1\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +2\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +3\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +4\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +5\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +6\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +7\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +8\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} +9\begin{align*}R = \frac{{\Delta x}}{{kA}}\end{align*} diff --git a/examples/golden/doc_lchComponents.golden b/examples/golden/doc_lchComponents.golden index ca175a9..3d3876a 100644 --- a/examples/golden/doc_lchComponents.golden +++ b/examples/golden/doc_lchComponents.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_magma.golden b/examples/golden/doc_magma.golden index 9b5f30d..148b872 100644 --- a/examples/golden/doc_magma.golden +++ b/examples/golden/doc_magma.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_mapA.golden b/examples/golden/doc_mapA.golden index 3118183..e53e712 100644 --- a/examples/golden/doc_mapA.golden +++ b/examples/golden/doc_mapA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_mkBackground.golden b/examples/golden/doc_mkBackground.golden index 087f82f..6c82cb3 100644 --- a/examples/golden/doc_mkBackground.golden +++ b/examples/golden/doc_mkBackground.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_mkText.golden b/examples/golden/doc_mkText.golden index c3df0f0..1f02386 100644 --- a/examples/golden/doc_mkText.golden +++ b/examples/golden/doc_mkText.golden @@ -1,10 +1,10 @@ -0 -1te -2tex -3text -4text -5text -6text -7text -8text -9text +0 +1te +2tex +3text +4text +5text +6text +7text +8text +9text diff --git a/examples/golden/doc_newSprite.golden b/examples/golden/doc_newSprite.golden index 05009fd..3b86914 100644 --- a/examples/golden/doc_newSprite.golden +++ b/examples/golden/doc_newSprite.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_newSpriteA'.golden b/examples/golden/doc_newSpriteA'.golden index bf9319f..ed2f497 100644 --- a/examples/golden/doc_newSpriteA'.golden +++ b/examples/golden/doc_newSpriteA'.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_newSpriteA.golden b/examples/golden/doc_newSpriteA.golden index 8d03a34..2797ecf 100644 --- a/examples/golden/doc_newSpriteA.golden +++ b/examples/golden/doc_newSpriteA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_newSpriteSVG.golden b/examples/golden/doc_newSpriteSVG.golden index daef1e9..10cdbf1 100644 --- a/examples/golden/doc_newSpriteSVG.golden +++ b/examples/golden/doc_newSpriteSVG.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_oscillateS.golden b/examples/golden/doc_oscillateS.golden index 68b4400..4f15a5b 100644 --- a/examples/golden/doc_oscillateS.golden +++ b/examples/golden/doc_oscillateS.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_overlapT.golden b/examples/golden/doc_overlapT.golden index e71e783..5e2101f 100644 --- a/examples/golden/doc_overlapT.golden +++ b/examples/golden/doc_overlapT.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_parA.golden b/examples/golden/doc_parA.golden index 0cee818..efd8be2 100644 --- a/examples/golden/doc_parA.golden +++ b/examples/golden/doc_parA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_parDropA.golden b/examples/golden/doc_parDropA.golden index 2fd6829..a4a9ce2 100644 --- a/examples/golden/doc_parDropA.golden +++ b/examples/golden/doc_parDropA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_parLoopA.golden b/examples/golden/doc_parLoopA.golden index 79f6254..f1aa6d8 100644 --- a/examples/golden/doc_parLoopA.golden +++ b/examples/golden/doc_parLoopA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_parula.golden b/examples/golden/doc_parula.golden index 0ae2d05..963b35c 100644 --- a/examples/golden/doc_parula.golden +++ b/examples/golden/doc_parula.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_pathify.golden b/examples/golden/doc_pathify.golden index 007d459..c46d978 100644 --- a/examples/golden/doc_pathify.golden +++ b/examples/golden/doc_pathify.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_pause.golden b/examples/golden/doc_pause.golden index c06748d..f73f325 100644 --- a/examples/golden/doc_pause.golden +++ b/examples/golden/doc_pause.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_pauseAround.golden b/examples/golden/doc_pauseAround.golden index 8aa39f8..800743d 100644 --- a/examples/golden/doc_pauseAround.golden +++ b/examples/golden/doc_pauseAround.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_pauseAtBeginning.golden b/examples/golden/doc_pauseAtBeginning.golden index ba640e8..5620c53 100644 --- a/examples/golden/doc_pauseAtBeginning.golden +++ b/examples/golden/doc_pauseAtBeginning.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_pauseAtEnd.golden b/examples/golden/doc_pauseAtEnd.golden index eef1896..ab41042 100644 --- a/examples/golden/doc_pauseAtEnd.golden +++ b/examples/golden/doc_pauseAtEnd.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_plasma.golden b/examples/golden/doc_plasma.golden index f980204..4db16b5 100644 --- a/examples/golden/doc_plasma.golden +++ b/examples/golden/doc_plasma.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_play.golden b/examples/golden/doc_play.golden index 6fbd8b7..ca0d781 100644 --- a/examples/golden/doc_play.golden +++ b/examples/golden/doc_play.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_playThenReverseA.golden b/examples/golden/doc_playThenReverseA.golden index da1142a..cdc2829 100644 --- a/examples/golden/doc_playThenReverseA.golden +++ b/examples/golden/doc_playThenReverseA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_queryNow.golden b/examples/golden/doc_queryNow.golden index b726f1b..e1d33e2 100644 --- a/examples/golden/doc_queryNow.golden +++ b/examples/golden/doc_queryNow.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6Now=2.0 -7Now=2.0 -8Now=2.0 -9Now=2.0 +0 +1 +2 +3 +4 +5 +6Now=2.0 +7Now=2.0 +8Now=2.0 +9Now=2.0 diff --git a/examples/golden/doc_repeatA.golden b/examples/golden/doc_repeatA.golden index 754e976..7822583 100644 --- a/examples/golden/doc_repeatA.golden +++ b/examples/golden/doc_repeatA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_reverseA.golden b/examples/golden/doc_reverseA.golden index 52181fc..e457d9f 100644 --- a/examples/golden/doc_reverseA.golden +++ b/examples/golden/doc_reverseA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_reverseS.golden b/examples/golden/doc_reverseS.golden index 1583a0f..c7c2133 100644 --- a/examples/golden/doc_reverseS.golden +++ b/examples/golden/doc_reverseS.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_rgbComponents.golden b/examples/golden/doc_rgbComponents.golden index 1e65709..7cf0e3b 100644 --- a/examples/golden/doc_rgbComponents.golden +++ b/examples/golden/doc_rgbComponents.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_seqA.golden b/examples/golden/doc_seqA.golden index 289d74b..4ca4299 100644 --- a/examples/golden/doc_seqA.golden +++ b/examples/golden/doc_seqA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_signalA.golden b/examples/golden/doc_signalA.golden index 923213c..9a9c276 100644 --- a/examples/golden/doc_signalA.golden +++ b/examples/golden/doc_signalA.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_simpleVar.golden b/examples/golden/doc_simpleVar.golden index e1a2b1b..fd32604 100644 --- a/examples/golden/doc_simpleVar.golden +++ b/examples/golden/doc_simpleVar.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_sinebow.golden b/examples/golden/doc_sinebow.golden index 917e4df..475b005 100644 --- a/examples/golden/doc_sinebow.golden +++ b/examples/golden/doc_sinebow.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_slideDownT.golden b/examples/golden/doc_slideDownT.golden index 1c95696..c3563d7 100644 --- a/examples/golden/doc_slideDownT.golden +++ b/examples/golden/doc_slideDownT.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_slideLeftT.golden b/examples/golden/doc_slideLeftT.golden index 419ccac..7c46484 100644 --- a/examples/golden/doc_slideLeftT.golden +++ b/examples/golden/doc_slideLeftT.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_slideUpT.golden b/examples/golden/doc_slideUpT.golden index cc99cce..f78076b 100644 --- a/examples/golden/doc_slideUpT.golden +++ b/examples/golden/doc_slideUpT.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_spriteE.golden b/examples/golden/doc_spriteE.golden index 224fa0e..7429921 100644 --- a/examples/golden/doc_spriteE.golden +++ b/examples/golden/doc_spriteE.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_spriteMap.golden b/examples/golden/doc_spriteMap.golden index 7e8c6f6..0f1d597 100644 --- a/examples/golden/doc_spriteMap.golden +++ b/examples/golden/doc_spriteMap.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_spriteTween.golden b/examples/golden/doc_spriteTween.golden index 5e489b6..0e4f409 100644 --- a/examples/golden/doc_spriteTween.golden +++ b/examples/golden/doc_spriteTween.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_spriteVar.golden b/examples/golden/doc_spriteVar.golden index 4064f8e..d67944a 100644 --- a/examples/golden/doc_spriteVar.golden +++ b/examples/golden/doc_spriteVar.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_spriteZ.golden b/examples/golden/doc_spriteZ.golden index fedd525..37ad852 100644 --- a/examples/golden/doc_spriteZ.golden +++ b/examples/golden/doc_spriteZ.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_svgLogo.golden b/examples/golden/doc_svgLogo.golden index 7411ba7..fa1042d 100644 --- a/examples/golden/doc_svgLogo.golden +++ b/examples/golden/doc_svgLogo.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_turbo.golden b/examples/golden/doc_turbo.golden index 4c56b19..4125a56 100644 --- a/examples/golden/doc_turbo.golden +++ b/examples/golden/doc_turbo.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_unVar.golden b/examples/golden/doc_unVar.golden index d113099..42a4bcc 100644 --- a/examples/golden/doc_unVar.golden +++ b/examples/golden/doc_unVar.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_viridis.golden b/examples/golden/doc_viridis.golden index 9d7823c..61284eb 100644 --- a/examples/golden/doc_viridis.golden +++ b/examples/golden/doc_viridis.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_wait.golden b/examples/golden/doc_wait.golden index aa22cfe..ed8dee0 100644 --- a/examples/golden/doc_wait.golden +++ b/examples/golden/doc_wait.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_waitOn.golden b/examples/golden/doc_waitOn.golden index 6fbd8b7..ca0d781 100644 --- a/examples/golden/doc_waitOn.golden +++ b/examples/golden/doc_waitOn.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_withViewBox.golden b/examples/golden/doc_withViewBox.golden index af4fe0d..a549f61 100644 --- a/examples/golden/doc_withViewBox.golden +++ b/examples/golden/doc_withViewBox.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_writeVar.golden b/examples/golden/doc_writeVar.golden index 7e87235..91a10a6 100644 --- a/examples/golden/doc_writeVar.golden +++ b/examples/golden/doc_writeVar.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/doc_xyzComponents.golden b/examples/golden/doc_xyzComponents.golden index a1668bc..bd337b2 100644 --- a/examples/golden/doc_xyzComponents.golden +++ b/examples/golden/doc_xyzComponents.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/goo.golden b/examples/golden/goo.golden index ac5ca02..59e8990 100644 --- a/examples/golden/goo.golden +++ b/examples/golden/goo.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 diff --git a/examples/golden/intro_canvas.golden b/examples/golden/intro_canvas.golden index f27de81..09198cf 100644 --- a/examples/golden/intro_canvas.golden +++ b/examples/golden/intro_canvas.golden @@ -1,10 +1,10 @@ -016 units16 units9 units9 units0.0,0.00.0,0.0 -116 units16 units9 units9 units2.0,1.42.0,1.4 -216 units16 units9 units9 units2.8,1.62.8,1.6 -316 units16 units9 units9 units-4.0,3.0-4.0,3.0 -416 units16 units9 units9 units-2.8,-1.8-2.8,-1.8 -516 units16 units9 units9 units-2.4,-2.0-2.4,-2.0 -616 units16 units9 units9 units5.0,-2.05.0,-2.0 -716 units16 units9 units9 units2.9,1.22.9,1.2 -816 units16 units9 units9 units1.0,0.51.0,0.5 -916 units16 units9 units9 units0.0,0.00.0,0.0 +016 units16 units9 units9 units0.0,0.00.0,0.0 +116 units16 units9 units9 units2.0,1.42.0,1.4 +216 units16 units9 units9 units2.8,1.62.8,1.6 +316 units16 units9 units9 units-4.0,3.0-4.0,3.0 +416 units16 units9 units9 units-2.8,-1.8-2.8,-1.8 +516 units16 units9 units9 units-2.4,-2.0-2.4,-2.0 +616 units16 units9 units9 units5.0,-2.05.0,-2.0 +716 units16 units9 units9 units2.9,1.22.9,1.2 +816 units16 units9 units9 units1.0,0.51.0,0.5 +916 units16 units9 units9 units0.0,0.00.0,0.0 diff --git a/examples/golden/intro_canvas_square.golden b/examples/golden/intro_canvas_square.golden index d3eba6a..e7b2f1b 100644 --- a/examples/golden/intro_canvas_square.golden +++ b/examples/golden/intro_canvas_square.golden @@ -1,10 +1,10 @@ -0 8 units 8 units 8 units 8 units 0.0,0.0 0.0,0.0 -1 8 units 8 units 8 units 8 units 1.7,1.0 1.7,1.0 -2 8 units 8 units 8 units 8 units 0.4,0.6 0.4,0.6 -3 8 units 8 units 8 units 8 units -1.0,1.5 -1.0,1.5 -4 8 units 8 units 8 units 8 units -1.7,-2.5 -1.7,-2.5 -5 8 units 8 units 8 units 8 units -0.7,-1.5 -0.7,-1.5 -6 8 units 8 units 8 units 8 units 2.5,-1.0 2.5,-1.0 -7 8 units 8 units 8 units 8 units 1.7,1.1 1.7,1.1 -8 8 units 8 units 8 units 8 units 0.7,0.5 0.7,0.5 -9 8 units 8 units 8 units 8 units 0.0,0.0 0.0,0.0 +0 8 units 8 units 8 units 8 units 0.0,0.0 0.0,0.0 +1 8 units 8 units 8 units 8 units 1.7,1.0 1.7,1.0 +2 8 units 8 units 8 units 8 units 0.4,0.6 0.4,0.6 +3 8 units 8 units 8 units 8 units -1.0,1.5 -1.0,1.5 +4 8 units 8 units 8 units 8 units -1.7,-2.5 -1.7,-2.5 +5 8 units 8 units 8 units 8 units -0.7,-1.5 -0.7,-1.5 +6 8 units 8 units 8 units 8 units 2.5,-1.0 2.5,-1.0 +7 8 units 8 units 8 units 8 units 1.7,1.1 1.7,1.1 +8 8 units 8 units 8 units 8 units 0.7,0.5 0.7,0.5 +9 8 units 8 units 8 units 8 units 0.0,0.0 0.0,0.0 diff --git a/examples/golden/intro_hello.golden b/examples/golden/intro_hello.golden index 968040f..6b666f6 100644 --- a/examples/golden/intro_hello.golden +++ b/examples/golden/intro_hello.golden @@ -1,10 +1,10 @@ -0Hello world -1Hello world -2Hello world -3Hello world -4Hello world -5Hello world -6Hello world -7Hello world -8Hello world -9Hello world +0Hello world +1Hello world +2Hello world +3Hello world +4Hello world +5Hello world +6Hello world +7Hello world +8Hello world +9Hello world diff --git a/examples/golden/latex_basic.golden b/examples/golden/latex_basic.golden index 8225fb9..6e4811e 100644 --- a/examples/golden/latex_basic.golden +++ b/examples/golden/latex_basic.golden @@ -1,10 +1,10 @@ -0\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -1\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -2\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -3\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -4\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -5\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -6\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -7\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -8\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} -9\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +0\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +1\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +2\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +3\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +4\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +5\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +6\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +7\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +8\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} +9\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*}\begin{align*}\sum_{k=1}^\infty {1 \over k^2} = {\pi^2 \over 6}\end{align*} diff --git a/examples/golden/raster.golden b/examples/golden/raster.golden index c27a08d..6827c47 100644 --- a/examples/golden/raster.golden +++ b/examples/golden/raster.golden @@ -1,10 +1,10 @@ -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 From f4878053b1433487d6a2aeebfebd8e171732a155 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Tue, 9 Feb 2021 20:47:52 +0800 Subject: [PATCH 041/114] reanimateLiveEntry should recurse. This fixes issue #195. --- src/Reanimate/Driver/Daemon.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Reanimate/Driver/Daemon.hs b/src/Reanimate/Driver/Daemon.hs index 572fb3c..a7ea7b0 100644 --- a/src/Reanimate/Driver/Daemon.hs +++ b/src/Reanimate/Driver/Daemon.hs @@ -111,7 +111,7 @@ reanimateLiveEntry animation = do return $ unlines [ ":r" , "Reanimate.reanimate (" ++ animation ++ ")" - , ":cmd System.Environment.withArgs [\"primed\"] Reanimate.reanimateLive" ] + , ":cmd System.Environment.withArgs [\"primed\"] (Reanimate.reanimateLiveEntry " ++ show animation ++ ")"] waitForChanges :: IO () waitForChanges = withManager $ \mgr -> do From 0e580e0fdf82d59465a364408a7bd1fe6284dfe1 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sat, 20 Feb 2021 18:46:26 +0800 Subject: [PATCH 042/114] Use newest reanimate-svg. (#197) --- examples/fe_bleed.hs | 3 +-- examples/tut_glue_blender.hs | 3 +-- examples/tut_glue_latex.hs | 3 +-- examples/tut_glue_povray.hs | 3 +-- examples/tut_glue_povray_ortho.hs | 3 +-- reanimate.cabal | 2 +- src/Reanimate/LaTeX.hs | 5 ++--- src/Reanimate/Misc.hs | 24 ++++++++++++------------ src/Reanimate/Scene/Object.hs | 3 +-- stack-lts-14.yaml | 2 +- stack-lts-15.yaml | 2 +- stack-lts-17.yaml | 13 +++++++++++++ stack.yaml | 4 ++-- videos/showcase/showcase.hs | 2 +- 14 files changed, 39 insertions(+), 33 deletions(-) create mode 100644 stack-lts-17.yaml diff --git a/examples/fe_bleed.hs b/examples/fe_bleed.hs index df2e3c7..21a0e32 100755 --- a/examples/fe_bleed.hs +++ b/examples/fe_bleed.hs @@ -18,7 +18,6 @@ import Codec.Picture.Types import Control.Lens hiding (magma) import Control.Monad import Data.Fixed -import Data.Monoid import Graphics.SvgTree import Linear.V2 import Linear.Vector @@ -129,7 +128,7 @@ main = reanimate $ scene $ do & filterWidth .~ pure (Percent 1) & filterHeight .~ pure (Percent 1) , FETurbulence $ defaultSvg - & turbulenceBaseFrequency .~ (2, Last Nothing) + & turbulenceBaseFrequency .~ (2, Nothing) & turbulenceType .~ FractalNoiseType & turbulenceNumOctaves .~ 1 & turbulenceSeed .~ 1 diff --git a/examples/tut_glue_blender.hs b/examples/tut_glue_blender.hs index 6b71825..bf891af 100755 --- a/examples/tut_glue_blender.hs +++ b/examples/tut_glue_blender.hs @@ -12,7 +12,6 @@ import Reanimate.Builtin.Documentation import Codec.Picture.Types import Control.Lens ((&), (^.)) import Control.Monad -import Data.Monoid import qualified Data.Text as T import Graphics.SvgTree import NeatInterpolation @@ -252,7 +251,7 @@ drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation drawAnimation' mbSeed fillDur step svg = scene $ do forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do let sWidth = - case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of + case toUserUnit defaultDPI <$> (attr ^. strokeWidth) of Just (Num d) -> d _ -> defaultStrokeWidth fork $ do diff --git a/examples/tut_glue_latex.hs b/examples/tut_glue_latex.hs index 4397351..0d0a74a 100755 --- a/examples/tut_glue_latex.hs +++ b/examples/tut_glue_latex.hs @@ -11,7 +11,6 @@ import Codec.Picture import Codec.Picture.Types import Control.Lens ((&), (^.)) import Control.Monad -import Data.Monoid import Graphics.SvgTree import System.Random import "random-shuffle" System.Random.Shuffle @@ -75,7 +74,7 @@ drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation drawAnimation' mbSeed fillDur step svg = scene $ do forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do let sWidth = - case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of + case toUserUnit defaultDPI <$> (attr ^. strokeWidth) of Just (Num d) -> d _ -> defaultStrokeWidth fork $ do diff --git a/examples/tut_glue_povray.hs b/examples/tut_glue_povray.hs index 796e561..6dc5ae6 100755 --- a/examples/tut_glue_povray.hs +++ b/examples/tut_glue_povray.hs @@ -13,7 +13,6 @@ import Codec.Picture import Codec.Picture.Types import Control.Lens ((&), (^.)) import Control.Monad -import Data.Monoid import Data.Text (Text) import qualified Data.Text as T import Graphics.SvgTree hiding (Text) @@ -146,7 +145,7 @@ drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation drawAnimation' mbSeed fillDur step svg = scene $ do forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do let sWidth = - case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of + case toUserUnit defaultDPI <$> (attr ^. strokeWidth) of Just (Num d) -> d _ -> defaultStrokeWidth fork $ do diff --git a/examples/tut_glue_povray_ortho.hs b/examples/tut_glue_povray_ortho.hs index 941a7cc..2753195 100755 --- a/examples/tut_glue_povray_ortho.hs +++ b/examples/tut_glue_povray_ortho.hs @@ -13,7 +13,6 @@ import Codec.Picture import Codec.Picture.Types import Control.Lens ((^.),(&)) import Control.Monad -import Data.Monoid import Data.Text (Text) import qualified Data.Text as T import Graphics.SvgTree hiding (Text) @@ -183,7 +182,7 @@ drawAnimation' :: Maybe Int -> Double -> Double -> SVG -> Animation drawAnimation' mbSeed fillDur step svg = scene $ do forM_ (zip [0..] $ shuf $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do let sWidth = - case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of + case toUserUnit defaultDPI <$> (attr ^. strokeWidth) of Just (Num d) -> d _ -> defaultStrokeWidth fork $ do diff --git a/reanimate.cabal b/reanimate.cabal index 389258b..2ba41cf 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -150,7 +150,7 @@ library process >=1.6.3.0, random >=1.1, random-shuffle >=0.0.4, - reanimate-svg >=0.13.0.0, + reanimate-svg >=0.13.0.1, split >=0.2.3.3, temporary >=1.3, text >=1.2.3.0, diff --git a/src/Reanimate/LaTeX.hs b/src/Reanimate/LaTeX.hs index 97338e9..bdc158b 100644 --- a/src/Reanimate/LaTeX.hs +++ b/src/Reanimate/LaTeX.hs @@ -42,7 +42,6 @@ import Control.Monad.State (runState, state) import qualified Data.ByteString as B import Data.Foldable (Foldable (fold)) import Data.Hashable (Hashable) -import Data.Monoid (Last (Last)) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Encoding as T @@ -192,7 +191,7 @@ postprocess = . lowerIds . mapTree clearDrawAttr where - clearDrawAttr t = t & strokeColor .~ Last Nothing + clearDrawAttr t = t & strokeColor .~ Nothing enginePostprocess :: TexEngine -> Tree -> Tree enginePostprocess LuaLaTeX svg = translate 0 (svgHeight svg) svg @@ -202,7 +201,7 @@ removeClipPaths :: SVG -> SVG removeClipPaths = mapTree worker where worker ClipPathTree {} = None - worker t = t & clipRule .~ Last Nothing & clipPathRef .~ Last Nothing + worker t = t & clipRule .~ Nothing & clipPathRef .~ Nothing -- executable, arguments, header, tex latexToSVG :: TexEngine -> String -> String -> [String] -> Text -> IO Tree diff --git a/src/Reanimate/Misc.hs b/src/Reanimate/Misc.hs index 953f34b..b5e8295 100644 --- a/src/Reanimate/Misc.hs +++ b/src/Reanimate/Misc.hs @@ -44,18 +44,18 @@ runCmd_ exec args = do _ <- evaluate (length stdout + length errMsg) case ret of ExitSuccess -> return (Right stdout) - ExitFailure err - | False -> - return $ - Left $ - "Failed to run: " - ++ showCommandForUser exec args - ++ "\n" - ++ "Error code: " - ++ show err - ++ "\n" - ++ "stderr: " - ++ errMsg + -- ExitFailure err + -- | False -> + -- return $ + -- Left $ + -- "Failed to run: " + -- ++ showCommandForUser exec args + -- ++ "\n" + -- ++ "Error code: " + -- ++ show err + -- ++ "\n" + -- ++ "stderr: " + -- ++ errMsg ExitFailure {} | null errMsg -> -- LaTeX prints errors to stdout. :( return $ Left stdout diff --git a/src/Reanimate/Scene/Object.hs b/src/Reanimate/Scene/Object.hs index 4f2bd60..b52fbe0 100644 --- a/src/Reanimate/Scene/Object.hs +++ b/src/Reanimate/Scene/Object.hs @@ -5,7 +5,6 @@ module Reanimate.Scene.Object where import Control.Lens import Control.Monad (forM_, void) import Control.Monad.State (State, execState) -import Data.Monoid (Last (getLast)) import Graphics.SvgTree (Number (..), Tree, pattern None, strokeWidth, toUserUnit) import Linear.V2 (R1 (_x), R2 (_y), V2 (..)) import Linear.Vector (Additive (lerp), (^*)) @@ -500,7 +499,7 @@ oDraw :: SVG -> Animation oDraw = oStagger $ \svg -> scene $ forM_ (svgGlyphs $ pathify svg) $ \(ctx, attr, node) -> do let sWidth = - case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of + case toUserUnit defaultDPI <$> (attr ^. strokeWidth) of Just (Num d) -> max defaultStrokeWidth d _ -> defaultStrokeWidth -- wait 1 diff --git a/stack-lts-14.yaml b/stack-lts-14.yaml index ac962ee..837d598 100644 --- a/stack-lts-14.yaml +++ b/stack-lts-14.yaml @@ -6,7 +6,7 @@ packages: - . extra-deps: -- reanimate-svg-0.13.0.0 +- reanimate-svg-0.13.0.1 - chiphunk-0.1.2.1 - cubicbezier-0.6.0.6@sha256:2191ff47144d9a13a2784651a33d340cd31be1926a6c188925143103eb3c8db3 - fast-math-1.0.2@sha256:91181eb836e54413cc5a841e797c42b2264954e893ea530b6fc4da0dccf6a8b7 diff --git a/stack-lts-15.yaml b/stack-lts-15.yaml index b672188..9e6aabd 100644 --- a/stack-lts-15.yaml +++ b/stack-lts-15.yaml @@ -8,7 +8,7 @@ packages: extra-deps: - chiphunk-0.1.2.1 - earcut-0.1.0.4@sha256:d5118b3eecf24d130263d81fb30f1ff56b1db43036582bfd1d8cc9ba3adae8be,1010 -- reanimate-svg-0.13.0.0 +- reanimate-svg-0.13.0.1 - hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 - hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/stack-lts-17.yaml b/stack-lts-17.yaml new file mode 100644 index 0000000..720acd2 --- /dev/null +++ b/stack-lts-17.yaml @@ -0,0 +1,13 @@ +resolver: lts-17.4 + +allow-newer: false + +packages: +- . + +extra-deps: +- earcut-0.1.0.4 +- reanimate-svg-0.13.0.1 +- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 +- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 +- vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/stack.yaml b/stack.yaml index 6056cb6..bc0abd4 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-16.27 +resolver: lts-16.31 allow-newer: false @@ -7,7 +7,7 @@ packages: extra-deps: - earcut-0.1.0.4 -- reanimate-svg-0.13.0.0 +- reanimate-svg-0.13.0.1 - hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 - hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/videos/showcase/showcase.hs b/videos/showcase/showcase.hs index 2ef0f4d..a588733 100755 --- a/videos/showcase/showcase.hs +++ b/videos/showcase/showcase.hs @@ -294,7 +294,7 @@ drawAnimation' :: Double -> Double -> SVG -> Animation drawAnimation' fillDur step svg = scene $ do forM_ (zip [0..] $ svgGlyphs svg) $ \(n, (fn, attr, tree)) -> do let sWidth = - case toUserUnit defaultDPI <$> getLast (attr ^. strokeWidth) of + case toUserUnit defaultDPI <$> (attr ^. strokeWidth) of Just (Num d) -> d _ -> defaultStrokeWidth fork $ do From 3a8dc6c7697ef827e96ec1d33a79489e66e25b93 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 11 Mar 2021 13:06:58 +0800 Subject: [PATCH 043/114] Use warnings instead of errors for stackage nightly tests. (#202) --- .github/workflows/stackage-nightly.yml | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/stackage-nightly.yml b/.github/workflows/stackage-nightly.yml index 6bec136..85cba61 100644 --- a/.github/workflows/stackage-nightly.yml +++ b/.github/workflows/stackage-nightly.yml @@ -1,8 +1,6 @@ name: Stackage nightly on: - push: - branches: [ master ] pull_request: branches: [ master ] @@ -33,11 +31,27 @@ jobs: ${{ runner.os }}- - name: Build nightly + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true run: | rm -fr discord-bot playground dist-newstyle - rm -f stack.yaml && stack init --resolver nightly - # Build twice because the stackage servers are incredibly unreliable. - stack build --resolver nightly --haddock --test --only-dependencies --bench --no-run-benchmarks || stack build --resolver nightly --haddock --test --only-dependencies --bench --no-run-benchmarks + rm -f stack.yaml + stack init --resolver nightly \ + && echo "::set-env name=passed::true" \ + || echo "::set-env name=passed::false" + stack build --resolver nightly --haddock --test --only-dependencies --bench --no-run-benchmarks \ + && echo "::set-env name=passed::true" \ + || echo "::set-env name=passed::false" - name: Test nightly + if: env.passed == 'true' run: | stack build --resolver nightly --haddock --test --bench --no-run-benchmarks + - name: Report status + if: env.passed == 'false' + uses: mshick/add-pr-comment@v1 + with: + message: | + Warning: Failed to build against stack nightly. + repo-token: ${{ secrets.GITHUB_TOKEN }} + repo-token-user-login: 'github-actions[bot]' # The user.login for temporary GitHub tokens + allow-repeats: false # This is the default From 9d9544df7ddaaa3473f92c9c09ddd9ae7a9565b7 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 11 Mar 2021 13:07:34 +0800 Subject: [PATCH 044/114] Improve README and error handling when encountering cabal bug. (#201) --- README.md | 33 ++++++++++++++++++++++++--------- src/Reanimate/Driver.hs | 20 ++++++++++++++++---- src/Reanimate/Driver/Server.hs | 11 ++++++----- 3 files changed, 46 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index a6fb481..c85e327 100644 --- a/README.md +++ b/README.md @@ -63,11 +63,26 @@ Optionally, you can install one or more of these programs to enable additional f I highly recommend that you install at least 'ffmpeg' and 'latex'. -# Installing / Running an example +# Getting started / Running an example -Reanimate ships with a web-based viewer and automatic code reloading. To get a small demo -up and running, clone the repository, run one of the examples (this will install the library), -and wait for a browser window to open: +Reanimate offers stack templates for getting started with a minimal example and +automatic code reloading. Running the commands below will put a one-line animation +in the 'animate' folder and then display the animation in a browser window. You can +then edit the animation source code and watch the animation update in real time: + +```console +$ stack new animate github:reanimate/plain +$ cd animate/ +$ # both 'cabal repl' and 'stack repl' can be used here: +$ cabal repl +:cmd reanimateLive +``` + +## Running examples from the repository + +Reanimate has a large collection of small examples which are both used for regression testing +and for GIFs in the API reference documentation. You can run these examples by first cloning the +repository and then running the examples as if they were executables: ```console $ git clone https://github.com/reanimate/reanimate.git @@ -76,11 +91,11 @@ $ stack build $ stack ./examples/doc_drawCircle.hs ``` -This should render the `doc_drawCircle` example in a new browser window. If you then change the -animation source code, the browser window will automatically reload and show the updated animation. +This should render the `doc_drawCircle` example in a new browser window. Automatic code reloading +will not be enabled unless you run `:cmd reanimateLive` from a GHCi session. -## Using Cabal +## Running examples from the repository using Cabal It's also possible to use cabal instead of stack: @@ -90,7 +105,7 @@ $ cd reanimate/ $ cabal v2-build $ # Workaround for a cabal bug: https://github.com/haskell/cabal/issues/6235 $ export reanimate_datadir=`pwd` -$ cabal v2-exec -- runhaskell examples/doc_drawCircle.hs --ghc ghc +$ cabal v2-exec -- runhaskell examples/doc_drawCircle.hs ``` ## Using Nix @@ -113,7 +128,7 @@ to pick up reanimate. Now, still within the `nix-shell` you can run: ```console -[nix-shell:./reanimate]$ reanimate_datadir=. runhaskell examples/doc_drawCircle.hs --ghc `which ghc` +[nix-shell:./reanimate]$ reanimate_datadir=. runhaskell examples/doc_drawCircle.hs ``` diff --git a/src/Reanimate/Driver.hs b/src/Reanimate/Driver.hs index 36fd2a5..70524c0 100644 --- a/src/Reanimate/Driver.hs +++ b/src/Reanimate/Driver.hs @@ -4,18 +4,19 @@ module Reanimate.Driver ) where -import Control.Applicative ((<|>)) +import Control.Applicative ((<|>)) import Control.Concurrent import Control.Monad import Data.Either import Data.Maybe -import Reanimate.Animation (Animation, duration) +import Paths_reanimate (getDataFileName) +import Reanimate.Animation (Animation, duration) import Reanimate.Driver.CLI import Reanimate.Driver.Check import Reanimate.Driver.Daemon import Reanimate.Parameters -import Reanimate.Render (render, renderSnippets, renderSvgs, renderSvgs_, - selectRaster) +import Reanimate.Render (render, renderSnippets, renderSvgs, renderSvgs_, + selectRaster) import System.Directory import System.Exit import System.FilePath @@ -200,10 +201,21 @@ makeEven :: Int -> Int makeEven x | even x = x | otherwise = x - 1 +sanityCheck :: IO () +sanityCheck = do + url <- getDataFileName "viewer-elm/dist/index.html" + hasClient <- doesFileExist url + unless hasClient $ do + hPutStrLn stderr $ "Couldn't find web client at: " ++ url + hPutStrLn stderr $ "You may need to run:" + hPutStrLn stderr $ " $ export reanimate_datadir=`pwd`" + hPutStrLn stderr $ "For more information, see this cabal issue: https://github.com/haskell/cabal/issues/6235" + exitFailure -- serve viewVerbose viewGHCPath viewGHCOpts viewOrigin viewAnimation :: Bool -> Animation -> IO () viewAnimation _detach animation = do + sanityCheck detached <- ensureDaemon let rate = 60 diff --git a/src/Reanimate/Driver/Server.hs b/src/Reanimate/Driver/Server.hs index 0ca8a31..f3f8c79 100644 --- a/src/Reanimate/Driver/Server.hs +++ b/src/Reanimate/Driver/Server.hs @@ -14,12 +14,12 @@ import qualified Data.Map as Map import qualified Data.Text as T import Network.Socket (AddrInfo (..), AddrInfoFlag (..), SocketOption (..), SocketType (Stream), accept, bind, close, defaultHints, - getAddrInfo, listen, socket, - setCloseOnExecIfNeeded, setSocketOption, withFdSocket, - withSocketsDo) + getAddrInfo, listen, setCloseOnExecIfNeeded, + setSocketOption, socket, withFdSocket, withSocketsDo) import Network.Socket.ByteString (recv) import Network.WebSockets import Paths_reanimate (getDataFileName) +import System.Exit (exitFailure) import System.IO (hPutStrLn, stderr) import Web.Browser (openBrowser) @@ -124,8 +124,9 @@ openViewer :: IO () openViewer = do url <- getDataFileName "viewer-elm/dist/index.html" bSucc <- openBrowser url - unless bSucc $ - hPutStrLn stderr $ "Failed to open browser. Manually visit: " ++ url + unless bSucc $ do + hPutStrLn stderr "Failed to open browser." + exitFailure ------------------------------------------------------------------------------- -- Websocket API From 7887fef4340d79393d04a59339a03cc961f46c1b Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 11 Mar 2021 13:08:14 +0800 Subject: [PATCH 045/114] Update stack lts version. (#200) * Use newest reanimate-svg. * Use lts-16 for docker. --- Dockerfile.base | 3 ++- Dockerfile.discord | 3 ++- Dockerfile.playground | 3 ++- discord-bot/stack.yaml | 2 +- discord-bot/stack.yaml.lock | 8 ++++---- playground/stack.yaml | 2 +- stack-lts-16.yaml | 13 +++++++++++++ stack.yaml | 2 +- 8 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 stack-lts-16.yaml diff --git a/Dockerfile.base b/Dockerfile.base index 50951ab..d837f01 100644 --- a/Dockerfile.base +++ b/Dockerfile.base @@ -20,6 +20,7 @@ RUN apt-get update && \ WORKDIR /src # Install reanimate dependencies and cache the layer -ADD reanimate.cabal stack.yaml ./ +ADD reanimate.cabal stack-lts-16.yaml ./ +ADD stack-lts-16.yaml ./stack.yaml RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock RUN rm reanimate.cabal stack.yaml diff --git a/Dockerfile.discord b/Dockerfile.discord index 0f81584..0a6ec6b 100644 --- a/Dockerfile.discord +++ b/Dockerfile.discord @@ -3,7 +3,8 @@ FROM reanimate/base WORKDIR /src # Install reanimate dependencies and cache the layer -ADD reanimate.cabal stack.yaml ./ +ADD reanimate.cabal ./ +ADD stack-lts-16.yaml ./stack.yaml RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock # Install discord-bot dependencies and cache the layer diff --git a/Dockerfile.playground b/Dockerfile.playground index c3984c5..ea03415 100644 --- a/Dockerfile.playground +++ b/Dockerfile.playground @@ -3,7 +3,8 @@ FROM reanimate/base WORKDIR /src # Install reanimate dependencies and cache the layer -ADD reanimate.cabal stack.yaml ./ +ADD reanimate.cabal ./ +ADD stack-lts-16.yaml ./stack.yaml RUN stack build --only-dependencies --no-install-ghc --system-ghc --haddock # Install playground dependencies and cache the layer diff --git a/discord-bot/stack.yaml b/discord-bot/stack.yaml index d3d2f62..5d7e552 100644 --- a/discord-bot/stack.yaml +++ b/discord-bot/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-16.12 +resolver: lts-16.31 allow-newer: false diff --git a/discord-bot/stack.yaml.lock b/discord-bot/stack.yaml.lock index 787704f..6582b4e 100644 --- a/discord-bot/stack.yaml.lock +++ b/discord-bot/stack.yaml.lock @@ -27,7 +27,7 @@ packages: hackage: req-3.1.0@sha256:b058fd588ccdbced9e7d33b9112cd41960f29ce90acc7d77e2dd7518da171a01,4926 snapshots: - completed: - size: 532377 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/16/12.yaml - sha256: f914cfa23fef85bdf895e300a8234d9d0edc2dbec67f4bc9c53f85867c50eab6 - original: lts-16.12 + size: 534126 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/16/31.yaml + sha256: 637fb77049b25560622a224845b7acfe81a09fdb6a96a3c75997a10b651667f6 + original: lts-16.31 diff --git a/playground/stack.yaml b/playground/stack.yaml index bba3065..10b523e 100644 --- a/playground/stack.yaml +++ b/playground/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-16.12 +resolver: lts-16.31 allow-newer: false diff --git a/stack-lts-16.yaml b/stack-lts-16.yaml new file mode 100644 index 0000000..bc0abd4 --- /dev/null +++ b/stack-lts-16.yaml @@ -0,0 +1,13 @@ +resolver: lts-16.31 + +allow-newer: false + +packages: +- . + +extra-deps: +- earcut-0.1.0.4 +- reanimate-svg-0.13.0.1 +- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 +- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 +- vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/stack.yaml b/stack.yaml index bc0abd4..641c3ff 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-16.31 +resolver: lts-17.04 allow-newer: false From df8e63e9b680bdba452fc978508eb98c1042526d Mon Sep 17 00:00:00 2001 From: Nick Bathum Date: Sat, 6 Mar 2021 09:34:20 -0500 Subject: [PATCH 046/114] Typo: text is left-aligned. --- docs/tut_equation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tut_equation.md b/docs/tut_equation.md index dcfd215..f294211 100644 --- a/docs/tut_equation.md +++ b/docs/tut_equation.md @@ -363,7 +363,7 @@ API references: [oScaleIn](https://hackage.haskell.org/package/reanimate/docs/Reanimate-Scene.html#v:oScaleIn), [oGrow](https://hackage.haskell.org/package/reanimate/docs/Reanimate-Scene.html#v:oGrow). -Let's use the `oDraw` function to draw text on the screen and let's make sure the text is right-aligned: +Let's use the `oDraw` function to draw text on the screen and let's make sure the text is left-aligned:
 animation :: Animation
@@ -521,4 +521,4 @@ env = addStatic (mkBackground "lightblue") .
       delay += 0;
     }
   },0);
-
\ No newline at end of file
+

From 8f36b657b967edaa68b15ae80cd388f5091cdcdc Mon Sep 17 00:00:00 2001
From: David Himmelstrup 
Date: Thu, 11 Mar 2021 16:18:54 +0800
Subject: [PATCH 047/114] Update getting-started section of docs.

---
 docs/index.md | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/docs/index.md b/docs/index.md
index 9b608ba..2e3a395 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -7,7 +7,20 @@
 
 # Getting started
 
-## Viewing a basic animation
+Reanimate offers stack templates for getting started with a minimal example and
+automatic code reloading. Running the commands below will put a one-line animation
+in the 'animate' folder and then display the animation in a browser window. You can
+then edit the animation source code and watch the animation update in real time:
+
+```console
+$ stack new animate github:reanimate/plain
+$ cd animate/
+$ # both 'cabal repl' and 'stack repl' can be used here:
+$ cabal repl
+:cmd reanimateLive
+```
+
+## Running examples from the repository
 
 ```console
 $ git clone https://github.com/reanimate/reanimate.git

From 5cc9de1acb088e5459793f06c8a95a56a1dcbe45 Mon Sep 17 00:00:00 2001
From: David Himmelstrup 
Date: Thu, 11 Mar 2021 16:21:33 +0800
Subject: [PATCH 048/114] Update ChangeLog.md

---
 ChangeLog.md | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/ChangeLog.md b/ChangeLog.md
index 8d38c58..e25c6ea 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and the
 project adheres to the [Haskell Package Versioning
 Policy (PVP)](https://pvp.haskell.org)
 
+## 1.1.4.0 -- 2021-03-11
+
+ * Fix build issue on M1 MacOS.
+ * Improve documentation.
+ * Fix bug in 'reanimateLiveEntry'.
+ * Simplify 'mkRect' definition.
+
 ## 1.1.3.2 -- 2021-01-14
 
  * Add flag for disabling the HGeometry dependency.

From 5ea023980ff7f488934d40593cc5069f5fd038b0 Mon Sep 17 00:00:00 2001
From: David Himmelstrup 
Date: Thu, 11 Mar 2021 16:21:48 +0800
Subject: [PATCH 049/114] Bump version to 1.1.4.0

---
 reanimate.cabal | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/reanimate.cabal b/reanimate.cabal
index 2ba41cf..b46ac2b 100644
--- a/reanimate.cabal
+++ b/reanimate.cabal
@@ -3,7 +3,7 @@ cabal-version:       2.0
 --  see http://haskell.org/cabal/users-guide/
 
 name:                reanimate
-version:             1.1.3.2
+version:             1.1.4.0
 -- synopsis:
 -- description:
 license:             PublicDomain

From cc6a5993342e0a5e7c01ac3fa4d0f99dae16e018 Mon Sep 17 00:00:00 2001
From: David Himmelstrup 
Date: Sat, 3 Jul 2021 22:51:01 +0800
Subject: [PATCH 050/114] Support the rgeometry backend.

---
 playground/nginx.conf | 47 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/playground/nginx.conf b/playground/nginx.conf
index 9185c57..f553ff4 100644
--- a/playground/nginx.conf
+++ b/playground/nginx.conf
@@ -1,3 +1,7 @@
+upstream rgeometry {
+  server rgeometry-server:20162;
+}
+
 upstream wsbackend {
   server playground:10161;
 }
@@ -40,3 +44,46 @@ server {
     proxy_set_header Host $host;
   }
 }
+
+server {
+  include /etc/nginx/mime.types;
+
+  listen [::]:443 ssl http2;
+  listen 443 ssl http2;
+
+  server_name web.rgeometry.org;
+
+  # SSL code
+  ssl_certificate /etc/nginx/ssl/live/web.rgeometry.org/fullchain.pem;
+  ssl_certificate_key /etc/nginx/ssl/live/web.rgeometry.org/privkey.pem;
+
+  root /var/www/html;
+
+  location / {
+      index index.html;
+      autoindex on;
+      add_header Access-Control-Allow-Origin '*';
+      location ~* .(wasm|js|png)$ {
+        add_header Cache-Control "public, max-age=31536000, immutable";
+      }
+  }
+
+  location /wasm/ {
+    rewrite ^/wasm/(.*) /$1  break;
+    proxy_read_timeout 1h;
+    proxy_pass http://rgeometry;
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "Upgrade";
+    proxy_set_header Host $host;
+  }
+
+  location /fetch-gist/ {
+    #add_header Access-Control-Allow-Origin '*';
+    if ($request_method = OPTIONS) {
+      add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
+      return 204;
+    }
+    proxy_pass https://gist.githubusercontent.com/;
+  }
+}

From 67b875246ddefd7effa44fd53c472aa8813853a7 Mon Sep 17 00:00:00 2001
From: David Himmelstrup 
Date: Sun, 4 Jul 2021 00:25:17 +0800
Subject: [PATCH 051/114] Update documentation links.

---
 README.md                             | 4 ++--
 playground/viewer-elm/dist/index.html | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index c85e327..674d7eb 100644
--- a/README.md
+++ b/README.md
@@ -135,8 +135,8 @@ Now, still within the `nix-shell` you can run:
 # Documentation
 
  * API reference: https://hackage.haskell.org/package/reanimate/docs/Reanimate.html
- * Core concepts: https://reanimate.readthedocs.io/en/latest/introduction/
- * Design overview: https://reanimate.readthedocs.io/en/latest/glue_tut/
+ * Core concepts: https://reanimate.readthedocs.io/en/latest/introduction.html
+ * Design overview: https://reanimate.readthedocs.io/en/latest/glue_tut.html
  * N-Queens tutorial (somewhat dated, uses reanimate from October 2019): https://williamyaoh.com/posts/2020-05-31-reanimate-nqueens-tutorial.html
  * You can also ask questions in the discord channel: 
 
diff --git a/playground/viewer-elm/dist/index.html b/playground/viewer-elm/dist/index.html
index af56454..1b8bf73 100644
--- a/playground/viewer-elm/dist/index.html
+++ b/playground/viewer-elm/dist/index.html
@@ -114,7 +114,7 @@
             
             
Core Concepts
- + reanimate.rtfd.io/en/latest/introduction/
@@ -256,4 +256,4 @@ - \ No newline at end of file + From 8e2b32ba7aac569bc8339a83ce0c45ed9003c610 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sun, 4 Jul 2021 23:23:46 +0800 Subject: [PATCH 052/114] Fix doc references. --- docs/index.md | 4 ++-- docs/introduction.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/index.md b/docs/index.md index 2e3a395..9138acf 100644 --- a/docs/index.md +++ b/docs/index.md @@ -106,6 +106,6 @@ $ stack ./examples/doc_andThen.hs render --format gif # Learning resources * [API documentation](https://hackage.haskell.org/package/reanimate/docs/Reanimate.html) -* [Core concepts](introduction) +* [Core concepts](introduction.md) * [Examples](https://github.com/reanimate/reanimate/tree/master/examples) -* [Design overview](glue_tut) +* [Design overview](glue_tut.md) diff --git a/docs/introduction.md b/docs/introduction.md index f228cfd..29d1993 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -3,7 +3,7 @@ This document will introduce the foundamental concepts used in **reanimate**. It is assumed that you are already familiar with Haskell. After reading, you will be able to understand all the concepts used in the [API reference documentation](https://hackage.haskell.org/package/reanimate/docs/Reanimate.html). This is not a tutorial, though, and you may have to look at the examples before you can turn these concepts into beautiful animations. -For a bird's eye view on the design philosophy and capabilities of **reanimate**, see [Gluing together animations](/glue_tut/). For help installing **reanimate**, see [Getting started](/#getting-started). +For a bird's eye view on the design philosophy and capabilities of **reanimate**, see [Gluing together animations](glue_tut.md). For help installing **reanimate**, see [Getting started](/#getting-started). ## Animations as Executables From 1232618b159bd81ffb06894e751e60f53c2b6b9c Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Wed, 11 Aug 2021 11:04:02 +0800 Subject: [PATCH 053/114] Fix cert renewal for web.rgeometry.org --- playground/nginx.conf | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/playground/nginx.conf b/playground/nginx.conf index f553ff4..996597f 100644 --- a/playground/nginx.conf +++ b/playground/nginx.conf @@ -8,7 +8,7 @@ upstream wsbackend { server { listen 80; - server_name reanimate.clozecards.com; + server_name reanimate.clozecards.com _; location ~ /.well-known/acme-challenge { allow all; @@ -86,4 +86,10 @@ server { } proxy_pass https://gist.githubusercontent.com/; } + + location ~ /.well-known/acme-challenge { + allow all; + root /var/www/certbot; + } + } From 0f24e76adeaaa34dfbecfdfdfc79df6214bd9eee Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Sat, 11 Sep 2021 12:59:14 +0800 Subject: [PATCH 054/114] Upgrade to GitHub-native Dependabot (#204) Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- .github/dependabot.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..f13892a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +version: 2 +updates: +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily + time: "11:00" + open-pull-requests-limit: 10 +- package-ecosystem: elm + directory: "/viewer-elm" + schedule: + interval: daily + time: "11:00" + open-pull-requests-limit: 10 +- package-ecosystem: elm + directory: "/playground/viewer-elm" + schedule: + interval: daily + time: "11:00" + open-pull-requests-limit: 10 From df0f8e591b9b3d56173b59701288ea0f0f20ae0b Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sat, 11 Sep 2021 13:34:52 +0800 Subject: [PATCH 055/114] Disable building against stackage nightly. (#216) * Disable nightly build because github no longer accepts comments from forks. * Disable azure nightly builds. * Use stack-18 by default. --- .azure/azure-linux-template.yml | 6 +++--- .../{workflows => disabled-workflows}/stackage-nightly.yml | 0 stack.yaml | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) rename .github/{workflows => disabled-workflows}/stackage-nightly.yml (100%) diff --git a/.azure/azure-linux-template.yml b/.azure/azure-linux-template.yml index 76a9748..554a6f3 100644 --- a/.azure/azure-linux-template.yml +++ b/.azure/azure-linux-template.yml @@ -17,9 +17,9 @@ jobs: stack-lts-14: BUILD: stack STACK_YAML: stack-lts-14.yaml - stack-nightly: - BUILD: stack - ARGS: --resolver nightly --no-run-tests + #stack-nightly: + # BUILD: stack + # ARGS: --resolver nightly --no-run-tests maxParallel: 6 steps: - task: Cache@2 diff --git a/.github/workflows/stackage-nightly.yml b/.github/disabled-workflows/stackage-nightly.yml similarity index 100% rename from .github/workflows/stackage-nightly.yml rename to .github/disabled-workflows/stackage-nightly.yml diff --git a/stack.yaml b/stack.yaml index 641c3ff..0e67af5 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,4 +1,4 @@ -resolver: lts-17.04 +resolver: lts-18.9 allow-newer: false @@ -10,4 +10,3 @@ extra-deps: - reanimate-svg-0.13.0.1 - hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 - hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 -- vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 From a7e875178423508a9865198b69a410c17058ffca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Sep 2021 16:40:48 +0800 Subject: [PATCH 056/114] Bump actions/setup-node from 1 to 2.4.0 (#219) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 1 to 2.4.0. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v1...v2.4.0) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/site-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/site-checks.yml b/.github/workflows/site-checks.yml index 0f1e781..d15114d 100644 --- a/.github/workflows/site-checks.yml +++ b/.github/workflows/site-checks.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Use Node.js 10.x - uses: actions/setup-node@v1 + uses: actions/setup-node@v2.4.0 with: node-version: 10.x - name: Install dependencies From ae14f3b09f884c16f4a0f9b55c283696234ba899 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Sep 2021 16:41:00 +0800 Subject: [PATCH 057/114] Bump jorelali/setup-elm from 2 to 3 (#218) Bumps [jorelali/setup-elm](https://github.com/jorelali/setup-elm) from 2 to 3. - [Release notes](https://github.com/jorelali/setup-elm/releases) - [Commits](https://github.com/jorelali/setup-elm/compare/v2...v3) --- updated-dependencies: - dependency-name: jorelali/setup-elm dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/playground.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index a3414d3..041829f 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -14,7 +14,7 @@ jobs: with: ghc-version: '8.8' cabal-version: 'latest' - - uses: jorelali/setup-elm@v2 + - uses: jorelali/setup-elm@v3 with: elm-version: 0.19.1 diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index ed794c2..359e696 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -15,7 +15,7 @@ jobs: with: ghc-version: '8.8' cabal-version: 'latest' - - uses: jorelali/setup-elm@v2 + - uses: jorelali/setup-elm@v3 with: elm-version: 0.19.1 From 2118e055586c120ae1874572191a4e06205928dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Sep 2021 16:41:24 +0800 Subject: [PATCH 058/114] Bump JamesIves/github-pages-deploy-action from 3.7.1 to 4.1.5 (#217) Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 3.7.1 to 4.1.5. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/3.7.1...4.1.5) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 041829f..e9916be 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -101,7 +101,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@3.7.1 + uses: JamesIves/github-pages-deploy-action@4.1.5 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From f3e5abf4167681ab6b968795229aa19af9018c0e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Sep 2021 16:41:50 +0800 Subject: [PATCH 059/114] Bump tar from 4.4.13 to 4.4.19 in /viewer-elm (#214) Bumps [tar](https://github.com/npm/node-tar) from 4.4.13 to 4.4.19. - [Release notes](https://github.com/npm/node-tar/releases) - [Changelog](https://github.com/npm/node-tar/blob/main/CHANGELOG.md) - [Commits](https://github.com/npm/node-tar/compare/v4.4.13...v4.4.19) --- updated-dependencies: - dependency-name: tar dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- viewer-elm/package-lock.json | 47 ++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index 0b8b51d..8c95c92 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -178,12 +178,6 @@ "readdirp": "^3.1.1" } }, - "chownr": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", - "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1169,20 +1163,41 @@ "dev": true }, "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz", + "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==", "dev": true, "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" }, "dependencies": { + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", From 3aa746f6d42b60d04321099431303ece68f6d4e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Sep 2021 16:42:01 +0800 Subject: [PATCH 060/114] Bump glob-parent from 5.1.0 to 5.1.2 in /viewer-elm (#207) Bumps [glob-parent](https://github.com/gulpjs/glob-parent) from 5.1.0 to 5.1.2. - [Release notes](https://github.com/gulpjs/glob-parent/releases) - [Changelog](https://github.com/gulpjs/glob-parent/blob/main/CHANGELOG.md) - [Commits](https://github.com/gulpjs/glob-parent/compare/v5.1.0...v5.1.2) --- updated-dependencies: - dependency-name: glob-parent dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- viewer-elm/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index 8c95c92..8334d6f 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -532,9 +532,9 @@ } }, "glob-parent": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", - "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" From 5c0eb70584d4ce13c65ec870e0ea165d421f2522 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Sep 2021 16:42:12 +0800 Subject: [PATCH 061/114] Bump lodash from 4.17.15 to 4.17.21 in /viewer-elm (#206) Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.21. - [Release notes](https://github.com/lodash/lodash/releases) - [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.21) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- viewer-elm/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index 8334d6f..db9500b 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -721,9 +721,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "lru-cache": { From aadf8dcee55e43ae7c12a76ba1fbf907784526f6 Mon Sep 17 00:00:00 2001 From: Drew Fenwick Date: Sat, 11 Sep 2021 10:43:41 +0100 Subject: [PATCH 062/114] Improve cabal hacking experience (#215) * Add standard haskell gitignore entries * Add cradles for using HLS with Cabal Co-authored-by: David Himmelstrup --- .gitignore | 24 +++++++++++++++++++++++- hie.yaml | 15 ++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 8ee1bf9..db30022 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,23 @@ -.stack-work +dist +dist-* +cabal-dev +*.o +*.hi +*.hie +*.chi +*.chs.h +*.dyn_o +*.dyn_hi +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +*.prof +*.aux +*.hp +*.eventlog +.stack-work/ +cabal.project.local +cabal.project.local~ +.HTF/ +.ghc.environment.* \ No newline at end of file diff --git a/hie.yaml b/hie.yaml index c9b9cbf..de54401 100644 --- a/hie.yaml +++ b/hie.yaml @@ -1,11 +1,20 @@ cradle: multi: - path: "./src" - config: {cradle: {stack: {component: "reanimate:lib"}} } + config: + cradle: + stack: {component: "reanimate:lib"} + cabal: {component: "lib:reanimate"} - path: "./videos" - config: {cradle: {stack: {component: "reanimate:lib"}} } + config: + cradle: + stack: {component: "reanimate:lib"} + cabal: {component: "lib:reanimate"} - path: "./examples" - config: {cradle: {stack: {component: "reanimate:lib"}} } + config: + cradle: + stack: {component: "reanimate:lib"} + cabal: {component: "lib:reanimate"} - path: "./test" config: {cradle: {none: }} - path: "./discord-bot" From b36fdb1e1bfbaec1c90f233f3aa20452a9865c69 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Fri, 8 Oct 2021 21:55:50 +0100 Subject: [PATCH 063/114] Update for updated inkscape command line options The current version of inkscape is 1.1.1. Its command line changed at some point and no longer includes `--without-gui`, `--file` or `--export-png`. See https://inkscape.org/doc/inkscape-man.html. What was once: ~~~ inkscape --without-gui --file=test.svg --export-png=test.png ~~~ is now: ~~~ inkscape --export-type=png test.svg ~~~ --- src/Reanimate/Driver/Check.hs | 2 +- src/Reanimate/Render.hs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Reanimate/Driver/Check.hs b/src/Reanimate/Driver/Check.hs index ee19e8a..33a2d61 100644 --- a/src/Reanimate/Driver/Check.hs +++ b/src/Reanimate/Driver/Check.hs @@ -120,7 +120,7 @@ hasRSvg = checkMinVersion minVersion <$> rsvgVersion hasInkscape :: IO (Either String String) hasInkscape = checkMinVersion minVersion <$> inkscapeVersion where - minVersion = Version [0,92] [] + minVersion = Version [1,0] [] hasMagick :: IO (Either String String) hasMagick = checkMinVersion minVersion <$> magickVersion diff --git a/src/Reanimate/Render.hs b/src/Reanimate/Render.hs index ce62cd9..9dfa2c7 100644 --- a/src/Reanimate/Render.hs +++ b/src/Reanimate/Render.hs @@ -413,9 +413,8 @@ applyRaster RasterNone _ = return () applyRaster RasterAuto _ = return () applyRaster RasterInkscape path = runCmd "inkscape" - [ "--without-gui" - , "--file=" ++ path - , "--export-png=" ++ replaceExtension path "png" + ["--export-type=png" + , path ] applyRaster RasterRSvg path = runCmd "rsvg-convert" From a0780c67fcb49edadf74c346fa9891f43a059b03 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Wed, 13 Oct 2021 14:31:23 +0800 Subject: [PATCH 064/114] Limit aeson version to <2. --- reanimate.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reanimate.cabal b/reanimate.cabal index b46ac2b..79eabfe 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -121,7 +121,7 @@ library build-depends: base >=4.10 && <5, JuicyPixels >=3.3.3, - aeson >=1.3.0.0, + aeson >=1.3.0.0 && <2, ansi-terminal >=0.8.0.4, array >=0.5.2.0, attoparsec >=0.13.2.0, From ff162b6a33dd44218c2f87f588844537065cf2cc Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Wed, 13 Oct 2021 10:16:47 +0100 Subject: [PATCH 065/114] Add `withStrokeOpacity` (#222) Currently, `withFillOpacity` is provided but not the stroke equivalent. Co-authored-by: David Himmelstrup --- src/Reanimate/Svg/Constructors.hs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Reanimate/Svg/Constructors.hs b/src/Reanimate/Svg/Constructors.hs index 23e0386..58c20e9 100644 --- a/src/Reanimate/Svg/Constructors.hs +++ b/src/Reanimate/Svg/Constructors.hs @@ -20,6 +20,7 @@ module Reanimate.Svg.Constructors , withId , withStrokeColor , withStrokeColorPixel + , withStrokeOpacity , withStrokeDashArray , withStrokeLineJoin , withFillColor @@ -209,6 +210,10 @@ withStrokeColor color = strokeColor .~ pure (mkColor color) withStrokeColorPixel :: PixelRGBA8 -> Tree -> Tree withStrokeColorPixel color = strokeColor .~ pure (ColorRef color) +-- | See +withStrokeOpacity :: Double -> Tree -> Tree +withStrokeOpacity opacity = strokeOpacity ?~ realToFrac opacity + -- | See withStrokeDashArray :: [Double] -> Tree -> Tree withStrokeDashArray arr = strokeDashArray .~ pure (map Num arr) From 82abb4e434a1a5b5040296278c733efc441670d6 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Wed, 13 Oct 2021 20:03:09 +0100 Subject: [PATCH 066/114] Add `mkColor "none" = FillNone` to `mkColor` Extending `mkColor :: String -> Texture` to yield `FillNone` for "none" would allow (for example) `withFillColor "none"` to 'turn color off'. For some users, that may be more intuitive and expressive than `withFillOpacity 0.0`. The Haddock documentation is updated, accordingly. --- src/Reanimate/Svg/Constructors.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Reanimate/Svg/Constructors.hs b/src/Reanimate/Svg/Constructors.hs index 58c20e9..1246ffb 100644 --- a/src/Reanimate/Svg/Constructors.hs +++ b/src/Reanimate/Svg/Constructors.hs @@ -193,10 +193,12 @@ centerUsing a = translate (-x-w/2) (-y-h/2) where (x, y, w, h) = boundingBox a --- | Create 'Texture' based on SVG color name. --- See for the list of available names. --- If the provided name doesn't correspond to valid SVG color name, white-ish color is used. +-- | Create 'Texture' based on a SVG color name or @\"none\"@. If the provided +-- 'String' is not a valid value, a white-ish color is used. +-- See for the list +-- of available color names. mkColor :: String -> Texture +mkColor "none" = FillNone mkColor name = case Map.lookup (T.pack name) svgNamedColors of Nothing -> ColorRef (PixelRGBA8 240 248 255 255) From ceb727e8da5185635095c80e03f0b977bc4cf199 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sat, 16 Oct 2021 09:20:34 +0100 Subject: [PATCH 067/114] Enable use of POV-Ray for Windows (#225) This pull request reflects code changes made to be able to use POV-Ray for Windows, Version 3.7.0.msvc10.win64. The changes have been tested on Windows 10 but not on unix-like operating systems. However, I don't think the code for unix-like operating systems has been affected. The reason for the changes is explained below. 1. The POV-Ray for Windows executable is named `pvengine64.exe` on 64-bit Windows, not `povray I've created two modules `POVRay`, specified separately for `windows` and `unix`, that export `povrayApp :: String`, yielding the correct name of the executable. The function is used in place of `"povray"` (eg in `Reanimate.Driver.Check.hasPovray`). 2. Generated file names containing `$` cause problems under PowerShell, due to automatic variables, and file names on Windows are not case sensitive I've changed the 64-character `alphabet` in `Reanimate.Cache.encodeInt` for a 32-character one which includes only capital letters and digits. This affects both Windows and unix-like operating systems. (An alternative would be versions of `encodeInt` specified differently for `windows` and `unix`.) 3. POV-Ray for Windows requires the special command line option `/EXIT` to return I've moved `Reanimate.Povray.mkPovrayImage'` to the two modules `POVRay`. In the `windows` version, `/EXIT` is now added to the list of switches passed to the POV-Ray executable. 4. POV-Ray for Windows cannot parse switches enclosed in `""` as switches The cause of the problem is described in more detail in the comments in the source code of module `POVRay`. As a work around, in the `windows` version of `mkPovrayImage'`, the POV-Ray command is written to a temporary batch file and it is that batch file which is passed to `runCmd`. Other matters In addition to the above, POV-Ray 3.7 includes 'Script I\O Restrictions` which can prevent the writing of files. These need to be disabled in the POV-Ray for Windows GUI (under the Options menu). --- reanimate.cabal | 1 + src/Reanimate/Cache.hs | 6 ++-- src/Reanimate/Driver/Check.hs | 3 +- src/Reanimate/Povray.hs | 18 +--------- unix/POVRay.hs | 27 ++++++++++++++ windows/POVRay.hs | 66 +++++++++++++++++++++++++++++++++++ 6 files changed, 100 insertions(+), 21 deletions(-) create mode 100644 unix/POVRay.hs create mode 100644 windows/POVRay.hs diff --git a/reanimate.cabal b/reanimate.cabal index 79eabfe..d1ff354 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -111,6 +111,7 @@ library Reanimate.Scene.Sprite Reanimate.Scene.Object Detach + POVRay autogen-modules: Paths_reanimate if flag(no-hgeometry) cpp-options: -DNO_HGEOMETRY diff --git a/src/Reanimate/Cache.hs b/src/Reanimate/Cache.hs index e39800e..0144ce6 100644 --- a/src/Reanimate/Cache.hs +++ b/src/Reanimate/Cache.hs @@ -104,6 +104,6 @@ encodeInt i = worker (fromIntegral i) 60 worker key sh | sh < 0 = [] | otherwise = - case (key `shiftR` sh) `mod` 64 of - idx -> alphabet !! fromIntegral idx : worker key (sh-6) - alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+$" + case (key `shiftR` sh) `mod` 32 of + idx -> alphabet !! fromIntegral idx : worker key (sh-5) + alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789" diff --git a/src/Reanimate/Driver/Check.hs b/src/Reanimate/Driver/Check.hs index 33a2d61..66ae5c4 100644 --- a/src/Reanimate/Driver/Check.hs +++ b/src/Reanimate/Driver/Check.hs @@ -11,6 +11,7 @@ import Control.Exception (SomeException, handle) import Control.Monad (forM_) import Data.Maybe (fromMaybe, listToMaybe) import Data.Version (Version (Version), parseVersion, showVersion) +import POVRay (povrayApp) import Reanimate.Driver.Magick (magickCmd) import Reanimate.Misc (runCmd_) import System.Console.ANSI.Codes @@ -88,7 +89,7 @@ hasDvisvgm :: IO (Either String String) hasDvisvgm = hasProgram "dvisvgm" hasPovray :: IO (Either String String) -hasPovray = hasProgram "povray" +hasPovray = hasProgram povrayApp hasFFmpeg :: IO (Either String String) hasFFmpeg = checkMinVersion minVersion <$> ffmpegVersion diff --git a/src/Reanimate/Povray.hs b/src/Reanimate/Povray.hs index 14b76eb..76cbb46 100644 --- a/src/Reanimate/Povray.hs +++ b/src/Reanimate/Povray.hs @@ -14,18 +14,13 @@ module Reanimate.Povray , povrayExtreme' ) where -import Data.Hashable (Hashable (hash)) import Data.Text (Text) -import qualified Data.Text as T -import qualified Data.Text.IO as T import Graphics.SvgTree (Tree) -import Reanimate.Cache (cacheFile, encodeInt) +import POVRay (mkPovrayImage') import Reanimate.Constants (screenHeight, screenWidth) -import Reanimate.Misc (requireExecutable, runCmd) import Reanimate.Parameters (pNoExternals) import Reanimate.Raster (mkImage) import Reanimate.Svg.Constructors (mkText) -import System.FilePath (replaceExtension, (<.>)) import System.IO.Unsafe (unsafePerformIO) povrayRaw :: [String] -> Text -> Tree @@ -88,14 +83,3 @@ mkPovrayImage :: [String] -> Text -> IO Tree mkPovrayImage _ script | pNoExternals = pure $ mkText script mkPovrayImage args script = mkImage screenWidth screenHeight <$> mkPovrayImage' args script - -mkPovrayImage' :: [String] -> Text -> IO FilePath -mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" -mkPovrayImage' args script = cacheFile template $ \target -> do - exec <- requireExecutable "povray" - let pov_file = replaceExtension target "pov" - T.writeFile pov_file script - runCmd exec (args ++ ["-D","+UA", pov_file, "+o"++target]) - where - template = encodeInt (hash key) <.> "png" - key = T.concat (script:map T.pack args) diff --git a/unix/POVRay.hs b/unix/POVRay.hs new file mode 100644 index 0000000..ae6d1e8 --- /dev/null +++ b/unix/POVRay.hs @@ -0,0 +1,27 @@ +module POVRay + ( povrayApp + , mkPovrayImage' + ) where + +import Data.Hashable (Hashable (hash)) +import Data.Text (Text) +import qualified Data.Text as T (concat, pack) +import qualified Data.Text.IO as T (writeFile) +import Reanimate.Cache (cacheFile, encodeInt) +import Reanimate.Misc (requireExecutable, runCmd) +import Reanimate.Parameters (pNoExternals) +import System.FilePath (replaceExtension, (<.>)) + +povrayApp :: String +povrayApp = "povray" + +mkPovrayImage' :: [String] -> Text -> IO FilePath +mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" +mkPovrayImage' args script = cacheFile template $ \target -> do + exec <- requireExecutable povrayApp + let pov_file = replaceExtension target "pov" + T.writeFile pov_file script + runCmd exec (args ++ ["-D", "+UA", "+I" ++ pov_file, "+o" ++ target]) + where + template = encodeInt (hash key) <.> "png" + key = T.concat (script:map T.pack args) diff --git a/windows/POVRay.hs b/windows/POVRay.hs new file mode 100644 index 0000000..1262a42 --- /dev/null +++ b/windows/POVRay.hs @@ -0,0 +1,66 @@ +module POVRay + ( povrayApp + , mkPovrayImage' + ) where + +import Data.Hashable (Hashable (hash)) +import Data.Text (Text) +import qualified Data.Text as T (concat, pack) +import qualified Data.Text.IO as T (writeFile) +import Reanimate.Cache (cacheFile, encodeInt) +import Reanimate.Misc (requireExecutable, runCmd) +import Reanimate.Parameters (pNoExternals) +import System.FilePath (replaceExtension, (<.>)) +import System.IO (hClose, hPutStrLn) +import System.IO.Temp (withSystemTempFile) + +povrayApp :: String +povrayApp = "pvengine64" -- Assumes 64 bit Windows + +mkPovrayImage' :: [String] -> Text -> IO FilePath +mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" +mkPovrayImage' args script = cacheFile template $ \target -> do + exec <- requireExecutable povrayApp + let pov_file = replaceExtension target "pov" + exec' = '"' : exec ++ "\"" -- Wrap exec in "" because the path is likely + -- to includes spaces + otherArgs = [ "-D" + , "+UA" + , "+I" ++ pov_file + , "+O" ++ target + , "/EXIT" -- Note [/EXIT special command-line option] + ] + command = concatMap (' ':) (exec' : args ++ otherArgs) + T.writeFile pov_file script + -- Note [Use of a batch file] + withSystemTempFile "pvcommand.bat" $ \path h -> do + hPutStrLn h command + hClose h + runCmd path [] + where + template = encodeInt (hash key) <.> "png" + key = T.concat (script:map T.pack args) + +{- +Note [/EXIT special command-line option] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +"The /EXIT command tells POV-Ray to perform the render given by the other +command-line options, combined with previously-set options such as internal +command-line settings, INI file, source file, and so forth, and then to exit. By +default, if this switch is not present, POV-Ray for Windows will remain running +after the render is complete. This switch only applies to renders started by +other options on the command-line. It will not affect renders started manually +from within POV-Ray for Windows itself." +source: https://www.povray.org/documentation/view/3.6.1/603/ + +Note [Use of batch file] +~~~~~~~~~~~~~~~~~~~~~~~~ + +POV-Ray for Windows assumes that anything on the command-line that is not a +switch is the name of an INI file. Switches are preceded by a plus or minus. +However, System.Process.createProcess_ wraps all arguments in "". POV_Ray for +Windows appears to interpret a switch wrapped in "" as the name of an INI file. + +The work around used here is to write the POV-Ray command line to a batch file. +-} From d1096abb633ea293b777609138fd3a7f4438a101 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sat, 16 Oct 2021 18:56:58 +0100 Subject: [PATCH 068/114] Refactor `Reanimate.Povray` and OS-specifc `POVRay` Further to pull request #225, I realised subsequently that the common code in the two `POVRay.mkPovrayImage'` functions could be returned to module `Reanimate.Povray`, and all that needed to be Windows- or Unix-like-specific was a `runPOVRay` function. This pull request does that refactoring. --- src/Reanimate/Povray.hs | 20 +++++++++++++++++++- unix/POVRay.hs | 25 +++++++------------------ windows/POVRay.hs | 32 ++++++++------------------------ 3 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/Reanimate/Povray.hs b/src/Reanimate/Povray.hs index 76cbb46..ba98f8c 100644 --- a/src/Reanimate/Povray.hs +++ b/src/Reanimate/Povray.hs @@ -14,15 +14,22 @@ module Reanimate.Povray , povrayExtreme' ) where +import Data.Hashable (Hashable (hash)) import Data.Text (Text) +import qualified Data.Text as T (concat, pack) +import qualified Data.Text.IO as T (writeFile) import Graphics.SvgTree (Tree) -import POVRay (mkPovrayImage') +import POVRay (runPOVRay) +import Reanimate.Cache (cacheFile, encodeInt) import Reanimate.Constants (screenHeight, screenWidth) import Reanimate.Parameters (pNoExternals) import Reanimate.Raster (mkImage) import Reanimate.Svg.Constructors (mkText) +import System.FilePath (replaceExtension, (<.>)) import System.IO.Unsafe (unsafePerformIO) + + povrayRaw :: [String] -> Text -> Tree povrayRaw args script = unsafePerformIO $ mkPovrayImage args script @@ -83,3 +90,14 @@ mkPovrayImage :: [String] -> Text -> IO Tree mkPovrayImage _ script | pNoExternals = pure $ mkText script mkPovrayImage args script = mkImage screenWidth screenHeight <$> mkPovrayImage' args script + +mkPovrayImage' :: [String] -> Text -> IO FilePath +mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" +mkPovrayImage' args script = cacheFile template $ \target -> do + let pov_file = replaceExtension target "pov" + otherArgs = ["-D", "+UA", "+I" ++ pov_file, "+O" ++ target] + T.writeFile pov_file script + runPOVRay $ args ++ otherArgs + where + template = encodeInt (hash key) <.> "png" + key = T.concat (script:map T.pack args) diff --git a/unix/POVRay.hs b/unix/POVRay.hs index ae6d1e8..c72e545 100644 --- a/unix/POVRay.hs +++ b/unix/POVRay.hs @@ -1,27 +1,16 @@ module POVRay ( povrayApp - , mkPovrayImage' + , runPOVRay ) where -import Data.Hashable (Hashable (hash)) -import Data.Text (Text) -import qualified Data.Text as T (concat, pack) -import qualified Data.Text.IO as T (writeFile) -import Reanimate.Cache (cacheFile, encodeInt) -import Reanimate.Misc (requireExecutable, runCmd) -import Reanimate.Parameters (pNoExternals) -import System.FilePath (replaceExtension, (<.>)) +import Reanimate.Misc (requireExecutable, runCmd) +-- | Name of the POV-Ray executable povrayApp :: String povrayApp = "povray" -mkPovrayImage' :: [String] -> Text -> IO FilePath -mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" -mkPovrayImage' args script = cacheFile template $ \target -> do +-- | Run the POV-Ray executable with arguments +runPOVRay :: [String] -> IO () +runPOVRay args = do exec <- requireExecutable povrayApp - let pov_file = replaceExtension target "pov" - T.writeFile pov_file script - runCmd exec (args ++ ["-D", "+UA", "+I" ++ pov_file, "+o" ++ target]) - where - template = encodeInt (hash key) <.> "png" - key = T.concat (script:map T.pack args) + runCmd exec args diff --git a/windows/POVRay.hs b/windows/POVRay.hs index 1262a42..f2fa004 100644 --- a/windows/POVRay.hs +++ b/windows/POVRay.hs @@ -1,45 +1,29 @@ module POVRay ( povrayApp - , mkPovrayImage' + , runPOVRay ) where -import Data.Hashable (Hashable (hash)) -import Data.Text (Text) -import qualified Data.Text as T (concat, pack) -import qualified Data.Text.IO as T (writeFile) -import Reanimate.Cache (cacheFile, encodeInt) import Reanimate.Misc (requireExecutable, runCmd) -import Reanimate.Parameters (pNoExternals) -import System.FilePath (replaceExtension, (<.>)) import System.IO (hClose, hPutStrLn) import System.IO.Temp (withSystemTempFile) +-- | Name of the POV-Ray executable povrayApp :: String povrayApp = "pvengine64" -- Assumes 64 bit Windows -mkPovrayImage' :: [String] -> Text -> IO FilePath -mkPovrayImage' _ _ | pNoExternals = pure "/povray/has/been/disabled" -mkPovrayImage' args script = cacheFile template $ \target -> do +-- | Run the POV-Ray executable with arguments +runPOVRay :: [String] -> IO () +runPOVRay args = do exec <- requireExecutable povrayApp - let pov_file = replaceExtension target "pov" - exec' = '"' : exec ++ "\"" -- Wrap exec in "" because the path is likely + let exec' = '"' : exec ++ "\"" -- Wrap exec in "" because the path is likely -- to includes spaces - otherArgs = [ "-D" - , "+UA" - , "+I" ++ pov_file - , "+O" ++ target - , "/EXIT" -- Note [/EXIT special command-line option] - ] - command = concatMap (' ':) (exec' : args ++ otherArgs) - T.writeFile pov_file script + args' = "/EXIT" : args -- Note [/EXIT special command-line option] + command = concatMap (' ':) (exec' : args') -- Note [Use of a batch file] withSystemTempFile "pvcommand.bat" $ \path h -> do hPutStrLn h command hClose h runCmd path [] - where - template = encodeInt (hash key) <.> "png" - key = T.concat (script:map T.pack args) {- Note [/EXIT special command-line option] From f53332f93bfc6e2b6923ca31f77e41dead8dd1f1 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sat, 16 Oct 2021 19:50:19 +0100 Subject: [PATCH 069/114] Add documentation on obtaining dependencies on Windows This pull request proposes an additional subsection in the documentation explaining to Windows users how they can obtain the FFmpeg, dvisvgm, POV-Ray, Blender, rsvg-convert, Inkscape, ImageMagick and LaTeX/XeLaTex dependencies. --- docs/index.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/index.md b/docs/index.md index 9138acf..4fdd2c7 100644 --- a/docs/index.md +++ b/docs/index.md @@ -72,6 +72,38 @@ be able to generate stand-alone video files (but can still view animations in a browser window). Without 'LaTeX' and 'dvisvgm', you won't be able use LaTeX for typesetting. +### Obtaining the dependencies on Windows + +The easiest way to obtain the [FFmpeg](https://www.ffmpeg.org/), +[rsvg-convert](https://wiki.gnome.org/Projects/LibRsvg) and +[ImageMagick](https://imagemagick.org/index.php) dependencies on Windows is to +use the [MSYS2](https://www.msys2.org/) installation that comes with `stack` and +is on the path in the `stack exec` environment, and its package manager +`pacman`. The MSYS2 `librsvg` package provides `rsvg-convert.exe`. + +``` +> stack exec -- pacman --sync --refresh +> stack exec -- pacman --sync mingw64/mingw-w64-x86_64-ffmpeg +> stack exec -- pacman --sync mingw64/mingw-w64-x86_64-librsvg +> stack exec -- pacman --sync mingw64/mingw-w64-x86_64-imagemagick +``` + +However, readily-available versions of FFmpeg on Windows have not been built +with the `--enable-librsvg` option. So, the `Has ffmpeg(rsvg)` dependency will +be `no` on Windows. + +Windows versions of [POV-Ray](http://www.povray.org/), +[Inkscape](https://inkscape.org/), and [Blender](https://www.blender.org/) can +be downloaded and installed and the folders containing the executables added to +the `PATH` environment variable. + +The [MiKTeX project](https://miktex.org/) provides a modern TeX distribution for +Windows, which also includes the [`dvisvgm` tool](https://dvisvgm.de/). The +folder containing the executables must be added to the `PATH` environment +variable. The `ctex` package (for Chinese typesetting) requires the `SimHei` +font, which is provided by the Windows Language Pack for Chinese (Simplified, +China). + ## Rendering animations **reanimate** has builtin support for rendering animations to video files and From a9b9728f0fe53e164878daf9822288ef9106a203 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sat, 16 Oct 2021 20:29:09 +0100 Subject: [PATCH 070/114] Update POV-Ray examples to avoid POV-Ray warnings This pull request updates the POV scripts in the two POV-Ray examples to avoid the warning messages in POV-Ray 3.7 (released November 2013). POV-Ray 3.7 requires the `version` directive. POV-Ray 3.7 considers the `assumed_gamma` keyword to be mandatory. POV-Ray warns when a `polygon` is not closed. POV-Ray warns when a scaling component is omitted. --- examples/tut_glue_povray.hs | 10 +++++++--- examples/tut_glue_povray_ortho.hs | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/examples/tut_glue_povray.hs b/examples/tut_glue_povray.hs index 6dc5ae6..edbc29d 100755 --- a/examples/tut_glue_povray.hs +++ b/examples/tut_glue_povray.hs @@ -53,6 +53,8 @@ script png transZ rotX rotZ = transZ_ = T.pack $ show transZ rotZ_ = T.pack $ show rotZ in [text| +#version 3.7; +//Files with predefined colors and textures #include "colors.inc" //Place the camera @@ -64,6 +66,8 @@ camera { right x*16/9 } +global_settings { assumed_gamma 1.0 } + //Ambient light to "brighten up" darker pictures global_settings { ambient_light White*3 } @@ -71,15 +75,15 @@ global_settings { ambient_light White*3 } background { color rgbt <0, 0, 0, 1> } // transparent polygon { - 4, - <0, 0>, <0, 1>, <1, 1>, <1, 0> + 5, + <0, 0>, <0, 1>, <1, 1>, <1, 0>, <0, 0> texture { pigment{ image_map{ png "${png_}" } } } translate <-1/2,-1/2> - scale <16,9> + scale <16,9,1> rotate <0,${rotX_},${rotZ_}> translate <0,0,${transZ_}> } diff --git a/examples/tut_glue_povray_ortho.hs b/examples/tut_glue_povray_ortho.hs index 2753195..b6c69c0 100755 --- a/examples/tut_glue_povray_ortho.hs +++ b/examples/tut_glue_povray_ortho.hs @@ -60,6 +60,7 @@ script png rotX rotY rotZ = rotY_ = T.pack $ show rotY rotZ_ = T.pack $ show rotZ in [text| +# version 3.7; //Files with predefined colors and textures #include "colors.inc" @@ -74,6 +75,7 @@ camera { right x*16 } +global_settings { assumed_gamma 1.0 } //Ambient light to "brighten up" darker pictures global_settings { ambient_light White*3 } From cb733df81d555842295331dadf80e9bb1771b424 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sat, 16 Oct 2021 22:10:02 +0100 Subject: [PATCH 071/114] Correct and extend `Reanimate.Povray' Haddock documentation This pull request corrects the Haddock documentation for `Reanimate.Povray' (incorrect narrative for some functions yielding `Tree' and inconsistent width x height dimensions). It also extends the introductory Haddock documenation to describe the structure of the functions exported and the use of their arguments, common to all the functions. --- src/Reanimate/Povray.hs | 62 ++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/src/Reanimate/Povray.hs b/src/Reanimate/Povray.hs index ba98f8c..954d42b 100644 --- a/src/Reanimate/Povray.hs +++ b/src/Reanimate/Povray.hs @@ -1,7 +1,25 @@ {-# LANGUAGE OverloadedStrings #-} {-| - [Povray](http://povray.org/) is a scriptable raytracer. All povray functions - are cached and will reuse images when scripts stay the same. + [POV-Ray](http://povray.org/) (the Persistance of Vision Raytracer) is a + scriptable raytracer. All POV-Ray functions are cached and will reuse images + when scripts stay the same. + + The functions come in two versions, for example 'povray' and 'povray''. The + versions without an apostrophe character yield a 'Tree'. The versions with a + final apostrophe character yield a 'FilePath' of a PNG file containing the + resulting image. + + The functions differ in their use of the POV-Ray @+W@ (width), @+H@ (height) + and @+A@ or @-A@ (anti-aliasing) switches, as set out below. Resolutions are + \'width x height\'. + + Example of use: + + > povray args script + + where @args@ is a list of other POV-Ray command-line switches (if any), and + @script@ is a POV-Ray scene description specified in the POV-Ray /scene/ + /description language/. -} module Reanimate.Povray ( povray @@ -38,53 +56,53 @@ povrayRaw' :: [String] -> Text -> FilePath povrayRaw' args script = unsafePerformIO $ mkPovrayImage' args script --- | Run the povray raytracer with a default resolution of 320x180 +-- | Run the POV-Ray raytracer with a default resolution of 320x180 -- and antialiasing enabled. The resulting image is scaled to fit -- the screen exactly. povray :: [String] -> Text -> Tree -povray args = povrayRaw (["+H180","+W320", "+A"] ++ args) +povray args = povrayRaw (["+H180", "+W320", "+A"] ++ args) --- | Run the povray raytracer with a default resolution of 320x180 +-- | Run the POV-Ray raytracer with a default resolution of 320x180 -- and antialiasing enabled. The FilePath points to a PNG file -- containing the resulting image. povray' :: [String] -> Text -> FilePath -povray' args = povrayRaw' (["+H180","+W320", "+A"] ++ args) +povray' args = povrayRaw' (["+H180", "+W320", "+A"] ++ args) --- | Run the povray raytracer with a default resolution of 320x180 +-- | Run the POV-Ray raytracer with a default resolution of 320x180 -- but without antialiasing. The resulting image is scaled to fit -- the screen exactly. povrayQuick :: [String] -> Text -> Tree -povrayQuick args = povrayRaw (["+H180","+W320"] ++ args) +povrayQuick args = povrayRaw (["+H180", "+W320"] ++ args) --- | Run the povray raytracer with a default resolution of 320x180 +-- | Run the POV-Ray raytracer with a default resolution of 320x180 -- but without antialiasing. The FilePath points to a PNG file -- containing the resulting image. povrayQuick' :: [String] -> Text -> FilePath -povrayQuick' args = povrayRaw' (["+H180","+W320"] ++ args) +povrayQuick' args = povrayRaw' (["+H180", "+W320"] ++ args) --- | Run the povray raytracer with a default resolution of 1440x2560 --- and antialiasing enabled. The FilePath points to a PNG file --- containing the resulting image. +-- | Run the POV-Ray raytracer with a default resolution of 2560x1440 +-- and antialiasing enabled. The resulting image is scaled to fit +-- the screen exactly. povraySlow :: [String] -> Text -> Tree -povraySlow args = povrayRaw (["+H1440","+W2560", "+A"] ++ args) +povraySlow args = povrayRaw (["+H1440", "+W2560", "+A"] ++ args) --- | Run the povray raytracer with a default resolution of 1440x2560 +-- | Run the POV-Ray raytracer with a default resolution of 2560x1440 -- and antialiasing enabled. The FilePath points to a PNG file -- containing the resulting image. povraySlow' :: [String] -> Text -> FilePath -povraySlow' args = povrayRaw' (["+H1440","+W2560", "+A"] ++ args) +povraySlow' args = povrayRaw' (["+H1440", "+W2560", "+A"] ++ args) --- | Run the povray raytracer with a default resolution of 2160x3840 --- and antialiasing enabled. The FilePath points to a PNG file --- containing the resulting image. +-- | Run the POV-Ray raytracer with a default resolution of 3840x2160 +-- and antialiasing enabled. The resulting image is scaled to fit +-- the screen exactly. povrayExtreme :: [String] -> Text -> Tree -povrayExtreme args = povrayRaw (["+H2160","+W3840", "+A"] ++ args) +povrayExtreme args = povrayRaw (["+H2160", "+W3840", "+A"] ++ args) --- | Run the povray raytracer with a default resolution of 2160x3840 +-- | Run the POV-Ray raytracer with a default resolution of 3840x2160 -- and antialiasing enabled. The FilePath points to a PNG file -- containing the resulting image. povrayExtreme' :: [String] -> Text -> FilePath -povrayExtreme' args = povrayRaw' (["+H2160","+W3840", "+A"] ++ args) +povrayExtreme' args = povrayRaw' (["+H2160", "+W3840", "+A"] ++ args) mkPovrayImage :: [String] -> Text -> IO Tree mkPovrayImage _ script | pNoExternals = pure $ mkText script From 1f6e35235af67fa16588ea2acd60d54cdc696187 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Tue, 19 Oct 2021 22:46:23 +0100 Subject: [PATCH 072/114] Suppress false broken link reports The link checker is reporting that the links in documentation to inkscape.org and wiki.gnome.org/Projects/LibRsvg are broken (with code 403 - Forbidden) when they are good links. --- .github/workflows/site-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/site-checks.yml b/.github/workflows/site-checks.yml index d15114d..4b20da4 100644 --- a/.github/workflows/site-checks.yml +++ b/.github/workflows/site-checks.yml @@ -29,7 +29,7 @@ jobs: - name: Check links at reanimate.github.io run: checklink --quiet --broken "https://reanimate.github.io/" >> failures.txt - name: Check links at reanimate.readthedocs.io - run: checklink --quiet --broken "https://reanimate.readthedocs.io/" >> failures.txt + run: checklink --quiet --broken "https://reanimate.readthedocs.io/" --suppress-broken 403:https://inkscape.org/ --suppress-broken 403:https://wiki.gnome.org/Projects/LibRsvg >> failures.txt # Haddock generates 404 links by default. :( #- name: Check links in haddock docs # run: checklink --quiet --broken "https://hackage.haskell.org/package/reanimate/docs/Reanimate.html" >> failures.txt From 584ef607a5eb374de73324359e05b139e3c25e38 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Wed, 27 Oct 2021 22:11:21 +0100 Subject: [PATCH 073/114] Fix #233 Enforce positive `Animation` durations This pull request: * causes `mkAnimation` to check (at run time) that the duration is positive, and exports new `unsafeMkAnimation` which still does not check; * uses the 'smart' constructor, and its check, in `staticFrame`, `pause`, `pauseAtBeginning`, `adjustDuration`, `repeatA`, `takeA` and `dropA`. Consequently, `takeA` and `dropA` do not need to clamp; * allows `pauseAtBeginning` and `pauseAtEnd` to have a zero duration (and, consequently, `pauseAround`); * allows `dropA` to drop 'nothing'; and * expands Haddock documentation of functions introducing duration, to explain valid values of duration. It also reformats some other Haddock comments with very long lines, so that code lines are no longer than 80 characters. --- src/Reanimate/Animation.hs | 126 +++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 47 deletions(-) diff --git a/src/Reanimate/Animation.hs b/src/Reanimate/Animation.hs index ffe2378..9ba7b84 100644 --- a/src/Reanimate/Animation.hs +++ b/src/Reanimate/Animation.hs @@ -17,6 +17,7 @@ module Reanimate.Animation , Animation -- * Creating animations , mkAnimation + , unsafeMkAnimation , animate , staticFrame , pause @@ -72,17 +73,26 @@ type SVG = Tree -- | Animations are SVGs over a finite time. data Animation = Animation Duration (Time -> SVG) --- | Construct an animation with a given duration. +-- | Construct an animation with a given duration. If the duration is not +-- positive throws 'Prelude.error'. mkAnimation :: Duration -> (Time -> SVG) -> Animation -mkAnimation = Animation +mkAnimation d f + | d > 0 = unsafeMkAnimation d f + | otherwise = error $ "Animation duration (" ++ show d ++ ") is not positive." + +-- | Construct an animation with a given duration, without checking that the +-- duration is positive. +unsafeMkAnimation :: Duration -> (Time -> SVG) -> Animation +unsafeMkAnimation = Animation -- | Construct an animation with a duration of @1@. animate :: (Time -> SVG) -> Animation animate = Animation 1 --- | Create an animation with provided @duration@, which consists of stationary frame displayed for its entire duration. +-- | Create an animation with provided @duration@, which consists of stationary +-- frame displayed for its entire duration. staticFrame :: Duration -> SVG -> Animation -staticFrame d svg = Animation d (const svg) +staticFrame d svg = mkAnimation d (const svg) -- | Query the duration of an animation. duration :: Animation -> Duration @@ -162,7 +172,8 @@ parDropA (Animation d1 f1) (Animation d2 f2) = where totalD = max d1 d2 --- | Empty animation (no SVG output) with a fixed duration. +-- | Empty animation (no SVG output) with a fixed duration. If the duration is +-- not positive throws 'Prelude.error'. -- -- Example: -- @@ -170,7 +181,7 @@ parDropA (Animation d1 f1) (Animation d2 f2) = -- -- <> pause :: Duration -> Animation -pause d = Animation d (const None) +pause d = mkAnimation d (const None) -- | Play left animation and freeze on the last frame, then play the right -- animation. New duration is '@duration lhs + duration rhs@'. @@ -183,9 +194,10 @@ pause d = Animation d (const None) andThen :: Animation -> Animation -> Animation andThen a b = a `parA` (pause (duration a) `seqA` b) --- | Calculate the frame that would be displayed at given point in @time@ of running @animation@. +-- | Calculate the frame that would be displayed at given point in @time@ of +-- running @animation@. -- --- The provided time parameter is clamped between 0 and animation duration. +-- The provided time parameter is clamped between 0 and animation duration. frameAt :: Time -> Animation -> SVG frameAt t (Animation d f) = f t' where @@ -196,8 +208,12 @@ renderTree :: SVG -> String renderTree t = maybe "" ppElement $ xmlOfTree t -- | Helper function for pretty-printing SVG nodes as SVG documents. -renderSvg :: Maybe Number -- ^ The number to use as value of the @width@ attribute of the resulting top-level svg element. If @Nothing@, the width attribute won't be rendered. - -> Maybe Number -- ^ Similar to previous argument, but for @height@ attribute. +renderSvg :: Maybe Number -- ^ The number to use as value of the @width@ + -- attribute of the resulting top-level svg element. + -- If @Nothing@, the width attribute won't be + -- rendered. + -> Maybe Number -- ^ Similar to previous argument, but for @height@ + -- attribute. -> SVG -- ^ SVG to render -> String -- ^ String representation of SVG XML markup renderSvg w h t = ppDocument doc @@ -226,7 +242,8 @@ renderSvg w h t = ppDocument doc mapA :: (SVG -> SVG) -> Animation -> Animation mapA fn (Animation d f) = Animation d (fn . f) --- | Freeze the last frame for @t@ seconds at the end of the animation. +-- | Freeze the last frame for @t@ seconds at the end of the animation. If the +-- duration is negative throws 'Prelude.error'. -- -- Example: -- @@ -234,9 +251,12 @@ mapA fn (Animation d f) = Animation d (fn . f) -- -- <> pauseAtEnd :: Duration -> Animation -> Animation -pauseAtEnd t a = a `andThen` pause t +pauseAtEnd t a + | t == 0 = a + | otherwise = a `andThen` pause t -- | Freeze the first frame for @t@ seconds at the beginning of the animation. +-- If the duration is negative throws 'Prelude.error'. -- -- Example: -- @@ -244,10 +264,12 @@ pauseAtEnd t a = a `andThen` pause t -- -- <> pauseAtBeginning :: Duration -> Animation -> Animation -pauseAtBeginning t a = - Animation t (freezeFrame 0 a) `seqA` a +pauseAtBeginning t a + | t == 0 = a + | otherwise = mkAnimation t (freezeFrame 0 a) `seqA` a --- | Freeze the first and the last frame of the animation for a specified duration. +-- | Freeze the first and the last frame of the animation for a specified +-- duration. If a duration is negative throws 'Prelude.error'. -- -- Example: -- @@ -262,13 +284,14 @@ freezeFrame :: Time -> Animation -> (Time -> SVG) freezeFrame t (Animation d f) = const $ f (t/d) -- | Change the duration of an animation. Animates are stretched or squished --- (rather than truncated) to fit the new duration. +-- (rather than truncated) to fit the new duration. If a changed duration is +-- not positive throws 'Prelude.error'. adjustDuration :: (Duration -> Duration) -> Animation -> Animation -adjustDuration fn (Animation d gen) = - Animation (fn d) gen +adjustDuration fn (Animation d gen) = mkAnimation (fn d) gen -- | Set the duration of an animation by adjusting its playback rate. The --- animation is still played from start to finish without being cropped. +-- animation is still played from start to finish without being cropped. If +-- the duration is not positive throws 'Prelude.error'. setDuration :: Duration -> Animation -> Animation setDuration newD = adjustDuration (const newD) @@ -295,8 +318,8 @@ playThenReverseA :: Animation -> Animation playThenReverseA a = a `seqA` reverseA a -- | Loop animation @n@ number of times. This number may be fractional and it --- may be less than 1. It must be greater than or equal to 0, though. --- New duration is @n*duration input@. +-- may be less than 1. It must be greater than 0, though. New duration is +-- @n*duration input@. If the duration is not positive throws 'Prelude.error'. -- -- Example: -- @@ -304,16 +327,21 @@ playThenReverseA a = a `seqA` reverseA a -- -- <> repeatA :: Double -> Animation -> Animation -repeatA n (Animation d f) = Animation (d*n) $ \t -> - f ((t*n) `mod'` 1) +repeatA n (Animation d f) = mkAnimation (d*n) $ \t -> f ((t*n) `mod'` 1) - --- | @freezeAtPercentage time animation@ creates an animation consisting of stationary frame, --- that would be displayed in the provided @animation@ at given @time@. --- The duration of the new animation is the same as the duration of provided @animation@. -freezeAtPercentage :: Time -- ^ value between 0 and 1. The frame displayed at this point in the original animation will be displayed for the duration of the new animation - -> Animation -- ^ original animation, from which the frame will be taken - -> Animation -- ^ new animation consisting of static frame displayed for the duration of the original animation +-- | @freezeAtPercentage time animation@ creates an animation consisting of +-- stationary frame, that would be displayed in the provided @animation@ at +-- given @time@. The duration of the new animation is the same as the duration +-- of provided @animation@. +freezeAtPercentage :: Time -- ^ value between 0 and 1. The frame displayed + -- at this point in the original animation + -- will be displayed for the duration of the + -- new animation + -> Animation -- ^ original animation, from which the frame + -- will be taken + -> Animation -- ^ new animation consisting of static frame + -- displayed for the duration of the original + -- animation freezeAtPercentage frac (Animation d genFrame) = Animation d $ const $ genFrame frac @@ -337,31 +365,35 @@ addStatic static = mapA (\frame -> mkGroup [static, frame]) signalA :: Signal -> Animation -> Animation signalA fn (Animation d gen) = Animation d $ gen . fn --- | @takeA duration animation@ creates a new animation consisting of initial segment of --- @animation@ of given @duration@, played at the same rate as the original animation. +-- | @takeA duration animation@ creates a new animation consisting of initial +-- segment of @animation@ of given @duration@, played at the same rate as the +-- original animation. If the duration is not positive throws 'Prelude.error'. -- --- The @duration@ parameter is clamped to be between 0 and @animation@'s duration. --- New animation duration is equal to (eventually clamped) @duration@. +-- The @duration@ parameter is clamped to be up to the @animation@'s duration. +-- New animation duration is equal to (eventually clamped) @duration@. takeA :: Duration -> Animation -> Animation -takeA len (Animation d gen) = Animation len' $ \t -> - gen (t * len'/d) - where - len' = clamp 0 d len +takeA len a@(Animation d gen) + | len >= d = a + | otherwise = mkAnimation len $ \t -> gen (t * len/d) --- | @dropA duration animation@ creates a new animation by dropping initial segment --- of length @duration@ from the provided @animation@, played at the same rate as the original animation. +-- | @dropA duration animation@ creates a new animation by dropping initial +-- segment of length @duration@ from the provided @animation@, played at the +-- same rate as the original animation. If the duration greater than or equal +-- to the @animation@'s duration throws 'Prelude.error'. -- --- The @duration@ parameter is clamped to be between 0 and @animation@'s duration. --- The duration of the resulting animation is duration of provided @animation@ minus (eventually clamped) @duration@. +-- The @duration@ parameter is clamped to be non-negative. The duration of the +-- resulting animation is duration of provided @animation@ minus @duration@. dropA :: Duration -> Animation -> Animation -dropA len (Animation d gen) = Animation len' $ \t -> - gen (t * len'/d + len/d) +dropA len a@(Animation d gen) + | len <= 0 = a + | otherwise = mkAnimation rest $ \t -> gen (t * rest/d + len/d) where - len' = d - clamp 0 d len + rest = d - len --- | @lastA duration animation@ return the last @duration@ seconds of the animation. +-- | @lastA duration animation@ return the last @duration@ seconds of the +-- animation. If the duration is not positive throws 'Prelude.error'. lastA :: Duration -> Animation -> Animation -lastA len a = dropA (duration a - len) a +lastA len a@(Animation d _) = dropA (d - len) a clamp :: Double -> Double -> Double -> Double clamp a b number From 13d3e81c0553c6d58df13f6d3d953a81f8d88b62 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Wed, 20 Oct 2021 23:14:53 +0100 Subject: [PATCH 074/114] Fix #196: Improve Haddock documentation of `withFillColor` --- src/Reanimate/Svg/Constructors.hs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Reanimate/Svg/Constructors.hs b/src/Reanimate/Svg/Constructors.hs index 1246ffb..27b2e5b 100644 --- a/src/Reanimate/Svg/Constructors.hs +++ b/src/Reanimate/Svg/Constructors.hs @@ -224,7 +224,10 @@ withStrokeDashArray arr = strokeDashArray .~ pure (map Num arr) withStrokeLineJoin :: LineJoin -> Tree -> Tree withStrokeLineJoin ljoin = strokeLineJoin .~ pure ljoin --- | See +-- | See . +-- +-- @withFillColor color@ takes the same approach to @color@ as 'mkColor'. For +-- RGB color values, use 'withFillColorPixel'. withFillColor :: String -> Tree -> Tree withFillColor color = fillColor .~ pure (mkColor color) From 5f02799402fb974fed7db92353299149590cf18e Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Fri, 5 Nov 2021 22:13:09 +0000 Subject: [PATCH 075/114] Add bounding boxes for svg nodes `Reanimate.Svg.BoundingBox.boundingBox` computes bounding boxes on a best-effort basis but currently makes no effort for `svg` nodes. This pull request proposes that the bounding box for svg nodes should be at least estimated based on the document's width and height. In addition, the addition of helper functions `ellipsePoints` and `toUserUnit'` reduce code duplication in function `svgBoundingPoints`. --- src/Reanimate/Svg/BoundingBox.hs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/Reanimate/Svg/BoundingBox.hs b/src/Reanimate/Svg/BoundingBox.hs index a152ca9..eda7f21 100644 --- a/src/Reanimate/Svg/BoundingBox.hs +++ b/src/Reanimate/Svg/BoundingBox.hs @@ -29,7 +29,9 @@ import qualified Reanimate.Transform as Transform -- -- Note: Bounding boxes are computed on a best-effort basis and will not work -- in all cases. The only supported SVG nodes are: path, circle, polyline, --- ellipse, line, rectangle, image. All other nodes return (0,0,0,0). +-- ellipse, line, rectangle, image and svg. All other nodes return (0,0,0,0). +-- The box for the svg node is based on the document's width and height +-- (if both are present). boundingBox :: Tree -> (Double, Double, Double, Double) boundingBox t = case svgBoundingPoints t of @@ -100,12 +102,18 @@ svgBoundingPoints t = map (Transform.transformPoint m) $ [V2 x y, V2 (x+w) (y+h)] _ -> [] MeshGradientTree{} -> [] + SvgTree d -> let mDims = (d ^. documentWidth, d ^. documentHeight) + in case mapTuple (fmap toUserUnit') mDims of + (Just (Num w), Just (Num h)) -> + [V2 0 0, V2 w 0, V2 w h, V2 0 h] + _ -> [] _ -> [] where m = Transform.mkMatrix (t^.transform) mapTuple f = f *** f + toUserUnit' = toUserUnit defaultDPI pointToRPoint p = - case mapTuple (toUserUnit defaultDPI) p of + case mapTuple toUserUnit' p of (Num x, Num y) -> V2 x y _ -> error "Reanimate.Svg.svgBoundingPoints: Unrecognized number format." @@ -113,7 +121,7 @@ svgBoundingPoints t = map (Transform.transformPoint m) $ let (xnum, ynum) = circ ^. circleCenter rnum = circ ^. circleRadius in case mapMaybe unpackNumber [xnum, ynum, rnum] of - [x, y, r] -> [ V2 (x + r * cos angle) (y + r * sin angle) | angle <- [0, pi/10 .. 2 * pi]] + [x, y, r] -> ellipsePoints x y r r _ -> [] ellipseBoundingPoints e = @@ -121,10 +129,13 @@ svgBoundingPoints t = map (Transform.transformPoint m) $ xrnum = e ^. ellipseXRadius yrnum = e ^. ellipseYRadius in case mapMaybe unpackNumber [xnum, ynum, xrnum, yrnum] of - [x,y,xr,yr] -> [V2 (x + xr * cos angle) (y + yr * sin angle) | angle <- [0, pi/10 .. 2 * pi]] - _ -> [] + [x, y, xr, yr] -> ellipsePoints x y xr yr + _ -> [] + + ellipsePoints x y xr yr = [ V2 (x + xr * cos angle) (y + yr * sin angle) + | angle <- [0, pi/10 .. 2 * pi] ] unpackNumber n = - case toUserUnit defaultDPI n of + case toUserUnit' n of Num d -> Just d _ -> Nothing From 744178deb09fc56ae94eae30a59d272ca36003d4 Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sat, 6 Nov 2021 23:28:14 +0000 Subject: [PATCH 076/114] Bump stack.yaml to LTS 18.15 Also adds explicit imports to module `Reanimate.Math.Triangulate`, to avoid name shadowing errors. --- src/Reanimate/Math/Triangulate.hs | 2 +- stack.yaml | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Reanimate/Math/Triangulate.hs b/src/Reanimate/Math/Triangulate.hs index 8883988..27d9ced 100644 --- a/src/Reanimate/Math/Triangulate.hs +++ b/src/Reanimate/Math/Triangulate.hs @@ -46,7 +46,7 @@ import Control.Monad.ST import Data.Ext import Data.Geometry.PlanarSubdivision (PolygonFaceData) import Data.Geometry.Point -import Data.Geometry.Polygon +import Data.Geometry.Polygon (SimplePolygon, fromPoints) import qualified Data.IntSet as ISet import qualified Data.PlaneGraph as Geo import Data.Proxy diff --git a/stack.yaml b/stack.yaml index 0e67af5..4db2d71 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,12 +1,8 @@ -resolver: lts-18.9 +resolver: lts-18.15 allow-newer: false packages: - . -extra-deps: -- earcut-0.1.0.4 -- reanimate-svg-0.13.0.1 -- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 -- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 +extra-deps: [] From bdeabc652079c5aa4189bea7335fcd22b05b785c Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sun, 7 Nov 2021 17:27:02 +0000 Subject: [PATCH 077/114] Bump Azure Windows CI to `stack.yaml` (lts-18.16) --- .azure/azure-windows-template.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.azure/azure-windows-template.yml b/.azure/azure-windows-template.yml index eca3764..e8c85af 100644 --- a/.azure/azure-windows-template.yml +++ b/.azure/azure-windows-template.yml @@ -7,10 +7,11 @@ jobs: vmImage: ${{ parameters.vmImage }} strategy: matrix: + stack: + BUILD: stack + STACK_YAML: stack.yaml + ARGS: --pedantic # lts-16.12 fails intermittently on windows. :( - # stack: - # BUILD: stack - # ARGS: --pedantic # lts-15 fails due to segfaults. Think it is a GHC issue. # stack-lts-15: # BUILD: stack From f73c725db4cc5f8122eac52b128efa8cd49c42ec Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sun, 7 Nov 2021 21:15:38 +0000 Subject: [PATCH 078/114] `svgBoundingPoints` for `RectangleTree` and `ImageTree` Currently, the bounding points for a rectangle or an image are only the upper left corner and the bottom right corner (if the width and height are specified). This pull request suggests that the other two corners of the rectangle need to be specified as bounding points (in case the rectangle is rotated by other than an integral multiple of 90 degrees). It also adds helper functions `rectPoints` and `rectPoints'` to reduce code duplication. --- src/Reanimate/Svg/BoundingBox.hs | 62 +++++++++++++++++--------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/src/Reanimate/Svg/BoundingBox.hs b/src/Reanimate/Svg/BoundingBox.hs index eda7f21..0331e73 100644 --- a/src/Reanimate/Svg/BoundingBox.hs +++ b/src/Reanimate/Svg/BoundingBox.hs @@ -78,38 +78,32 @@ linePoints = worker zero svgBoundingPoints :: Tree -> [RPoint] svgBoundingPoints t = map (Transform.transformPoint m) $ case t of - None -> [] - UseTree{} -> [] - GroupTree g -> concatMap svgBoundingPoints (g^.groupChildren) - SymbolTree g -> concatMap svgBoundingPoints (g^.groupChildren) - FilterTree{} -> [] + None -> [] + UseTree{} -> [] + GroupTree g -> concatMap svgBoundingPoints (g ^. groupChildren) + SymbolTree g -> concatMap svgBoundingPoints (g ^. groupChildren) + FilterTree{} -> [] DefinitionTree{} -> [] - PathTree p -> linePoints $ toLineCommands (p^.pathDefinition) - CircleTree c -> circleBoundingPoints c - PolyLineTree pl -> pl ^. polyLinePoints - EllipseTree e -> ellipseBoundingPoints e - LineTree line -> map pointToRPoint [line^.linePoint1, line^.linePoint2] - RectangleTree rect -> - case pointToRPoint (rect^.rectUpperLeftCorner) of - V2 x y -> V2 x y : - case mapTuple (fmap $ toUserUnit defaultDPI) (rect^.rectWidth, rect^.rectHeight) of - (Just (Num w), Just (Num h)) -> [V2 (x+w) (y+h)] - _ -> [] - TextTree{} -> [] - ImageTree img -> - case (img^.imageCornerUpperLeft, img^.imageWidth, img^.imageHeight) of - ((Num x, Num y), Num w, Num h) -> - [V2 x y, V2 (x+w) (y+h)] - _ -> [] + PathTree p -> linePoints $ toLineCommands (p ^. pathDefinition) + CircleTree c -> circleBoundingPoints c + PolyLineTree pl -> pl ^. polyLinePoints + EllipseTree e -> ellipseBoundingPoints e + LineTree l -> map pointToRPoint [l ^. linePoint1, l ^. linePoint2] + RectangleTree r -> + let p = pointToRPoint (r ^. rectUpperLeftCorner) + mDims = (r ^. rectWidth, r ^. rectHeight) + in rectPoints p mDims + TextTree{} -> [] + ImageTree img -> + let p = pointToRPoint (img ^. imageCornerUpperLeft) + dims = (img ^. imageWidth, img ^. imageHeight) + in rectPoints' p dims MeshGradientTree{} -> [] - SvgTree d -> let mDims = (d ^. documentWidth, d ^. documentHeight) - in case mapTuple (fmap toUserUnit') mDims of - (Just (Num w), Just (Num h)) -> - [V2 0 0, V2 w 0, V2 w h, V2 0 h] - _ -> [] - _ -> [] + SvgTree d -> let mDims = (d ^. documentWidth, d ^. documentHeight) + in rectPoints (V2 0 0) mDims + _ -> [] where - m = Transform.mkMatrix (t^.transform) + m = Transform.mkMatrix (t ^. transform) mapTuple f = f *** f toUserUnit' = toUserUnit defaultDPI pointToRPoint p = @@ -135,6 +129,16 @@ svgBoundingPoints t = map (Transform.transformPoint m) $ ellipsePoints x y xr yr = [ V2 (x + xr * cos angle) (y + yr * sin angle) | angle <- [0, pi/10 .. 2 * pi] ] + rectPoints p mDims = case mDims of + (Just w, Just h) -> rectPoints' p (w, h) + _ -> [p] + + rectPoints' p@(V2 x y) dims = + p : case mapTuple toUserUnit' dims of + ((Num w), (Num h)) -> let (x', y') = (x + w, y + h) + in [V2 x' y, V2 x' y', V2 x y'] + _ -> [] + unpackNumber n = case toUserUnit' n of Num d -> Just d From daa42a57f478b19318889c1796717bd6572f453c Mon Sep 17 00:00:00 2001 From: Mike Pilgrem Date: Sat, 13 Nov 2021 01:54:26 +0000 Subject: [PATCH 079/114] Fix #240 Use valid file URI format in `mkImage` --- src/Reanimate/Misc.hs | 10 ++++++++++ src/Reanimate/Raster.hs | 7 ++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Reanimate/Misc.hs b/src/Reanimate/Misc.hs index b5e8295..c8f094f 100644 --- a/src/Reanimate/Misc.hs +++ b/src/Reanimate/Misc.hs @@ -7,6 +7,7 @@ module Reanimate.Misc withTempFile, renameOrCopyFile, getReanimateCacheDirectory, + fileUri ) where @@ -118,3 +119,12 @@ getReanimateCacheDirectory = do -- Incrementing this value invalidates all cached results. cacheVersion :: Int cacheVersion = 0 + +-- | A valid file URI is file:///. If is absent, it +-- is file:///. On Windows, absolute paths begin (for example) "C:\". +fileUri :: FilePath -> String +fileUri path = "file://" <> path' + where + path' = case path of + '/' : _ -> path + _ -> '/' : path diff --git a/src/Reanimate/Raster.hs b/src/Reanimate/Raster.hs index f468ad5..465364b 100644 --- a/src/Reanimate/Raster.hs +++ b/src/Reanimate/Raster.hs @@ -43,8 +43,9 @@ import Reanimate.Animation (SVG, renderSvg) import Reanimate.Cache (cacheFile, encodeInt) import Reanimate.Constants (screenHeight, screenWidth) import Reanimate.Driver.Magick (magickCmd) -import Reanimate.Misc (getReanimateCacheDirectory, renameOrCopyFile, - requireExecutable, runCmd) +import Reanimate.Misc (fileUri, getReanimateCacheDirectory, + renameOrCopyFile, requireExecutable, + runCmd) import Reanimate.Parameters (Height, Raster (RasterNone), Width, pHeight, pNoExternals, pRaster, pRootDirectory, pWidth) import Reanimate.Render (applyRaster, requireRaster) @@ -122,7 +123,7 @@ mkImage width height path = unsafePerformIO $ do & Svg.imageHeight .~ Svg.Num height & Svg.imageHref - .~ ("file://" ++ target) + .~ (fileUri target) & Svg.imageCornerUpperLeft .~ (Svg.Num (-width / 2), Svg.Num (-height / 2)) & Svg.imageAspectRatio From d22af8dc38d867122e7d01b328f6bc3ae88759fc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Nov 2021 11:17:54 +0000 Subject: [PATCH 080/114] Bump JamesIves/github-pages-deploy-action from 4.1.5 to 4.1.6 Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.1.5 to 4.1.6. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/4.1.5...4.1.6) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index e9916be..1f7a5b8 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -101,7 +101,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@4.1.5 + uses: JamesIves/github-pages-deploy-action@4.1.6 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From 46c730569dcf51fdfbb92aca54dc546cbd1fe504 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:26:42 +0000 Subject: [PATCH 081/114] Bump JamesIves/github-pages-deploy-action from 4.1.6 to 4.2.2 Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.1.6 to 4.2.2. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/4.1.6...v4.2.2) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 1f7a5b8..b2f5a0c 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -101,7 +101,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@4.1.6 + uses: JamesIves/github-pages-deploy-action@v4.2.2 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From 3c60c0d64d76a710cfeeb7b0205ba9556df3d2cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Dec 2021 11:17:02 +0000 Subject: [PATCH 082/114] Bump actions/setup-node from 2.4.0 to 2.5.1 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 2.4.0 to 2.5.1. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v2.4.0...v2.5.1) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/site-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/site-checks.yml b/.github/workflows/site-checks.yml index 4b20da4..ca77e9e 100644 --- a/.github/workflows/site-checks.yml +++ b/.github/workflows/site-checks.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Use Node.js 10.x - uses: actions/setup-node@v2.4.0 + uses: actions/setup-node@v2.5.1 with: node-version: 10.x - name: Install dependencies From 30359e9d371157b92ab77fcced789c6699971e1c Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sun, 23 Jan 2022 16:27:43 +0000 Subject: [PATCH 083/114] Add 'signalS' and `signalO` for applying easing functions to sprites/objects. (#260) --- .azure/azure-osx-template.yml | 10 ++++----- .github/workflows/playground.yml | 1 + azure-pipelines.yml | 10 ++++----- examples/doc_signalO.hs | 27 +++++++++++++++++++++++ examples/doc_signalS.hs | 13 +++++++++++ src/Reanimate.hs | 1 + src/Reanimate/Scene.hs | 2 ++ src/Reanimate/Scene/Core.hs | 18 ++++++++++++++++ src/Reanimate/Scene/Object.hs | 6 +++++- src/Reanimate/Scene/Sprite.hs | 37 +++++++++++++++++++++++--------- 10 files changed, 104 insertions(+), 21 deletions(-) create mode 100644 examples/doc_signalO.hs create mode 100755 examples/doc_signalS.hs diff --git a/.azure/azure-osx-template.yml b/.azure/azure-osx-template.yml index 14d5ef6..0274139 100644 --- a/.azure/azure-osx-template.yml +++ b/.azure/azure-osx-template.yml @@ -11,12 +11,12 @@ jobs: BUILD: stack STACK_YAML: stack.yaml ARGS: --pedantic - stack-lts-15: + #stack-lts-16: + # BUILD: stack + # STACK_YAML: stack-lts-16.yaml + stack-lts-17: BUILD: stack - STACK_YAML: stack-lts-14.yaml - stack-lts-14: - BUILD: stack - STACK_YAML: stack-lts-14.yaml + STACK_YAML: stack-lts-17.yaml maxParallel: 6 steps: - task: Cache@2 diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index 359e696..ffe8bd5 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -30,6 +30,7 @@ jobs: - name: Install dependencies run: | + sudo apt-get update sudo apt-get -y install texlive texlive-latex-base texlive-latex-extra stack build --only-dependencies (cd playground && stack build --only-dependencies) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a54cc2e..528a629 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,11 +21,11 @@ jobs: vmImage: ubuntu-latest os: linux -- template: ./.azure/azure-osx-template.yml - parameters: - name: macOS - vmImage: macOS-10.14 - os: osx +#- template: ./.azure/azure-osx-template.yml +# parameters: +# name: macOS +# vmImage: macOS-11 +# os: osx - template: ./.azure/azure-windows-template.yml parameters: diff --git a/examples/doc_signalO.hs b/examples/doc_signalO.hs new file mode 100644 index 0000000..62cc466 --- /dev/null +++ b/examples/doc_signalO.hs @@ -0,0 +1,27 @@ +#!/usr/bin/env stack +-- stack runghc --package reanimate +module Main(main) where + +import Reanimate +import Reanimate.Scene +import Reanimate.Builtin.Documentation +import Control.Lens +import Control.Monad + +main :: IO () +main = reanimate $ docEnv $ scene $ do + objs <- waitOn $ replicateM 3 $ do + obj1 <- newObject $ mkCircle 1 + oModifyS obj1 $ oEasing .= id + oModifyS obj1 $ oRightX .= screenRight + fork $ oShowWith obj1 oFadeIn + fork $ oTweenS obj1 2 $ \t -> + oLeftX %= \origin -> fromToS origin screenLeft t + wait 1 + oHideWith obj1 oFadeOut + wait (-1.5) + return obj1 + dur <- queryNow + wait (-dur) + forM_ objs $ \obj -> do + signalO obj dur $ curveS 2 diff --git a/examples/doc_signalS.hs b/examples/doc_signalS.hs new file mode 100755 index 0000000..51d1a0f --- /dev/null +++ b/examples/doc_signalS.hs @@ -0,0 +1,13 @@ +#!/usr/bin/env stack +-- stack runghc --package reanimate +module Main(main) where + +import Reanimate +import Reanimate.Builtin.Documentation + +main :: IO () +main = reanimate $ docEnv $ playThenReverseA $ scene $ do + sprite <- fork $ newSpriteA $ drawCircle + signalS sprite 1 (curveS 2) + wait 1 + signalS sprite 1 (powerS 2) diff --git a/src/Reanimate.hs b/src/Reanimate.hs index 9a17215..2b25bda 100644 --- a/src/Reanimate.hs +++ b/src/Reanimate.hs @@ -103,6 +103,7 @@ module Reanimate , unVar -- :: Var s a -> Frame s a , spriteT -- :: Frame s Time , spriteDuration -- :: Frame s Duration + , signalS -- :: Sprite s -> Duration -> Signal -> Scene s () , newSprite -- :: Frame s SVG -> Scene s (Sprite s) , newSprite_ -- :: Frame s SVG -> Scene s () , newSpriteA -- :: Animation -> Scene s (Sprite s) diff --git a/src/Reanimate/Scene.hs b/src/Reanimate/Scene.hs index 6f7a565..a4290a3 100644 --- a/src/Reanimate/Scene.hs +++ b/src/Reanimate/Scene.hs @@ -20,6 +20,7 @@ module Reanimate.Scene waitOn, -- :: Scene s a -> Scene s a adjustZ, -- :: (ZIndex -> ZIndex) -> Scene s a -> Scene s a withSceneDuration, -- :: Scene s () -> Scene s Duration + signalS, -- Signal -> Scene s a -> Scene s a -- * Variables Var, @@ -56,6 +57,7 @@ module Reanimate.Scene -- * Object API Object, ObjectData, + signalO, oNew, newObject, oModify, diff --git a/src/Reanimate/Scene/Core.hs b/src/Reanimate/Scene/Core.hs index 1c2dba5..38678f6 100644 --- a/src/Reanimate/Scene/Core.hs +++ b/src/Reanimate/Scene/Core.hs @@ -73,6 +73,24 @@ scene action = ) ) +-- -- | Apply easing function to all render elements created by the scene +-- -- in the timespan from now to the scene duration. +-- -- +-- -- Note that this does not affect time as seen by `queryNow` or any +-- -- time-dependent variables or object properties. +-- signalS :: Signal -> Scene s a -> Scene s a +-- signalS signal (M action) = M $ \now -> do +-- (a, s, p, gens) <- action now +-- let action_dur = max s p +-- modify_t t +-- | t < now = t +-- | t > now+action_dur = t +-- | otherwise = now + signal ((t-now) / action_dur) * action_dur +-- let applyS gen = do +-- fn <- gen +-- return $ \dur t -> fn dur (modify_t t) +-- return (a, s, p, map applyS gens) + -- | Execute actions in a scene without advancing the clock. Note that scenes do not end before -- all forked actions have completed. -- diff --git a/src/Reanimate/Scene/Object.hs b/src/Reanimate/Scene/Object.hs index b52fbe0..351722f 100644 --- a/src/Reanimate/Scene/Object.hs +++ b/src/Reanimate/Scene/Object.hs @@ -18,7 +18,7 @@ import Reanimate.Morph.Linear (linear) import Reanimate.Svg import Reanimate.Scene.Core (Scene, fork, scene, wait) -import Reanimate.Scene.Sprite (Sprite, newSprite, newSpriteA', play, spriteModify, unVar) +import Reanimate.Scene.Sprite (Sprite, newSprite, newSpriteA', play, spriteModify, unVar, signalS) import Reanimate.Scene.Var (Var, modifyVar, newVar, readVar, tweenVar) ------------------------------------------------------- @@ -245,6 +245,10 @@ oBBHeight = oBB . _4 ------------------------------------------------------------------------------- -- Object modifiers +-- | Apply easing function before rendering object. +signalO :: Object s a -> Duration -> Signal -> Scene s () +signalO obj dur signal = signalS (objectSprite obj) dur signal + -- | Modify object properties. oModify :: Object s a -> (ObjectData a -> ObjectData a) -> Scene s () oModify o = modifyVar (objectData o) diff --git a/src/Reanimate/Scene/Sprite.hs b/src/Reanimate/Scene/Sprite.hs index a25d398..a809758 100644 --- a/src/Reanimate/Scene/Sprite.hs +++ b/src/Reanimate/Scene/Sprite.hs @@ -16,6 +16,7 @@ import Reanimate.Scene.Core (Scene (M), ZIndex, addGen, fork, liftST, wait) import Reanimate.Scene.Var (Var (..), newVar, readVar, unpackVar) import Reanimate.Transition (Transition, overlapT) +import Reanimate.Ease (Signal) -- | Create and render a variable. The rendering will be born at the current timestamp -- and will persist until the end of the scene. @@ -57,7 +58,7 @@ play ani = newSpriteA ani >>= destroySprite -- | Sprites are animations with a given time of birth as well as a time of death. -- They can be controlled using variables, tweening, and effects. -data Sprite s = Sprite Time (STRef s (Duration, ST s (Duration -> Time -> SVG -> (SVG, ZIndex)))) +data Sprite s = Sprite Time (STRef s (Time -> Time)) (STRef s (Duration, ST s (Duration -> Time -> SVG -> (SVG, ZIndex)))) -- | Sprite frame generator. Generates frames over time in a stateful environment. newtype Frame s a = Frame {unFrame :: ST s (Time -> Duration -> Time -> a)} @@ -113,13 +114,16 @@ spriteDuration = Frame $ return (\_real_t d _t -> d) newSprite :: Frame s SVG -> Scene s (Sprite s) newSprite render = do now <- queryNow + tmod <- liftST $ newSTRef id ref <- liftST $ newSTRef (-1, return $ \_d _t svg -> (svg, 0)) addGen $ do fn <- unFrame render + time_fn <- readSTRef tmod (spriteDur, spriteEffectGen) <- readSTRef ref spriteEffect <- spriteEffectGen - return $ \d absT -> - let relD = (if spriteDur < 0 then d else spriteDur) - now + return $ \d absT_ -> + let absT = time_fn absT_ + relD = (if spriteDur < 0 then d else spriteDur) - now relT = absT - now -- Sprite is live [now;duration[ -- If we're at the end of a scene, sprites @@ -131,7 +135,7 @@ newSprite render = do in if inTimeSlice || isLastFrame then spriteEffect relD relT (fn absT relD relT) else (None, 0) - return $ Sprite now ref + return $ Sprite now tmod ref -- | Create new sprite defined by a frame generator. The sprite will die at -- the end of the scene. @@ -224,7 +228,7 @@ applyVar var sprite fn = spriteModify sprite $ do -- -- <> destroySprite :: Sprite s -> Scene s () -destroySprite (Sprite _ ref) = do +destroySprite (Sprite _ _tmod ref) = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, render) -> @@ -232,7 +236,7 @@ destroySprite (Sprite _ ref) = do -- | Low-level frame modifier. spriteModify :: Sprite s -> Frame s ((SVG, ZIndex) -> (SVG, ZIndex)) -> Scene s () -spriteModify (Sprite born ref) modFn = liftST $ +spriteModify (Sprite born _tmod ref) modFn = liftST $ modifySTRef ref $ \(ttl, renderGen) -> ( ttl, do @@ -242,6 +246,19 @@ spriteModify (Sprite born ref) modFn = liftST $ let absT = relT + born in modRender absT relD relT . render relD relT ) +-- | Apply easing function before rendering sprite. +signalS :: Sprite s -> Duration -> Signal -> Scene s () +signalS (Sprite _born tmod _ref) dur signal = do + now <- queryNow + let modify_t t + | t < now = t + | t > now+dur = t + | otherwise = now + signal ((t-now) / dur) * dur + liftST $ + modifySTRef tmod $ \fn -> modify_t . fn + + + -- | Map the SVG output of a sprite. -- -- Example: @@ -254,7 +271,7 @@ spriteModify (Sprite born ref) modFn = liftST $ -- -- <> spriteMap :: Sprite s -> (SVG -> SVG) -> Scene s () -spriteMap sprite@(Sprite born _) fn = do +spriteMap sprite@(Sprite born _ _) fn = do now <- queryNow let tDelta = now - born spriteModify sprite $ do @@ -272,7 +289,7 @@ spriteMap sprite@(Sprite born _) fn = do -- -- <> spriteTween :: Sprite s -> Duration -> (Double -> SVG -> SVG) -> Scene s () -spriteTween sprite@(Sprite born _) dur fn = do +spriteTween sprite@(Sprite born _ _) dur fn = do now <- queryNow let tDelta = now - born spriteModify sprite $ do @@ -314,7 +331,7 @@ spriteVar sprite def fn = do -- -- <> spriteE :: Sprite s -> Effect -> Scene s () -spriteE (Sprite born ref) effect = do +spriteE (Sprite born _tmod ref) effect = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, renderGen) -> @@ -340,7 +357,7 @@ spriteE (Sprite born ref) effect = do -- -- <> spriteZ :: Sprite s -> ZIndex -> Scene s () -spriteZ (Sprite born ref) zindex = do +spriteZ (Sprite born _tmod ref) zindex = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, renderGen) -> From 5b76d53737e4da0b200f333fc885f9b4ef746ffc Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sun, 23 Jan 2022 17:35:04 +0000 Subject: [PATCH 084/114] Fix CI. (#261) --- .github/workflows/haskell.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index b4a6a01..f1c2505 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-haskell@v1 with: - ghc-version: '8.8.2' + ghc-version: 'latest' cabal-version: '3.0' - name: Cache From 4030ff877bbe518e2d2417434c39c449c62d9175 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sun, 23 Jan 2022 18:54:31 +0100 Subject: [PATCH 085/114] Bump ghc version. --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index b2f5a0c..ce310e0 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -12,7 +12,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-haskell@v1 with: - ghc-version: '8.8' + ghc-version: 'latest' cabal-version: 'latest' - uses: jorelali/setup-elm@v3 with: From 5bf94d0d05eb5ce329125f958c191c0326da67fd Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sun, 23 Jan 2022 19:02:38 +0100 Subject: [PATCH 086/114] Disable coverage for deps. --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index ce310e0..58628ce 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -32,7 +32,7 @@ jobs: - name: Install dependencies run: | cabal v2-update - cabal v2-build --enable-coverage --only-dependencies + cabal v2-build --only-dependencies mkdir pages - name: Build From f0e1eb413f51a62df5ad1463f528a4e7b6f542e3 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Sun, 23 Jan 2022 19:27:13 +0100 Subject: [PATCH 087/114] Disable coverage. --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 58628ce..e9d76dd 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -37,7 +37,7 @@ jobs: - name: Build run: | - cabal v2-build --enable-coverage + cabal v2-build # - name: Generate HPC files # run: | From c0b5eeea070a410b4b41822368641e08fe96ff42 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 24 Jan 2022 09:40:40 +0100 Subject: [PATCH 088/114] Update apt sources. --- .github/workflows/gh-pages.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index e9d76dd..5804684 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -87,6 +87,7 @@ jobs: # Is there a way to reuse the script from playground.yml? - name: Playground run: | + sudo apt-get update sudo apt-get -y install texlive texlive-latex-base texlive-latex-extra CWD=`pwd` stack build From 1536605cdd4cc0d23de9a49713e15a9330d02f55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 23 Jan 2022 17:36:04 +0000 Subject: [PATCH 089/114] Bump follow-redirects from 1.9.0 to 1.14.7 in /viewer-elm Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.9.0 to 1.14.7. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.9.0...v1.14.7) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] --- viewer-elm/package-lock.json | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index db9500b..b8a945c 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -452,30 +452,10 @@ } }, "follow-redirects": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.9.0.tgz", - "integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==", - "dev": true, - "requires": { - "debug": "^3.0.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } + "version": "1.14.7", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", + "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "dev": true }, "forever-agent": { "version": "0.6.1", From 8375edaaf5eac0a52317818b9fae58fc002a7122 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Mon, 24 Jan 2022 10:49:05 +0100 Subject: [PATCH 090/114] Bump version to 1.1.5.0 --- reanimate.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reanimate.cabal b/reanimate.cabal index d1ff354..0179c07 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.4.0 +version: 1.1.5.0 -- synopsis: -- description: license: PublicDomain From 54ffee4e6d86a5e45ab2965ca4ba2a47351d12bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Feb 2022 12:48:25 +0100 Subject: [PATCH 091/114] Bump ajv from 6.10.2 to 6.12.6 in /viewer-elm (#263) Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.10.2 to 6.12.6. - [Release notes](https://github.com/ajv-validator/ajv/releases) - [Commits](https://github.com/ajv-validator/ajv/compare/v6.10.2...v6.12.6) --- updated-dependencies: - dependency-name: ajv dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- viewer-elm/package-lock.json | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index b8a945c..39c3ab2 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -5,14 +5,21 @@ "requires": true, "dependencies": { "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" + }, + "dependencies": { + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + } } }, "ansi-regex": { @@ -417,11 +424,6 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" - }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", From c4a2f1dedd55de3d303cd743fd9e94556b7cfca8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Feb 2022 12:48:33 +0100 Subject: [PATCH 092/114] Bump follow-redirects from 1.14.7 to 1.14.8 in /viewer-elm (#264) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- viewer-elm/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index 39c3ab2..3462190 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -454,9 +454,9 @@ } }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.8.tgz", + "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "dev": true }, "forever-agent": { From 67a47298021c9e55bd9299f67dc88c4ce347aef2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Feb 2022 12:48:41 +0100 Subject: [PATCH 093/114] Bump JamesIves/github-pages-deploy-action from 4.2.2 to 4.2.5 (#265) Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.2.2 to 4.2.5. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/v4.2.2...v4.2.5) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 5804684..f7aa7ed 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -102,7 +102,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.2.2 + uses: JamesIves/github-pages-deploy-action@v4.2.5 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From c6e801683de889d057315a944edbb7cbffa137ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 25 Feb 2022 12:48:54 +0100 Subject: [PATCH 094/114] Bump actions/setup-node from 2.5.1 to 3 (#266) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 2.5.1 to 3. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v2.5.1...v3) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/site-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/site-checks.yml b/.github/workflows/site-checks.yml index ca77e9e..8848456 100644 --- a/.github/workflows/site-checks.yml +++ b/.github/workflows/site-checks.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Use Node.js 10.x - uses: actions/setup-node@v2.5.1 + uses: actions/setup-node@v3 with: node-version: 10.x - name: Install dependencies From e7b74693953501d9e51c2166cc48365d732734b2 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Wed, 30 Mar 2022 13:25:15 +0200 Subject: [PATCH 095/114] Restrict hgeometry dependency. (#273) --- reanimate.cabal | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/reanimate.cabal b/reanimate.cabal index 0179c07..4a6e626 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -117,8 +117,8 @@ library cpp-options: -DNO_HGEOMETRY else build-depends: - hgeometry >=0.11.0.0, - hgeometry-combinatorial >=0.11.0.0 + hgeometry >=0.11.0.0 && < 0.14, + hgeometry-combinatorial >=0.11.0.0 && < 0.14 build-depends: base >=4.10 && <5, JuicyPixels >=3.3.3, From 19df0ae7a803307a5af0b9251dc1c25a75cfda72 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Mar 2022 14:14:11 +0200 Subject: [PATCH 096/114] Bump minimist from 1.2.5 to 1.2.6 in /viewer-elm (#272) Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6) --- updated-dependencies: - dependency-name: minimist dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- viewer-elm/package-lock.json | 6 +++--- viewer-elm/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index 3462190..8dc980a 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -749,9 +749,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "minipass": { diff --git a/viewer-elm/package.json b/viewer-elm/package.json index 4f9dbae..1645bcd 100644 --- a/viewer-elm/package.json +++ b/viewer-elm/package.json @@ -18,6 +18,6 @@ "elm-format": "^0.8.2", "elm-live": "^4.0.1", "uglify-js": "^3.7.2", - "minimist": ">=1.2.2" + "minimist": ">=1.2.6" } } From d0a606e7bbdb71ac60a5d1acddc2a2e7bc840472 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 30 Mar 2022 14:15:11 +0200 Subject: [PATCH 097/114] Bump actions/checkout from 2 to 3 (#268) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- .github/workflows/site-checks.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index f7aa7ed..f0b67fb 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-haskell@v1 with: ghc-version: 'latest' diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index f1c2505..0fabd18 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-haskell@v1 with: ghc-version: 'latest' diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index ffe8bd5..f071afa 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: actions/setup-haskell@v1 with: ghc-version: '8.8' diff --git a/.github/workflows/site-checks.yml b/.github/workflows/site-checks.yml index 8848456..1bfdec2 100644 --- a/.github/workflows/site-checks.yml +++ b/.github/workflows/site-checks.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 10.x uses: actions/setup-node@v3 with: From c5ab0606e727317d7f4067f98f2485e187297bf5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Apr 2022 13:16:53 +0200 Subject: [PATCH 098/114] Bump actions/cache from 2 to 3.0.1 (#274) Bumps [actions/cache](https://github.com/actions/cache) from 2 to 3.0.1. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v2...v3.0.1) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index f0b67fb..7175211 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,7 +19,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3.0.1 with: path: | ~/.cabal diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index 0fabd18..2df52d8 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -19,7 +19,7 @@ jobs: cabal-version: '3.0' - name: Cache - uses: actions/cache@v1 + uses: actions/cache@v3.0.1 env: cache-name: cache-cabal with: diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index f071afa..3eeea70 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -20,7 +20,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v2 + uses: actions/cache@v3.0.1 with: path: | ~/.stack From 33a0d488aa24f958eee84d11c7be2bfa9308eea5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 15:57:09 +0200 Subject: [PATCH 099/114] Bump JamesIves/github-pages-deploy-action from 4.2.5 to 4.3.0 (#275) Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.2.5 to 4.3.0. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/v4.2.5...v4.3.0) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 7175211..ca7892a 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -102,7 +102,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.2.5 + uses: JamesIves/github-pages-deploy-action@v4.3.0 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From 6f0dba72843003d96a18343e9b45867475c566d5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Apr 2022 15:57:34 +0200 Subject: [PATCH 100/114] Bump actions/cache from 3.0.1 to 3.0.2 (#276) Bumps [actions/cache](https://github.com/actions/cache) from 3.0.1 to 3.0.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.1...v3.0.2) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index ca7892a..85202f7 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,7 +19,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.1 + uses: actions/cache@v3.0.2 with: path: | ~/.cabal diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index 2df52d8..2bdf032 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -19,7 +19,7 @@ jobs: cabal-version: '3.0' - name: Cache - uses: actions/cache@v3.0.1 + uses: actions/cache@v3.0.2 env: cache-name: cache-cabal with: diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index 3eeea70..a841435 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -20,7 +20,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.1 + uses: actions/cache@v3.0.2 with: path: | ~/.stack From 594a7a491f920c31ad7f4360a446a087abe9c41c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 15:40:03 +0200 Subject: [PATCH 101/114] Bump JamesIves/github-pages-deploy-action from 4.3.0 to 4.3.3 (#278) Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.3.0 to 4.3.3. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/v4.3.0...v4.3.3) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 85202f7..1dc4b7b 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -102,7 +102,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.3.0 + uses: JamesIves/github-pages-deploy-action@v4.3.3 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From f70ef76ddb479c6acef8032487beaa646cfd8885 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jun 2022 15:40:14 +0200 Subject: [PATCH 102/114] Bump actions/cache from 3.0.2 to 3.0.3 (#280) Bumps [actions/cache](https://github.com/actions/cache) from 3.0.2 to 3.0.3. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.2...v3.0.3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 1dc4b7b..cb25dd9 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,7 +19,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.2 + uses: actions/cache@v3.0.3 with: path: | ~/.cabal diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index 2bdf032..a029572 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -19,7 +19,7 @@ jobs: cabal-version: '3.0' - name: Cache - uses: actions/cache@v3.0.2 + uses: actions/cache@v3.0.3 env: cache-name: cache-cabal with: diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index a841435..7cc93dc 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -20,7 +20,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.2 + uses: actions/cache@v3.0.3 with: path: | ~/.stack From ed1c0ba6c198b7f14a2d512ca77470cc41f3bfa4 Mon Sep 17 00:00:00 2001 From: Paul Gardiner Date: Thu, 2 Jun 2022 14:40:56 +0100 Subject: [PATCH 103/114] Hierarchical sprites and objects (#269) * Separate sprite creation from adding to scene This is work towards supporting hierarchical sprites and objects: the Sprite data definition is updated to include it's generator and a new function newSpritePart is added to create a sprite without adding the generator to the scene, making it invisible. Later commits will provide a way for sprites created by newSpritePart to be used in the definitions of other sprites. * Support use of one sprite within another This is work towards supporting hierarchical sprites and objects. A new function, renderSprite, is defined that exposes its generator in the form of a Frame context that can be used in the definitions of other sprites. Some internal types have had to be changed to support renderSprite. The frame context created by renderSprite runs the sprite's generator, and must supply the scene duration to it, and so the frame type has had to be updated also to be dependent on the scene duration. In turn, a sprite's effects mapping needs to be able to interpret a frame context in the implementation of spriteModify, and so the effects mapping has also had to be made dependent on the scene duration. * Support use of objects within hierarchical sprites Allow use of objects as leaves within a hierarchically defined sprite. Two new functions are added: The function newObjectPart creates an object, not immediately added to the scene, so invisible even after calls to oShow, and mainfesting only if used within the definition of a sprite. The function renderObject exposes the generator of the object's internal sprite in the form of a frame context that can be used in the definitions of other sprites. * Add example script showing use of newObjectPart and renderObject This is a slightly contrived example, chosen to show an animation that is difficult to contruct other than hiearchically. Two strings are placed one over the other. They are shown using oDraw which requires their being Objects. The overlapping strings are faded out, which requires opacity to be applied at the group level: fading each individually would lead to the lower string becoming visible through the upper one as opacity is decreased. --- docs/gifs/doc_renderObject.gif | Bin 0 -> 53349 bytes src/Reanimate.hs | 2 + src/Reanimate/Scene.hs | 4 ++ src/Reanimate/Scene/Object.hs | 39 +++++++++++++++- src/Reanimate/Scene/Sprite.hs | 80 ++++++++++++++++++++------------- 5 files changed, 93 insertions(+), 32 deletions(-) create mode 100644 docs/gifs/doc_renderObject.gif diff --git a/docs/gifs/doc_renderObject.gif b/docs/gifs/doc_renderObject.gif new file mode 100644 index 0000000000000000000000000000000000000000..c88505577d28010334a965e119a360f0147cb97c GIT binary patch literal 53349 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 XmJltu%HQ&>ET04=3rYDv0s;U#G|8Dn literal 0 HcmV?d00001 diff --git a/src/Reanimate.hs b/src/Reanimate.hs index 2b25bda..990ed15 100644 --- a/src/Reanimate.hs +++ b/src/Reanimate.hs @@ -105,12 +105,14 @@ module Reanimate , spriteDuration -- :: Frame s Duration , signalS -- :: Sprite s -> Duration -> Signal -> Scene s () , newSprite -- :: Frame s SVG -> Scene s (Sprite s) + , newSpritePart -- :: Frame s SVG -> Scene s (Sprite s) , newSprite_ -- :: Frame s SVG -> Scene s () , newSpriteA -- :: Animation -> Scene s (Sprite s) , newSpriteA' -- :: Sync -> Animation -> Scene s (Sprite s) , newSpriteSVG -- :: SVG -> Scene s (Sprite s) , newSpriteSVG_ -- :: SVG -> Scene s () , destroySprite -- :: Sprite s -> Scene s () + , renderSprite -- :: Sprite s -> Frame s SVG , applyVar -- :: Var s a -> Sprite s -> (a -> SVG -> SVG) -> Scene s () , spriteModify -- :: Sprite s -> Frame s ((SVG,ZIndex) -> (SVG, ZIndex)) -> Scene s () , spriteMap -- :: Sprite s -> (SVG -> SVG) -> Scene s () diff --git a/src/Reanimate/Scene.hs b/src/Reanimate/Scene.hs index a4290a3..0a29305 100644 --- a/src/Reanimate/Scene.hs +++ b/src/Reanimate/Scene.hs @@ -39,12 +39,14 @@ module Reanimate.Scene spriteT, -- :: Frame s Time spriteDuration, -- :: Frame s Duration newSprite, -- :: Frame s SVG -> Scene s (Sprite s) + newSpritePart, -- :: Frame s SVG -> Scene s (Sprite s) newSprite_, -- :: Frame s SVG -> Scene s () newSpriteA, -- :: Animation -> Scene s (Sprite s) newSpriteA', -- :: Sync -> Animation -> Scene s (Sprite s) newSpriteSVG, -- :: SVG -> Scene s (Sprite s) newSpriteSVG_, -- :: SVG -> Scene s () destroySprite, -- :: Sprite s -> Scene s () + renderSprite, -- :: Sprite s -> Frame s SVG applyVar, -- :: Var s a -> Sprite s -> (a -> SVG -> SVG) -> Scene s () spriteModify, -- :: Sprite s -> Frame s ((SVG,ZIndex) -> (SVG, ZIndex)) -> Scene s () spriteMap, -- :: Sprite s -> (SVG -> SVG) -> Scene s () @@ -60,6 +62,8 @@ module Reanimate.Scene signalO, oNew, newObject, + newObjectPart, + renderObject, oModify, oModifyS, oRead, diff --git a/src/Reanimate/Scene/Object.hs b/src/Reanimate/Scene/Object.hs index 351722f..660eb00 100644 --- a/src/Reanimate/Scene/Object.hs +++ b/src/Reanimate/Scene/Object.hs @@ -18,7 +18,7 @@ import Reanimate.Morph.Linear (linear) import Reanimate.Svg import Reanimate.Scene.Core (Scene, fork, scene, wait) -import Reanimate.Scene.Sprite (Sprite, newSprite, newSpriteA', play, spriteModify, unVar, signalS) +import Reanimate.Scene.Sprite (Frame, Sprite, addPartToScene, newSpritePart, newSpriteA', play, spriteModify, unVar, signalS, renderSprite) import Reanimate.Scene.Var (Var, modifyVar, newVar, readVar, tweenVar) ------------------------------------------------------- @@ -290,6 +290,15 @@ oNew = newObject -- | Create new object. newObject :: Renderable a => a -> Scene s (Object s a) newObject val = do + obj <- newObjectPart val + addPartToScene $ objectSprite obj + return obj + +-- | Create new object, but not showing as part of the scene, Such +-- objects can be used hierachically within the definitions of +-- sprites, via the function renderObject. +newObjectPart :: Renderable a => a -> Scene s (Object s a) +newObjectPart val = do ref <- newVar ObjectData @@ -306,7 +315,7 @@ newObject val = do _oScale = 1, _oScaleOrigin = V2 0 0 } - sprite <- newSprite $ do + sprite <- newSpritePart $ do ~obj@ObjectData {..} <- unVar ref pure $ if _oShown @@ -327,6 +336,32 @@ newObject val = do where svg = toSVG val +-- | Create a frame context from an object for use within a sprite definition. +-- +-- Example: +-- +-- @ +-- do opacityVar <- 'newVar' 1 +-- textObj1 <- 'newObjectPart' $ 'scale' 3 $ 'center' $ 'latex' "Fade" +-- 'oModify' textObj1 $ 'oContext' .~ 'withFillColor' "red" +-- textObj2 <- 'newObjectPart' $ 'scale' 3 $ 'center' $ 'latex' "Overlap" +-- 'oModify' textObj2 $ 'oContext' .~ 'withFillColor' "blue" +-- sprite <- 'newSprite' $ do +-- opacity <- 'unVar' opacityVar +-- text1 <- 'renderObject' textObj1 +-- text2 <- 'renderObject' textObj2 +-- 'return' $ 'withGroupOpacity' opacity $ 'mkGroup' [text1, text2] +-- 'fork' $ 'oShowWith' textObj1 $ 'setDuration' 1 . 'oDraw' +-- 'wait' 0.2 +-- 'fork' $ 'oShowWith' textObj2 $ 'setDuration' 1 . 'oDraw' +-- 'wait' 0.2 +-- 'tweenVar' opacityVar 1 $ 'const' $ 'fromToS' 1 0 +-- @ +-- +-- <> +renderObject :: Object s a -> Frame s SVG +renderObject obj = renderSprite $ objectSprite obj + oScaleApply :: ObjectData a -> (SVG -> SVG) oScaleApply ObjectData {..} = uncurryV2 translate (negate _oScaleOrigin) diff --git a/src/Reanimate/Scene/Sprite.hs b/src/Reanimate/Scene/Sprite.hs index a809758..f93d711 100644 --- a/src/Reanimate/Scene/Sprite.hs +++ b/src/Reanimate/Scene/Sprite.hs @@ -12,7 +12,7 @@ import Graphics.SvgTree (pattern None) import Reanimate.Animation (Animation, Duration, SVG, Sync (SyncStretch), Time, dropA, duration, getAnimationFrame) import Reanimate.Effect (Effect, delayE) -import Reanimate.Scene.Core (Scene (M), ZIndex, addGen, fork, liftST, queryNow, scene, +import Reanimate.Scene.Core (Gen, Scene (M), ZIndex, addGen, fork, liftST, queryNow, scene, wait) import Reanimate.Scene.Var (Var (..), newVar, readVar, unpackVar) import Reanimate.Transition (Transition, overlapT) @@ -58,22 +58,22 @@ play ani = newSpriteA ani >>= destroySprite -- | Sprites are animations with a given time of birth as well as a time of death. -- They can be controlled using variables, tweening, and effects. -data Sprite s = Sprite Time (STRef s (Time -> Time)) (STRef s (Duration, ST s (Duration -> Time -> SVG -> (SVG, ZIndex)))) +data Sprite s = Sprite Time (STRef s (Time -> Time)) (STRef s (Duration, ST s (Duration -> Duration -> Time -> SVG -> (SVG, ZIndex)))) (Gen s) -- | Sprite frame generator. Generates frames over time in a stateful environment. -newtype Frame s a = Frame {unFrame :: ST s (Time -> Duration -> Time -> a)} +newtype Frame s a = Frame {unFrame :: ST s (Duration -> Time -> Duration -> Time -> a)} instance Functor (Frame s) where fmap fn (Frame gen) = Frame $ do m <- gen - return (\real_t d t -> fn $ m real_t d t) + return (\scene_d real_t d t -> fn $ m scene_d real_t d t) instance Applicative (Frame s) where - pure v = Frame $ return (\_ _ _ -> v) + pure v = Frame $ return (\_ _ _ _ -> v) Frame f <*> Frame g = Frame $ do m1 <- f m2 <- g - return $ \real_t d t -> m1 real_t d t (m2 real_t d t) + return $ \scene_d real_t d t -> m1 scene_d real_t d t (m2 scene_d real_t d t) -- | Dereference a variable as a Sprite frame. -- @@ -90,15 +90,15 @@ instance Applicative (Frame s) where unVar :: Var s a -> Frame s a unVar var = Frame $ do fn <- unpackVar var - return $ \real_t _d _t -> fn real_t + return $ \_scene_d real_t _d _t -> fn real_t -- | Dereference seconds since sprite birth. spriteT :: Frame s Time -spriteT = Frame $ return (\_real_t _d t -> t) +spriteT = Frame $ return (\_scene_d _real_t _d t -> t) -- | Dereference duration of the current sprite. spriteDuration :: Frame s Duration -spriteDuration = Frame $ return (\_real_t d _t -> d) +spriteDuration = Frame $ return (\_scene_d _real_t d _t -> d) -- | Create new sprite defined by a frame generator. Unless otherwise specified using -- 'destroySprite', the sprite will die at the end of the scene. @@ -113,17 +113,26 @@ spriteDuration = Frame $ return (\_real_t d _t -> d) -- <> newSprite :: Frame s SVG -> Scene s (Sprite s) newSprite render = do + s <- newSpritePart render + addPartToScene s + return s + +-- | Create a new sprite defined by a frame generator, but not showing +-- as part of the scene. Such sprites can be used hierarchically within +-- the definitions of other sprites, via the function renderSprite. +newSpritePart :: Frame s SVG -> Scene s (Sprite s) +newSpritePart render = do now <- queryNow tmod <- liftST $ newSTRef id - ref <- liftST $ newSTRef (-1, return $ \_d _t svg -> (svg, 0)) - addGen $ do + ref <- liftST $ newSTRef (-1, return $ \_ad _d _t svg -> (svg, 0)) + return $ Sprite now tmod ref $ do fn <- unFrame render time_fn <- readSTRef tmod (spriteDur, spriteEffectGen) <- readSTRef ref spriteEffect <- spriteEffectGen - return $ \d absT_ -> + return $ \absD absT_ -> let absT = time_fn absT_ - relD = (if spriteDur < 0 then d else spriteDur) - now + relD = (if spriteDur < 0 then absD else spriteDur) - now relT = absT - now -- Sprite is live [now;duration[ -- If we're at the end of a scene, sprites @@ -131,11 +140,13 @@ newSprite render = do -- This behavior is difficult to get right. See the 'bug_*' examples for -- automated tests. inTimeSlice = relT >= 0 && relT < relD - isLastFrame = d == absT && relT == relD - in if inTimeSlice || isLastFrame - then spriteEffect relD relT (fn absT relD relT) + isLastFrame = absD == absT && relT == relD + in if inTimeSlice || isLastFrame + then spriteEffect absD relD relT (fn absD absT relD relT) else (None, 0) - return $ Sprite now tmod ref + +addPartToScene :: Sprite s -> Scene s () +addPartToScene (Sprite _ _ _ gen) = addGen gen -- | Create new sprite defined by a frame generator. The sprite will die at -- the end of the scene. @@ -197,6 +208,15 @@ newSpriteSVG = newSprite . pure newSpriteSVG_ :: SVG -> Scene s () newSpriteSVG_ = void . newSpriteSVG +-- | Create a frame context from the source sprite for use within another. Use of this +-- function allows several sprites to be combined into a single one, with the +-- method of combination controled by variables. +renderSprite :: Sprite s -> Frame s SVG +renderSprite (Sprite _ _ _ gen) = + Frame $ do + genFn <- gen + return (\absD absT _ _ -> fst $ genFn absD absT) + -- | Change the rendering of a sprite using data from a variable. If data from several variables -- is needed, use a frame generator instead. -- @@ -228,7 +248,7 @@ applyVar var sprite fn = spriteModify sprite $ do -- -- <> destroySprite :: Sprite s -> Scene s () -destroySprite (Sprite _ _tmod ref) = do +destroySprite (Sprite _ _tmod ref _) = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, render) -> @@ -236,19 +256,19 @@ destroySprite (Sprite _ _tmod ref) = do -- | Low-level frame modifier. spriteModify :: Sprite s -> Frame s ((SVG, ZIndex) -> (SVG, ZIndex)) -> Scene s () -spriteModify (Sprite born _tmod ref) modFn = liftST $ +spriteModify (Sprite born _tmod ref _) modFn = liftST $ modifySTRef ref $ \(ttl, renderGen) -> ( ttl, do render <- renderGen modRender <- unFrame modFn - return $ \relD relT -> - let absT = relT + born in modRender absT relD relT . render relD relT + return $ \absD relD relT -> + let absT = relT + born in modRender absD absT relD relT . render absD relD relT ) -- | Apply easing function before rendering sprite. signalS :: Sprite s -> Duration -> Signal -> Scene s () -signalS (Sprite _born tmod _ref) dur signal = do +signalS (Sprite _born tmod _ref _) dur signal = do now <- queryNow let modify_t t | t < now = t @@ -271,7 +291,7 @@ signalS (Sprite _born tmod _ref) dur signal = do -- -- <> spriteMap :: Sprite s -> (SVG -> SVG) -> Scene s () -spriteMap sprite@(Sprite born _ _) fn = do +spriteMap sprite@(Sprite born _ _ _) fn = do now <- queryNow let tDelta = now - born spriteModify sprite $ do @@ -289,7 +309,7 @@ spriteMap sprite@(Sprite born _ _) fn = do -- -- <> spriteTween :: Sprite s -> Duration -> (Double -> SVG -> SVG) -> Scene s () -spriteTween sprite@(Sprite born _ _) dur fn = do +spriteTween sprite@(Sprite born _ _ _) dur fn = do now <- queryNow let tDelta = now - born spriteModify sprite $ do @@ -331,15 +351,15 @@ spriteVar sprite def fn = do -- -- <> spriteE :: Sprite s -> Effect -> Scene s () -spriteE (Sprite born _tmod ref) effect = do +spriteE (Sprite born _tmod ref _) effect = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, renderGen) -> ( ttl, do render <- renderGen - return $ \d t svg -> - let (svg', z) = render d t svg + return $ \ad d t svg -> + let (svg', z) = render ad d t svg in (delayE (max 0 $ now - born) effect d t svg', z) ) @@ -357,15 +377,15 @@ spriteE (Sprite born _tmod ref) effect = do -- -- <> spriteZ :: Sprite s -> ZIndex -> Scene s () -spriteZ (Sprite born _tmod ref) zindex = do +spriteZ (Sprite born _tmod ref _) zindex = do now <- queryNow liftST $ modifySTRef ref $ \(ttl, renderGen) -> ( ttl, do render <- renderGen - return $ \d t svg -> - let (svg', z) = render d t svg in (svg', if t < now - born then z else zindex) + return $ \ad d t svg -> + let (svg', z) = render ad d t svg in (svg', if t < now - born then z else zindex) ) -- | Destroy all local sprites at the end of a scene. From f58a00e56a0209ee97763a1dc0b5e523435fd62e Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 2 Jun 2022 20:09:15 +0200 Subject: [PATCH 104/114] Disable hgeometry dependency and bump version. (#282) --- .azure/azure-linux-template.yml | 2 +- ChangeLog.md | 3 +++ reanimate.cabal | 17 +++-------------- src/Reanimate/PolyShape.hs | 3 ++- stack-lts-14.yaml | 2 -- stack-lts-15.yaml | 2 -- stack-lts-16.yaml | 2 -- stack-lts-17.yaml | 2 -- test/Properties.hs | 12 +++++++++++- 9 files changed, 20 insertions(+), 25 deletions(-) diff --git a/.azure/azure-linux-template.yml b/.azure/azure-linux-template.yml index 554a6f3..2911dac 100644 --- a/.azure/azure-linux-template.yml +++ b/.azure/azure-linux-template.yml @@ -24,7 +24,7 @@ jobs: steps: - task: Cache@2 inputs: - key: ${{ parameters.name }} | ${{ parameters.vmImage }} | $(ARGS) | $(STACK_YAML) | stack-root | $(Agent.OS) + key: ${{ parameters.name }} | ${{ parameters.vmImage }} | $(ARGS) | $(STACK_YAML) | stack-root | $(Agent.OS) | v2 path: $(STACK_ROOT) cacheHitVar: CACHE_RESTORED displayName: Cache stack root diff --git a/ChangeLog.md b/ChangeLog.md index e25c6ea..c37c960 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,6 +5,9 @@ Notable changes to the project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and the project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org) +## 1.1.6.0 -- 2022-06-02 + + * Drop hgeometry dependency. ## 1.1.4.0 -- 2021-03-11 diff --git a/reanimate.cabal b/reanimate.cabal index 4a6e626..d494745 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.5.0 +version: 1.1.6.0 -- synopsis: -- description: license: PublicDomain @@ -37,13 +37,6 @@ Source-Repository head Type: git Location: git://github.com/lemmih/reanimate.git -flag no-hgeometry - description: - Disable all features that depend on hgeometry. Should only - be used when developing new hgeometry algorithms. - default: False - manual: True - library hs-source-dirs: src if os(windows) @@ -113,12 +106,7 @@ library Detach POVRay autogen-modules: Paths_reanimate - if flag(no-hgeometry) - cpp-options: -DNO_HGEOMETRY - else - build-depends: - hgeometry >=0.11.0.0 && < 0.14, - hgeometry-combinatorial >=0.11.0.0 && < 0.14 + cpp-options: -DNO_HGEOMETRY build-depends: base >=4.10 && <5, JuicyPixels >=3.3.3, @@ -178,6 +166,7 @@ test-suite spec Helpers hs-source-dirs: test ghc-options: -w + cpp-options: -DNO_HGEOMETRY build-depends: base, directory, diff --git a/src/Reanimate/PolyShape.hs b/src/Reanimate/PolyShape.hs index 9d6b2b3..9dc7264 100644 --- a/src/Reanimate/PolyShape.hs +++ b/src/Reanimate/PolyShape.hs @@ -41,7 +41,7 @@ module Reanimate.PolyShape , plGroupTouching ) where -import Control.Lens ((&), (.~), (^.)) +import Control.Lens ((&), (.~)) import Data.List (nub, partition, sortOn) import qualified Data.Vector as V import Geom2D.CubicBezier.Linear (ClosedPath (..), @@ -67,6 +67,7 @@ import Reanimate.Math.Polygon (Polygon, import Reanimate.Svg #if !defined(NO_HGEOMETRY) +import Control.Lens ((^.)) import Algorithms.Geometry.PolygonTriangulation.Triangulate (triangulate') import Data.Ext diff --git a/stack-lts-14.yaml b/stack-lts-14.yaml index 837d598..1c40eb5 100644 --- a/stack-lts-14.yaml +++ b/stack-lts-14.yaml @@ -14,8 +14,6 @@ extra-deps: - hmatrix-0.20.0.0@sha256:d79a9218e314f1a2344457c3851bd1d2536518ecb5f1a2fcd81daa45e46cd025,4870 - earcut-0.1.0.4@sha256:d5118b3eecf24d130263d81fb30f1ff56b1db43036582bfd1d8cc9ba3adae8be,1010 - tasty-rerun-1.1.17@sha256:d4a3ccb0f63f499f36edc71b33c0f91c850eddb22dd92b928aa33b8459f3734a,1373 -- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 -- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 - hashable-1.3.0.0@sha256:4c70f1407881059e93550d3742191254296b2737b793a742bd901348fb3e1fb1,5206 - network-3.1.2.1@sha256:188d6daea8cd91bc3553efd5a90a1e7c6d0425fa66a53baa74db5b6d9fd75c8b,4968 diff --git a/stack-lts-15.yaml b/stack-lts-15.yaml index 9e6aabd..8f8e83e 100644 --- a/stack-lts-15.yaml +++ b/stack-lts-15.yaml @@ -9,6 +9,4 @@ extra-deps: - chiphunk-0.1.2.1 - earcut-0.1.0.4@sha256:d5118b3eecf24d130263d81fb30f1ff56b1db43036582bfd1d8cc9ba3adae8be,1010 - reanimate-svg-0.13.0.1 -- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 -- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/stack-lts-16.yaml b/stack-lts-16.yaml index bc0abd4..77144f3 100644 --- a/stack-lts-16.yaml +++ b/stack-lts-16.yaml @@ -8,6 +8,4 @@ packages: extra-deps: - earcut-0.1.0.4 - reanimate-svg-0.13.0.1 -- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 -- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/stack-lts-17.yaml b/stack-lts-17.yaml index 720acd2..2135ef1 100644 --- a/stack-lts-17.yaml +++ b/stack-lts-17.yaml @@ -8,6 +8,4 @@ packages: extra-deps: - earcut-0.1.0.4 - reanimate-svg-0.13.0.1 -- hgeometry-0.11.0.0@sha256:09ead201a6ac3492c0be8dda5a6b32792b9ae87cab730b8362d46ee8d5c2acb4,11714 -- hgeometry-combinatorial-0.11.0.0@sha256:03176f235a1c49a415fe1266274dafca84deb917cbcbf9a654452686b4cd2bfe,8286 - vinyl-0.13.0@sha256:0f247cd3f8682b30881a07de18e6fec52d540646fbcb328420049cc8d63cd407,3724 diff --git a/test/Properties.hs b/test/Properties.hs index 53a4e7f..21dcf20 100644 --- a/test/Properties.hs +++ b/test/Properties.hs @@ -1,13 +1,17 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# OPTIONS_GHC -w #-} {-# LANGUAGE TemplateHaskell #-} module Properties where +import Test.Tasty + +#if !defined(NO_HGEOMETRY) + import qualified Data.Vector as V import Linear.V2 import Linear.Vector import Test.QuickCheck -import Test.Tasty import Test.Tasty.QuickCheck import Reanimate.Math.Common @@ -18,6 +22,8 @@ import Helpers import Debug.Trace + + prop_pGenerate (PolyParam a) (PolyParam b) (PolyParam c) (PolyParam d) = pIsSimple $ pGenerate [a,b,c,d] @@ -87,3 +93,7 @@ prop_dualCycle p = forAll (choose (0,pSize p-1)) $ \n -> return [] all_props :: TestTree all_props = testProperties "properties" $allProperties +#else +all_props :: TestTree +all_props = testGroup "properties" [] +#endif From a1d946c1b9a56912cc9604c557f7dc9ac5b3dca6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 14:06:05 +0200 Subject: [PATCH 105/114] Bump actions/cache from 3.0.3 to 3.0.4 (#283) Bumps [actions/cache](https://github.com/actions/cache) from 3.0.3 to 3.0.4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.3...v3.0.4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index cb25dd9..c1137ff 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,7 +19,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.3 + uses: actions/cache@v3.0.4 with: path: | ~/.cabal diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index a029572..29f6643 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -19,7 +19,7 @@ jobs: cabal-version: '3.0' - name: Cache - uses: actions/cache@v3.0.3 + uses: actions/cache@v3.0.4 env: cache-name: cache-cabal with: diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index 7cc93dc..7c9e2b7 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -20,7 +20,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.3 + uses: actions/cache@v3.0.4 with: path: | ~/.stack From d0263d15aadb57c65b062be64330d96f881b8c2d Mon Sep 17 00:00:00 2001 From: Anjali Smith <93302754+as0501@users.noreply.github.com> Date: Sun, 12 Jun 2022 05:56:42 -0400 Subject: [PATCH 106/114] Fork() and Waitpid() Simulator (#288) Co-authored-by: Anjali Smith --- examples/waitpid_simulator.hs | 129 ++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 examples/waitpid_simulator.hs diff --git a/examples/waitpid_simulator.hs b/examples/waitpid_simulator.hs new file mode 100644 index 0000000..959d340 --- /dev/null +++ b/examples/waitpid_simulator.hs @@ -0,0 +1,129 @@ +#!/usr/bin/env stack +-- stack runghc --package reanimate +module Main (main) where + +import Reanimate +import Reanimate.Builtin.Documentation +import Reanimate.Scene +import Data.Text (Text) +import qualified Data.Text as T +import Control.Lens +import Graphics.SvgTree hiding (Point, Text) + +customDuration :: Duration +customDuration = 3 +data Point = Point Double Double +data Segment = Segment Point Point + +-- Helper functions creating an Animation from two coordinates +animatePart :: Segment -> Animation +animatePart (Segment (Point startx starty) (Point endx endy)) = signalA (curveS 2) $ setDuration customDuration $ + animate $ \t -> + partialSvg t $ pathify (mkLine (startx, starty) (endx, endy) & strokeLineCap .~ (pure CapSquare)) + +-- Helper function to create coordinates for a specific line +splitSegments :: Segment -> Int -> [Segment] +splitSegments seg numSegs = + let firstSeg = getFirstSeg seg numSegs + in take numSegs (iterate shiftSeg firstSeg) + +-- Helper function to create the first smaller segment in a large segment +getFirstSeg :: Segment -> Int -> Segment +getFirstSeg (Segment (Point startx starty) (Point endx endy)) numSegs + = Segment (Point startx starty) (Point ( startx + ((endx - startx)/(fromIntegral numSegs))) ( starty + ((endy - starty)/(fromIntegral numSegs)))) + +-- Helper function to shift a segment to the right by the size of itself +shiftSeg :: Segment -> Segment +shiftSeg (Segment (Point startx starty) (Point endx endy)) + = Segment (Point endx endy) (Point (endx + (endx-startx)) (endy + (endy-starty))) + +-- Helper function to animate the line segment that represents a fork +animateFork :: Segment -> Animation +animateFork (Segment (Point startx starty) (Point endx endy)) + = oFadeIn (mkLine (startx,starty) (endx, endy)) + +-- Helper function to label a proccess with a pid +labelPids :: Segment -> Int -> SVG +labelPids (Segment (Point startx starty) (Point _ _)) i = withStrokeWidth (defaultStrokeWidth * 0.5) $ withFillOpacity 1 $ mkGroup + [translate (startx - 0.75) (starty) $ scale 0.25 $ outlineText $T.pack("pid: " ++ (show i))] + +-- Helper function to position a line of text +mkTextLabel:: [Char] -> Point -> SVG +mkTextLabel txt (Point startx starty) = withStrokeWidth (defaultStrokeWidth * 0.5) $ withFillOpacity 1 $ mkGroup + [translate (startx) (starty) $ scale 0.2 $ outlineText $ T.pack(txt)] + +mkPrintLabelFromPnt :: Point -> [Char] -> Animation +mkPrintLabelFromPnt pnt txt = + oFadeIn $ mkTextLabel ("printf(" ++ (show txt) ++ ")" ) pnt +-- Helper function to speed up an animation +speedUpAnimation :: Animation -> Animation +speedUpAnimation anim = adjustDuration (*0.5) anim + +-- Helper function to label a fork() call and its return value +mkForkLabel :: Point -> Int -> Animation +mkForkLabel point val = oFadeIn (mkTextLabel ("fork() = " ++ (show val) ) point) + +-- Helper function that creates waitpid() call label +mkWaitpidLabel :: Point -> Animation +mkWaitpidLabel pnt = oFadeIn $ mkTextLabel "waitpid(1001, NULL, 0)" pnt + +-- Helper function that creates an SVG of outlined text +outlineText :: Text -> SVG +outlineText txt = mkGroup + [ center + $ withStrokeColorPixel rtfdBackgroundColor + $ withStrokeWidth (defaultStrokeWidth * 8) + $ withFillOpacity 0 + $ latex txt + , withStrokeWidth 0 $ withFillOpacity 1 $ center $ latex txt + ] + +main :: IO () +main = reanimate + $ docEnv + $ ((pidLabelAnimations !! 0) `parA` (parentAnimations !! 0)) + `andThen` ((forkLabelAnims !! 0) `parA` (forkAnimation)) + `andThen` (forkLabelAnims !! 1) + `andThen` ((pidLabelAnimations !! 1) `parA` (childAnimations !! 0) `parA` waitpidLabelAnim) + `andThen` (childPrintfLabelAnim) + `andThen` (parentAnimations !! 1) + `andThen` (parentPrintfLabelAnim) + +--Lists of segments that represent each proccess +parentSegments :: [Segment] +parentSegments = splitSegments (Segment (Point (-6) 0) (Point 6 0)) 2 + +childSegments :: [Segment] +childSegments = splitSegments (Segment (Point 0 (-3)) (Point 6 (-3))) 1 + +forkSegment :: Segment +forkSegment = Segment (Point 0 0) (Point 0 (-3)) + +--Lists of animations for each line +parentAnimations :: [Animation] +parentAnimations = map animatePart parentSegments + +childAnimations :: [Animation] +childAnimations = map animatePart childSegments + +forkAnimation :: Animation +forkAnimation = animateFork forkSegment + +--List of animations to label each proccess with its PID +pidLabelAnimations :: [Animation] +pidLabelAnimations = [speedUpAnimation (oFadeIn (labelPids (parentSegments !! 0) 1000)), speedUpAnimation (oFadeIn (labelPids (childSegments !! 0) 1001))] + +--List of animations to label the fork() calls +forkLabelAnims :: [Animation] +forkLabelAnims = [mkForkLabel (Point (0) 0.25) 1001, mkForkLabel (Point (0) (-2.75)) 0] + +-- Animation to label the waitpid() call +waitpidLabelAnim :: Animation +waitpidLabelAnim = mkWaitpidLabel (Point (0.75) (0.5)) + +-- Animation to label printf() +parentPrintfLabelAnim :: Animation +parentPrintfLabelAnim = mkPrintLabelFromPnt (Point (5) (0.25)) "I'm the parent, and I'm done waiting!" + +childPrintfLabelAnim :: Animation +childPrintfLabelAnim = mkPrintLabelFromPnt (Point (5) (-2.75)) "I'm the child!" From 4a3ec6b43febf53584de6dfce6e2bd1f35f30af6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Jun 2022 14:53:04 +0200 Subject: [PATCH 107/114] Bump JamesIves/github-pages-deploy-action from 4.3.3 to 4.3.4 (#289) Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.3.3 to 4.3.4. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/v4.3.3...v4.3.4) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index c1137ff..ec30643 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -102,7 +102,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.3.3 + uses: JamesIves/github-pages-deploy-action@v4.3.4 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From c95b0fe9c2035fbc8855a2ddbfeb6a78e0cb3d80 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Jul 2022 13:25:51 +0200 Subject: [PATCH 108/114] Bump actions/cache from 3.0.4 to 3.0.5 (#290) Bumps [actions/cache](https://github.com/actions/cache) from 3.0.4 to 3.0.5. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.4...v3.0.5) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index ec30643..470c980 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,7 +19,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.4 + uses: actions/cache@v3.0.5 with: path: | ~/.cabal diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index 29f6643..b05fe68 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -19,7 +19,7 @@ jobs: cabal-version: '3.0' - name: Cache - uses: actions/cache@v3.0.4 + uses: actions/cache@v3.0.5 env: cache-name: cache-cabal with: diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index 7c9e2b7..b431e16 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -20,7 +20,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.4 + uses: actions/cache@v3.0.5 with: path: | ~/.stack From 4a5f60865466954615321c48e0e9b7d0ef4b7445 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Jul 2022 14:05:06 +0200 Subject: [PATCH 109/114] Bump JamesIves/github-pages-deploy-action from 4.3.4 to 4.4.0 (#291) Bumps [JamesIves/github-pages-deploy-action](https://github.com/JamesIves/github-pages-deploy-action) from 4.3.4 to 4.4.0. - [Release notes](https://github.com/JamesIves/github-pages-deploy-action/releases) - [Commits](https://github.com/JamesIves/github-pages-deploy-action/compare/v4.3.4...v4.4.0) --- updated-dependencies: - dependency-name: JamesIves/github-pages-deploy-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 470c980..f844ee4 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -102,7 +102,7 @@ jobs: cp dist/* $CWD/pages/playground/ - name: Deploy 🚀 - uses: JamesIves/github-pages-deploy-action@v4.3.4 + uses: JamesIves/github-pages-deploy-action@v4.4.0 with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} BRANCH: gh-pages # The branch the action should deploy to. From d4d3898831edb4aa2182701fd83452cd991cdd54 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 12 Oct 2022 16:00:23 +0200 Subject: [PATCH 110/114] Bump actions/cache from 3.0.5 to 3.0.10 (#296) Bumps [actions/cache](https://github.com/actions/cache) from 3.0.5 to 3.0.10. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3.0.5...v3.0.10) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index f844ee4..318c54a 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,7 +19,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.5 + uses: actions/cache@v3.0.10 with: path: | ~/.cabal diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index b05fe68..deb9920 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -19,7 +19,7 @@ jobs: cabal-version: '3.0' - name: Cache - uses: actions/cache@v3.0.5 + uses: actions/cache@v3.0.10 env: cache-name: cache-cabal with: diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index b431e16..8a11955 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -20,7 +20,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.5 + uses: actions/cache@v3.0.10 with: path: | ~/.stack From 7d949ea0eac379007da11b48f77012661115e9a1 Mon Sep 17 00:00:00 2001 From: AndreasPK Date: Wed, 21 Dec 2022 12:21:48 +0100 Subject: [PATCH 111/114] Fix build for ghc-9.2 (#301) * Fix builds against hashable >= 1.4 Derive Eq for APolygon as required by the added Eq constraint on Hashable. * Bump version to 1.1.7 for new instance, relax aeson bounds. --- ChangeLog.md | 5 +++++ reanimate.cabal | 4 ++-- src/Reanimate/Math/Polygon.hs | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index c37c960..cff4d03 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -5,6 +5,11 @@ Notable changes to the project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and the project adheres to the [Haskell Package Versioning Policy (PVP)](https://pvp.haskell.org) + +## 1.1.7.0 -- 2022-10-15 + + * Derive `Eq` for APolygon + ## 1.1.6.0 -- 2022-06-02 * Drop hgeometry dependency. diff --git a/reanimate.cabal b/reanimate.cabal index d494745..3b6fdb3 100644 --- a/reanimate.cabal +++ b/reanimate.cabal @@ -3,7 +3,7 @@ cabal-version: 2.0 -- see http://haskell.org/cabal/users-guide/ name: reanimate -version: 1.1.6.0 +version: 1.1.7.0 -- synopsis: -- description: license: PublicDomain @@ -110,7 +110,7 @@ library build-depends: base >=4.10 && <5, JuicyPixels >=3.3.3, - aeson >=1.3.0.0 && <2, + aeson >=1.3.0.0 && <2.2, ansi-terminal >=0.8.0.4, array >=0.5.2.0, attoparsec >=0.13.2.0, diff --git a/src/Reanimate/Math/Polygon.hs b/src/Reanimate/Math/Polygon.hs index 2a62276..2b79c54 100644 --- a/src/Reanimate/Math/Polygon.hs +++ b/src/Reanimate/Math/Polygon.hs @@ -115,7 +115,7 @@ data APolygon a = Polygon , polygonOffset :: Int , polygonTriangulation :: Triangulation , polygonSSSP :: Vector SSSP - } + } deriving Eq type Polygon = APolygon Rational type P = V2 Double From d8e853b1b734eabb3e8b5dfc13093a06626e20a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Dec 2022 12:22:12 +0100 Subject: [PATCH 112/114] Bump actions/cache from 3.0.10 to 3.0.11 (#297) --- .github/workflows/gh-pages.yml | 2 +- .github/workflows/haskell.yml | 2 +- .github/workflows/playground.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml index 318c54a..5992998 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -19,7 +19,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.10 + uses: actions/cache@v3.0.11 with: path: | ~/.cabal diff --git a/.github/workflows/haskell.yml b/.github/workflows/haskell.yml index deb9920..ee97e90 100644 --- a/.github/workflows/haskell.yml +++ b/.github/workflows/haskell.yml @@ -19,7 +19,7 @@ jobs: cabal-version: '3.0' - name: Cache - uses: actions/cache@v3.0.10 + uses: actions/cache@v3.0.11 env: cache-name: cache-cabal with: diff --git a/.github/workflows/playground.yml b/.github/workflows/playground.yml index 8a11955..851d679 100644 --- a/.github/workflows/playground.yml +++ b/.github/workflows/playground.yml @@ -20,7 +20,7 @@ jobs: elm-version: 0.19.1 - name: Cache - uses: actions/cache@v3.0.10 + uses: actions/cache@v3.0.11 with: path: | ~/.stack From 82638c078c2f62838d8b6cf77a6a138cf37d2f77 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Dec 2022 12:22:43 +0100 Subject: [PATCH 113/114] Bump qs from 6.5.2 to 6.5.3 in /viewer-elm (#302) --- viewer-elm/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/viewer-elm/package-lock.json b/viewer-elm/package-lock.json index 8dc980a..186da44 100644 --- a/viewer-elm/package-lock.json +++ b/viewer-elm/package-lock.json @@ -926,9 +926,9 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" }, "range-parser": { "version": "1.2.1", From 583ee9f426bb96ac15996772a6fd7ccf0caf08a7 Mon Sep 17 00:00:00 2001 From: David Himmelstrup Date: Thu, 6 Feb 2025 19:32:19 +0100 Subject: [PATCH 114/114] remove invalid site checking workflow --- .github/workflows/site-checks.yml | 41 ------------------------------- 1 file changed, 41 deletions(-) delete mode 100644 .github/workflows/site-checks.yml diff --git a/.github/workflows/site-checks.yml b/.github/workflows/site-checks.yml deleted file mode 100644 index 1bfdec2..0000000 --- a/.github/workflows/site-checks.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: Site checker - -on: - schedule: - - cron: "0 * * * *" - push: - branches: [ master, feature-ci ] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js 10.x - uses: actions/setup-node@v3 - with: - node-version: 10.x - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get -y install w3c-linkchecker - - name: Check websocket connection - run: | - set -o xtrace - wget https://github.com/vi/websocat/releases/download/v1.6.0/websocat_amd64-linux-static -O websocat - chmod +x websocat - ./websocat -q -uU "wss://reanimate.clozecards.com/ws/" - - name: Check links at reanimate.github.io - run: checklink --quiet --broken "https://reanimate.github.io/" >> failures.txt - - name: Check links at reanimate.readthedocs.io - run: checklink --quiet --broken "https://reanimate.readthedocs.io/" --suppress-broken 403:https://inkscape.org/ --suppress-broken 403:https://wiki.gnome.org/Projects/LibRsvg >> failures.txt - # Haddock generates 404 links by default. :( - #- name: Check links in haddock docs - # run: checklink --quiet --broken "https://hackage.haskell.org/package/reanimate/docs/Reanimate.html" >> failures.txt - - name: Check for failures - run: | - if [ -s failures.txt ]; then - cat failures.txt - exit 1 - fi