mirror of
https://gitlab.com/sheaf/metabrush.git
synced 2024-11-05 14:53:37 +00:00
encode/decode documents to JSON using waargonaut
This commit is contained in:
parent
9c5f8b1198
commit
8a6b4f5391
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,3 +10,4 @@ img/examples
|
||||||
*.md
|
*.md
|
||||||
*.html
|
*.html
|
||||||
hie.yaml
|
hie.yaml
|
||||||
|
*.mb
|
||||||
|
|
|
@ -82,8 +82,6 @@ library
|
||||||
^>= 0.20.0.0
|
^>= 0.20.0.0
|
||||||
, vector
|
, vector
|
||||||
^>= 0.12.1.2
|
^>= 0.12.1.2
|
||||||
, QuickCheck
|
|
||||||
^>= 2.14.1
|
|
||||||
|
|
||||||
executable MetaBrush
|
executable MetaBrush
|
||||||
|
|
||||||
|
@ -109,6 +107,7 @@ executable MetaBrush
|
||||||
, MetaBrush.Document
|
, MetaBrush.Document
|
||||||
, MetaBrush.Document.Draw
|
, MetaBrush.Document.Draw
|
||||||
, MetaBrush.Document.Selection
|
, MetaBrush.Document.Selection
|
||||||
|
, MetaBrush.Document.Serialise
|
||||||
, MetaBrush.Event
|
, MetaBrush.Event
|
||||||
, MetaBrush.Event.KeyCodes
|
, MetaBrush.Event.KeyCodes
|
||||||
, MetaBrush.Render.Document
|
, MetaBrush.Render.Document
|
||||||
|
@ -132,10 +131,10 @@ executable MetaBrush
|
||||||
|
|
||||||
build-depends:
|
build-depends:
|
||||||
MetaBrush
|
MetaBrush
|
||||||
|
, bytestring
|
||||||
|
^>= 0.10.10.1
|
||||||
, directory
|
, directory
|
||||||
>= 1.3.4.0 && < 1.4
|
>= 1.3.4.0 && < 1.4
|
||||||
--, fingertree
|
|
||||||
-- >= 0.1.4.2 && < 0.2
|
|
||||||
, gi-gdk
|
, gi-gdk
|
||||||
>= 3.0.22 && < 3.1
|
>= 3.0.22 && < 3.1
|
||||||
, gi-gio
|
, gi-gio
|
||||||
|
@ -152,9 +151,13 @@ executable MetaBrush
|
||||||
^>= 0.24
|
^>= 0.24
|
||||||
, lens
|
, lens
|
||||||
^>= 4.19.2
|
^>= 4.19.2
|
||||||
|
, scientific
|
||||||
|
^>= 0.3.6.2
|
||||||
, stm
|
, stm
|
||||||
^>= 2.5.0.0
|
^>= 2.5.0.0
|
||||||
, tardis
|
, tardis
|
||||||
^>= 0.4.1.0
|
^>= 0.4.1.0
|
||||||
, text
|
, text
|
||||||
^>= 1.2.3.1 && < 1.2.5
|
^>= 1.2.3.1 && < 1.2.5
|
||||||
|
, waargonaut
|
||||||
|
^>= 0.8.0.1
|
||||||
|
|
34
app/Main.hs
34
app/Main.hs
|
@ -102,31 +102,51 @@ testDocuments = IntMap.fromList
|
||||||
$ zip [0..]
|
$ zip [0..]
|
||||||
[ Document
|
[ Document
|
||||||
{ displayName = "Closed"
|
{ displayName = "Closed"
|
||||||
, filePath = Nothing
|
, mbFilePath = Nothing
|
||||||
, unsavedChanges = False
|
, unsavedChanges = False
|
||||||
, strokes = [ Stroke ( ellipse 150 100 ( PointData Normal ( rect 30 6 $ BrushPointData Normal ) ) ) "Ellipse" True ( unsafeUnique 0 )
|
|
||||||
]
|
|
||||||
, bounds = AABB ( Point2D 0 0 ) ( Point2D 100 100 )
|
, bounds = AABB ( Point2D 0 0 ) ( Point2D 100 100 )
|
||||||
, viewportCenter = Point2D 50 50
|
, viewportCenter = Point2D 50 50
|
||||||
, zoomFactor = 1
|
, zoomFactor = 1
|
||||||
|
, documentUnique = unsafeUnique 0
|
||||||
|
, strokes = [ Stroke
|
||||||
|
{ strokeName = "Ellipse"
|
||||||
|
, strokeVisible = True
|
||||||
|
, strokeUnique = unsafeUnique 10
|
||||||
|
, strokePoints = ellipse 150 100 ( PointData Normal ( rect 30 6 $ BrushPointData Normal ) )
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
, Document
|
, Document
|
||||||
{ displayName = "Line"
|
{ displayName = "Line"
|
||||||
, filePath = Nothing
|
, mbFilePath = Nothing
|
||||||
, unsavedChanges = True
|
, unsavedChanges = True
|
||||||
, strokes = [ Stroke linePts "Line" True ( unsafeUnique 1 ) ]
|
|
||||||
, bounds = AABB ( Point2D 0 0 ) ( Point2D 50 50 )
|
, bounds = AABB ( Point2D 0 0 ) ( Point2D 50 50 )
|
||||||
, viewportCenter = Point2D 0 0
|
, viewportCenter = Point2D 0 0
|
||||||
, zoomFactor = 1
|
, zoomFactor = 1
|
||||||
|
, documentUnique = unsafeUnique 1
|
||||||
|
, strokes = [ Stroke
|
||||||
|
{ strokeName = "Line"
|
||||||
|
, strokeVisible = True
|
||||||
|
, strokeUnique = unsafeUnique 11
|
||||||
|
, strokePoints = linePts
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
, Document
|
, Document
|
||||||
{ displayName = "Short line"
|
{ displayName = "Short line"
|
||||||
, filePath = Nothing
|
, mbFilePath = Nothing
|
||||||
, unsavedChanges = False
|
, unsavedChanges = False
|
||||||
, strokes = [ Stroke linePts2 "ShortLine" True ( unsafeUnique 2 ) ]
|
|
||||||
, bounds = AABB ( Point2D 0 0 ) ( Point2D 50 50 )
|
, bounds = AABB ( Point2D 0 0 ) ( Point2D 50 50 )
|
||||||
, viewportCenter = Point2D 0 0
|
, viewportCenter = Point2D 0 0
|
||||||
, zoomFactor = 1
|
, zoomFactor = 1
|
||||||
|
, documentUnique = unsafeUnique 2
|
||||||
|
, strokes = [ Stroke
|
||||||
|
{ strokeName = "ShortLine"
|
||||||
|
, strokeVisible = True
|
||||||
|
, strokeUnique = unsafeUnique 12
|
||||||
|
, strokePoints = linePts2
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
where
|
where
|
||||||
|
|
|
@ -3,6 +3,9 @@ packages: .
|
||||||
constraints:
|
constraints:
|
||||||
acts -finitary
|
acts -finitary
|
||||||
|
|
||||||
|
allow-newer:
|
||||||
|
waargonaut:*
|
||||||
|
|
||||||
-- fixes gi-cairo-render to work with haskell-gi >= 0.24
|
-- fixes gi-cairo-render to work with haskell-gi >= 0.24
|
||||||
source-repository-package
|
source-repository-package
|
||||||
type: git
|
type: git
|
||||||
|
@ -16,3 +19,9 @@ source-repository-package
|
||||||
location: https://github.com/haskell-numerics/hmatrix
|
location: https://github.com/haskell-numerics/hmatrix
|
||||||
tag: 08138810946c7eae2254feeb33269cd962d5e0c8
|
tag: 08138810946c7eae2254feeb33269cd962d5e0c8
|
||||||
subdir: packages/base
|
subdir: packages/base
|
||||||
|
|
||||||
|
-- adds MonadTrans Decoder instance to waargonaut Decoder
|
||||||
|
source-repository-package
|
||||||
|
type: git
|
||||||
|
location: https://github.com/sheaf/waargonaut
|
||||||
|
tag: dc835fb86d2592fa2e55753fa4eb7c59d6124699
|
||||||
|
|
|
@ -64,21 +64,22 @@ data AABB
|
||||||
data Document
|
data Document
|
||||||
= Document
|
= Document
|
||||||
{ displayName :: !Text
|
{ displayName :: !Text
|
||||||
, filePath :: !( Maybe FilePath )
|
, mbFilePath :: !( Maybe FilePath )
|
||||||
, unsavedChanges :: !Bool
|
, unsavedChanges :: !Bool
|
||||||
, strokes :: ![ Stroke ]
|
|
||||||
, bounds :: !AABB
|
, bounds :: !AABB
|
||||||
, viewportCenter :: !( Point2D Double )
|
, viewportCenter :: !( Point2D Double )
|
||||||
, zoomFactor :: !Double
|
, zoomFactor :: !Double
|
||||||
|
, documentUnique :: Unique
|
||||||
|
, strokes :: ![ Stroke ]
|
||||||
}
|
}
|
||||||
deriving stock ( Show, Generic )
|
deriving stock ( Show, Generic )
|
||||||
|
|
||||||
data Stroke
|
data Stroke
|
||||||
= Stroke
|
= Stroke
|
||||||
{ strokePoints :: !( Seq ( StrokePoint PointData ) )
|
{ strokeName :: Text
|
||||||
, strokeName :: Text
|
|
||||||
, strokeVisible :: !Bool
|
, strokeVisible :: !Bool
|
||||||
, strokeUnique :: Unique
|
, strokeUnique :: Unique
|
||||||
|
, strokePoints :: !( Seq ( StrokePoint PointData ) )
|
||||||
}
|
}
|
||||||
deriving stock ( Show, Generic )
|
deriving stock ( Show, Generic )
|
||||||
|
|
||||||
|
|
|
@ -84,10 +84,11 @@ getDrawAnchor uniqueSupply c doc@( Document { zoomFactor } ) =
|
||||||
newDoc' =
|
newDoc' =
|
||||||
over ( field' @"strokes" )
|
over ( field' @"strokes" )
|
||||||
( Stroke
|
( Stroke
|
||||||
( Seq.singleton $ PathPoint c ( PointData Normal Empty ) )
|
{ strokeName = "Stroke " <> uniqueText uniq
|
||||||
( "Stroke " <> uniqueText uniq )
|
, strokeVisible = True
|
||||||
True
|
, strokeUnique = uniq
|
||||||
uniq
|
, strokePoints = Seq.singleton $ PathPoint c ( PointData Normal Empty )
|
||||||
|
}
|
||||||
: )
|
: )
|
||||||
newDoc
|
newDoc
|
||||||
pure ( newDoc', AnchorAtEnd uniq, c )
|
pure ( newDoc', AnchorAtEnd uniq, c )
|
||||||
|
|
263
src/app/MetaBrush/Document/Serialise.hs
Normal file
263
src/app/MetaBrush/Document/Serialise.hs
Normal file
|
@ -0,0 +1,263 @@
|
||||||
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
|
||||||
|
module MetaBrush.Document.Serialise
|
||||||
|
( documentToJSON, documentFromJSON )
|
||||||
|
where
|
||||||
|
|
||||||
|
-- base
|
||||||
|
import qualified Data.Bifunctor as Bifunctor
|
||||||
|
( first )
|
||||||
|
import Data.Foldable
|
||||||
|
( toList )
|
||||||
|
import Data.Functor.Contravariant
|
||||||
|
( contramap )
|
||||||
|
|
||||||
|
-- bytestring
|
||||||
|
import qualified Data.ByteString as Strict
|
||||||
|
( ByteString )
|
||||||
|
import qualified Data.ByteString.Lazy as Lazy
|
||||||
|
( ByteString )
|
||||||
|
|
||||||
|
-- containers
|
||||||
|
import Data.Sequence
|
||||||
|
( Seq )
|
||||||
|
import qualified Data.Sequence as Seq
|
||||||
|
( fromList )
|
||||||
|
|
||||||
|
-- scientific
|
||||||
|
import qualified Data.Scientific as Scientific
|
||||||
|
( fromFloatDigits, toRealFloat )
|
||||||
|
|
||||||
|
-- stm
|
||||||
|
import qualified Control.Concurrent.STM as STM
|
||||||
|
( atomically )
|
||||||
|
|
||||||
|
-- text
|
||||||
|
import Data.Text
|
||||||
|
( Text )
|
||||||
|
|
||||||
|
-- transformers
|
||||||
|
import Control.Monad.IO.Class
|
||||||
|
( MonadIO(liftIO) )
|
||||||
|
import Control.Monad.Trans.Class
|
||||||
|
( MonadTrans(lift) )
|
||||||
|
|
||||||
|
-- waargonaut
|
||||||
|
import qualified Waargonaut.Attoparsec as JSON.Decoder
|
||||||
|
( decodeAttoparsecByteString )
|
||||||
|
import qualified Waargonaut.Decode as JSON
|
||||||
|
( Decoder )
|
||||||
|
import qualified Waargonaut.Decode.Error as JSON
|
||||||
|
( DecodeError )
|
||||||
|
import qualified Waargonaut.Decode as JSON.Decoder
|
||||||
|
( atKey, bool, list, oneOf, scientific, text )
|
||||||
|
import qualified Waargonaut.Encode as JSON
|
||||||
|
( Encoder, Encoder' )
|
||||||
|
import qualified Waargonaut.Encode as JSON.Encoder
|
||||||
|
( simplePureEncodeByteString
|
||||||
|
, atKey', bool, list, mapLikeObj, scientific, text
|
||||||
|
)
|
||||||
|
|
||||||
|
-- MetaBrush
|
||||||
|
import Math.Bezier.Stroke
|
||||||
|
( StrokePoint(..) )
|
||||||
|
import Math.Vector2D
|
||||||
|
( Point2D(..) ) --, Vector2D(..), Mat22(..) )
|
||||||
|
import MetaBrush.Document
|
||||||
|
( Document(..)
|
||||||
|
, AABB(..)
|
||||||
|
, Stroke(..)
|
||||||
|
, PointData(..)
|
||||||
|
, BrushPointData(..)
|
||||||
|
, FocusState(..)
|
||||||
|
)
|
||||||
|
import MetaBrush.Unique
|
||||||
|
( UniqueSupply, freshUnique )
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
documentToJSON :: Document -> Lazy.ByteString
|
||||||
|
documentToJSON = JSON.Encoder.simplePureEncodeByteString encodeDocument
|
||||||
|
|
||||||
|
documentFromJSON :: UniqueSupply -> Maybe FilePath -> Strict.ByteString -> IO ( Either JSON.DecodeError Document )
|
||||||
|
documentFromJSON uniqueSupply mfp
|
||||||
|
= fmap ( Bifunctor.first fst )
|
||||||
|
. JSON.Decoder.decodeAttoparsecByteString ( decodeDocument uniqueSupply mfp )
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
encodeDouble :: Applicative f => JSON.Encoder f Double
|
||||||
|
encodeDouble = contramap Scientific.fromFloatDigits JSON.Encoder.scientific
|
||||||
|
|
||||||
|
decodeDouble :: Monad m => JSON.Decoder m Double
|
||||||
|
decodeDouble = fmap Scientific.toRealFloat JSON.Decoder.scientific
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodePoint2D :: Applicative f => JSON.Encoder' a -> JSON.Encoder f ( Point2D a )
|
||||||
|
encodePoint2D enc = JSON.Encoder.mapLikeObj \ ( Point2D x y ) ->
|
||||||
|
JSON.Encoder.atKey' "x" enc x . JSON.Encoder.atKey' "y" enc y
|
||||||
|
|
||||||
|
decodePoint2D :: Monad m => JSON.Decoder m a -> JSON.Decoder m ( Point2D a )
|
||||||
|
decodePoint2D dec = Point2D <$> JSON.Decoder.atKey "x" dec <*> JSON.Decoder.atKey "y" dec
|
||||||
|
|
||||||
|
|
||||||
|
{-
|
||||||
|
encodeVector2D :: Applicative f => JSON.Encoder' a -> JSON.Encoder f ( Vector2D a )
|
||||||
|
encodeVector2D enc = JSON.Encoder.mapLikeObj \ ( Vector2D x y ) ->
|
||||||
|
JSON.Encoder.atKey' "x" enc x
|
||||||
|
. JSON.Encoder.atKey' "y" enc y
|
||||||
|
|
||||||
|
decodeVector2D :: Monad m => JSON.Decoder m a -> JSON.Decoder m ( Vector2D a )
|
||||||
|
decodeVector2D dec = Vector2D <$> JSON.Decoder.atKey "x" dec <*> JSON.Decoder.atKey "y" dec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodeMat22 :: Applicative f => JSON.Encoder' a -> JSON.Encoder f ( Mat22 a )
|
||||||
|
encodeMat22 enc = JSON.Encoder.mapLikeObj \ ( Mat22 m00 m01 m10 m11 ) ->
|
||||||
|
JSON.Encoder.atKey' "m00" enc m00
|
||||||
|
. JSON.Encoder.atKey' "m01" enc m01
|
||||||
|
. JSON.Encoder.atKey' "m10" enc m10
|
||||||
|
. JSON.Encoder.atKey' "m11" enc m11
|
||||||
|
|
||||||
|
decodeMat22 :: Monad m => JSON.Decoder m a -> JSON.Decoder m ( Mat22 a )
|
||||||
|
decodeMat22 dec =
|
||||||
|
Mat22 <$> JSON.Decoder.atKey "m00" dec
|
||||||
|
<*> JSON.Decoder.atKey "m01" dec
|
||||||
|
<*> JSON.Decoder.atKey "m10" dec
|
||||||
|
<*> JSON.Decoder.atKey "m11" dec
|
||||||
|
-}
|
||||||
|
|
||||||
|
|
||||||
|
encodeAABB :: Applicative f => JSON.Encoder f AABB
|
||||||
|
encodeAABB = JSON.Encoder.mapLikeObj \ ( AABB { topLeft, botRight } ) ->
|
||||||
|
JSON.Encoder.atKey' "topLeft" enc topLeft
|
||||||
|
. JSON.Encoder.atKey' "botRight" enc botRight
|
||||||
|
where
|
||||||
|
enc :: JSON.Encoder' ( Point2D Double )
|
||||||
|
enc = encodePoint2D encodeDouble
|
||||||
|
|
||||||
|
decodeAABB :: forall m. Monad m => JSON.Decoder m AABB
|
||||||
|
decodeAABB = do
|
||||||
|
topLeft <- JSON.Decoder.atKey "topLeft" dec
|
||||||
|
botRight <- JSON.Decoder.atKey "botRight" dec
|
||||||
|
pure ( AABB { topLeft, botRight } )
|
||||||
|
where
|
||||||
|
dec :: JSON.Decoder m ( Point2D Double )
|
||||||
|
dec = decodePoint2D decodeDouble
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodeStrokePoint :: Applicative f => JSON.Encoder' d -> JSON.Encoder f ( StrokePoint d )
|
||||||
|
encodeStrokePoint enc = JSON.Encoder.mapLikeObj \case
|
||||||
|
PathPoint { coords, pointData } ->
|
||||||
|
JSON.Encoder.atKey' "coords" ( encodePoint2D encodeDouble ) coords
|
||||||
|
. JSON.Encoder.atKey' "data" enc pointData
|
||||||
|
. JSON.Encoder.atKey' "type" JSON.Encoder.text "path"
|
||||||
|
ControlPoint { coords, pointData } ->
|
||||||
|
JSON.Encoder.atKey' "coords" ( encodePoint2D encodeDouble ) coords
|
||||||
|
. JSON.Encoder.atKey' "data" enc pointData
|
||||||
|
. JSON.Encoder.atKey' "type" JSON.Encoder.text "control"
|
||||||
|
|
||||||
|
decodeStrokePointTypeIsPath :: Monad m => JSON.Decoder m Bool
|
||||||
|
decodeStrokePointTypeIsPath = JSON.Decoder.oneOf JSON.Decoder.text "StrokePoint Type"
|
||||||
|
[ ( "path", True ), ( "control", False ) ]
|
||||||
|
|
||||||
|
decodeStrokePoint :: Monad m => JSON.Decoder m d -> JSON.Decoder m ( StrokePoint d )
|
||||||
|
decodeStrokePoint dec = do
|
||||||
|
coords <- JSON.Decoder.atKey "coords" ( decodePoint2D decodeDouble )
|
||||||
|
pointData <- JSON.Decoder.atKey "data" dec
|
||||||
|
isPathPoint <- JSON.Decoder.atKey "type" decodeStrokePointTypeIsPath
|
||||||
|
if isPathPoint
|
||||||
|
then pure ( PathPoint { coords, pointData } )
|
||||||
|
else pure ( ControlPoint { coords, pointData } )
|
||||||
|
|
||||||
|
encodeFocusState :: Applicative f => JSON.Encoder f FocusState
|
||||||
|
encodeFocusState = contramap focusText JSON.Encoder.text
|
||||||
|
where
|
||||||
|
focusText :: FocusState -> Text
|
||||||
|
focusText Normal = "normal"
|
||||||
|
focusText Hover = "hover"
|
||||||
|
focusText Selected = "selected"
|
||||||
|
|
||||||
|
decodeFocusState :: Monad m => JSON.Decoder m FocusState
|
||||||
|
decodeFocusState = JSON.Decoder.oneOf JSON.Decoder.text "FocusState"
|
||||||
|
[ ( "normal" , Normal )
|
||||||
|
, ( "hover" , Hover )
|
||||||
|
, ( "selected", Selected )
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodeBrushPointData :: Applicative f => JSON.Encoder f BrushPointData
|
||||||
|
encodeBrushPointData = JSON.Encoder.mapLikeObj \ ( BrushPointData { brushPointState } ) ->
|
||||||
|
JSON.Encoder.atKey' "focus" encodeFocusState brushPointState
|
||||||
|
|
||||||
|
decodeBrushPointData :: Monad m => JSON.Decoder m BrushPointData
|
||||||
|
decodeBrushPointData = do
|
||||||
|
brushPointState <- JSON.Decoder.atKey "focus" decodeFocusState
|
||||||
|
pure ( BrushPointData { brushPointState } )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodeSequence :: Applicative f => JSON.Encoder f a -> JSON.Encoder f ( Seq a )
|
||||||
|
encodeSequence enc = contramap toList ( JSON.Encoder.list enc )
|
||||||
|
|
||||||
|
decodeSequence :: Monad m => JSON.Decoder m a -> JSON.Decoder m ( Seq a )
|
||||||
|
decodeSequence dec = Seq.fromList <$> JSON.Decoder.list dec
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodePointData :: Applicative f => JSON.Encoder f PointData
|
||||||
|
encodePointData = JSON.Encoder.mapLikeObj \ ( PointData { pointState, brushShape } ) ->
|
||||||
|
JSON.Encoder.atKey' "focus" encodeFocusState pointState
|
||||||
|
. JSON.Encoder.atKey' "brush" ( encodeSequence ( encodeStrokePoint encodeBrushPointData ) ) brushShape
|
||||||
|
|
||||||
|
decodePointData :: Monad m => JSON.Decoder m PointData
|
||||||
|
decodePointData = do
|
||||||
|
pointState <- JSON.Decoder.atKey "focus" decodeFocusState
|
||||||
|
brushShape <- JSON.Decoder.atKey "brush" ( decodeSequence ( decodeStrokePoint decodeBrushPointData ) )
|
||||||
|
pure ( PointData { pointState, brushShape } )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodeStroke :: Applicative f => JSON.Encoder f Stroke
|
||||||
|
encodeStroke = JSON.Encoder.mapLikeObj \ ( Stroke { strokeName, strokeVisible, strokePoints } ) ->
|
||||||
|
JSON.Encoder.atKey' "name" JSON.Encoder.text strokeName
|
||||||
|
. JSON.Encoder.atKey' "visible" JSON.Encoder.bool strokeVisible
|
||||||
|
. JSON.Encoder.atKey' "points" ( encodeSequence ( encodeStrokePoint encodePointData ) ) strokePoints
|
||||||
|
|
||||||
|
decodeStroke :: MonadIO m => UniqueSupply -> JSON.Decoder m Stroke
|
||||||
|
decodeStroke uniqueSupply = do
|
||||||
|
strokeName <- JSON.Decoder.atKey "name" JSON.Decoder.text
|
||||||
|
strokeVisible <- JSON.Decoder.atKey "visible" JSON.Decoder.bool
|
||||||
|
strokeUnique <- lift ( liftIO . STM.atomically $ freshUnique uniqueSupply )
|
||||||
|
strokePoints <- JSON.Decoder.atKey "points" ( decodeSequence ( decodeStrokePoint decodePointData ) )
|
||||||
|
pure ( Stroke { strokeName, strokeVisible, strokeUnique, strokePoints } )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
encodeDocument :: Applicative f => JSON.Encoder f Document
|
||||||
|
encodeDocument = JSON.Encoder.mapLikeObj \ ( Document { displayName, bounds, viewportCenter, zoomFactor, strokes } ) ->
|
||||||
|
JSON.Encoder.atKey' "name" JSON.Encoder.text displayName
|
||||||
|
. JSON.Encoder.atKey' "bounds" encodeAABB bounds
|
||||||
|
. JSON.Encoder.atKey' "center" ( encodePoint2D encodeDouble ) viewportCenter
|
||||||
|
. JSON.Encoder.atKey' "zoom" encodeDouble zoomFactor
|
||||||
|
. JSON.Encoder.atKey' "strokes" ( JSON.Encoder.list encodeStroke ) strokes
|
||||||
|
|
||||||
|
decodeDocument :: MonadIO m => UniqueSupply -> Maybe FilePath -> JSON.Decoder m Document
|
||||||
|
decodeDocument uniqueSupply mbFilePath = do
|
||||||
|
displayName <- JSON.Decoder.atKey "name" JSON.Decoder.text
|
||||||
|
let
|
||||||
|
unsavedChanges :: Bool
|
||||||
|
unsavedChanges = False
|
||||||
|
bounds <- JSON.Decoder.atKey "bounds" decodeAABB
|
||||||
|
viewportCenter <- JSON.Decoder.atKey "center" ( decodePoint2D decodeDouble )
|
||||||
|
zoomFactor <- JSON.Decoder.atKey "zoom" decodeDouble
|
||||||
|
documentUnique <- lift ( liftIO . STM.atomically $ freshUnique uniqueSupply )
|
||||||
|
strokes <- JSON.Decoder.atKey "strokes" ( JSON.Decoder.list ( decodeStroke uniqueSupply ) )
|
||||||
|
pure ( Document { displayName, mbFilePath, unsavedChanges, bounds, viewportCenter, zoomFactor, documentUnique, strokes } )
|
|
@ -160,7 +160,8 @@ renderDocument
|
||||||
pure $ ControlPoint cp ( PointData Normal Empty )
|
pure $ ControlPoint cp ( PointData Normal Empty )
|
||||||
, Just ( PathPoint finalPoint ( PointData Normal Empty ) )
|
, Just ( PathPoint finalPoint ( PointData Normal Empty ) )
|
||||||
]
|
]
|
||||||
= ( Stroke previewPts undefined True undefined ) : strokes doc
|
= ( Stroke { strokePoints = previewPts, strokeVisible = True, strokeUnique = undefined, strokeName = undefined } )
|
||||||
|
: strokes doc
|
||||||
| otherwise
|
| otherwise
|
||||||
= strokes doc
|
= strokes doc
|
||||||
|
|
||||||
|
|
|
@ -65,8 +65,6 @@ import Math.Roots
|
||||||
import Math.Vector2D
|
import Math.Vector2D
|
||||||
( Mat22(..), Point2D(..), Vector2D(..) )
|
( Mat22(..), Point2D(..), Vector2D(..) )
|
||||||
|
|
||||||
import Debug.Trace
|
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- | Fits a cubic Bézier spline to the given curve \( t \mapsto C(t), 0 \leqslant t \leqslant 1 \),
|
-- | Fits a cubic Bézier spline to the given curve \( t \mapsto C(t), 0 \leqslant t \leqslant 1 \),
|
||||||
|
|
Loading…
Reference in a new issue