stroke hierarchy

This commit is contained in:
sheaf 2021-04-26 17:18:48 +02:00
parent a5fdce1133
commit d604d4120e
7 changed files with 168 additions and 36 deletions

View file

@ -116,7 +116,7 @@ import MetaBrush.Context
) )
import MetaBrush.Document import MetaBrush.Document
( emptyDocument ( emptyDocument
, Stroke(..), FocusState(..) , Stroke(..), StrokeHierarchy(..), FocusState(..)
, PointData(..) , PointData(..)
) )
import MetaBrush.Document.History import MetaBrush.Document.History
@ -175,7 +175,7 @@ runApplication application = do
[ emptyDocument "Test" docUnique [ emptyDocument "Test" docUnique
& ( field' @"documentContent" . field' @"strokes" ) .~ & ( field' @"documentContent" . field' @"strokes" ) .~
( Seq.fromList ( Seq.fromList
[ Stroke [ StrokeLeaf $ Stroke
{ strokeName = "Stroke 1" { strokeName = "Stroke 1"
, strokeVisible = True , strokeVisible = True
, strokeUnique = strokeUnique , strokeUnique = strokeUnique

View file

@ -26,7 +26,8 @@ module MetaBrush.Document
( AABB(..), mkAABB ( AABB(..), mkAABB
, Document(..), DocumentContent(..) , Document(..), DocumentContent(..)
, emptyDocument , emptyDocument
, Stroke(..), StrokeSpline, _strokeSpline, overStrokeSpline , Stroke(..), StrokeHierarchy(..), visibleStrokes
, StrokeSpline, _strokeSpline, overStrokeSpline
, PointData(..), BrushPointData(..), DiffPointData(..) , PointData(..), BrushPointData(..), DiffPointData(..)
, FocusState(..), Hoverable(..), HoverContext(..) , FocusState(..), Hoverable(..), HoverContext(..)
, Guide(..) , Guide(..)
@ -57,9 +58,9 @@ import Data.Map.Strict
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
( empty, insert ) ( empty, insert )
import Data.Sequence import Data.Sequence
( Seq ) ( Seq(..) )
import qualified Data.Sequence as Seq import qualified Data.Sequence as Seq
( empty ) ( empty, singleton )
-- deepseq -- deepseq
import Control.DeepSeq import Control.DeepSeq
@ -158,11 +159,35 @@ data DocumentContent
{ unsavedChanges :: !Bool { unsavedChanges :: !Bool
, latestChange :: !Text , latestChange :: !Text
, guides :: !( Map Unique Guide ) , guides :: !( Map Unique Guide )
, strokes :: !( Seq Stroke ) , strokes :: !( Seq StrokeHierarchy )
} }
deriving stock ( Show, Generic ) deriving stock ( Show, Generic )
deriving anyclass NFData deriving anyclass NFData
-- | Hierarchy for groups of strokes.
data StrokeHierarchy
= StrokeGroup
{ groupName :: !Text
, groupVisible :: !Bool
, groupContents :: !( Seq StrokeHierarchy )
}
| StrokeLeaf
{ strokeLeaf :: !Stroke }
deriving stock ( Show, Generic )
deriving anyclass NFData
visibleStrokes :: StrokeHierarchy -> Seq Stroke
visibleStrokes ( StrokeGroup { groupVisible, groupContents } )
| groupVisible
= foldMap visibleStrokes groupContents
| otherwise
= Empty
visibleStrokes ( StrokeLeaf { strokeLeaf } )
| strokeVisible strokeLeaf
= Seq.singleton strokeLeaf
| otherwise
= Empty
type StrokeSpline clo brushParams = type StrokeSpline clo brushParams =
Spline clo ( CachedStroke RealWorld ) ( PointData brushParams ) Spline clo ( CachedStroke RealWorld ) ( PointData brushParams )

View file

@ -5,6 +5,7 @@
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-} {-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
@ -16,8 +17,12 @@ module MetaBrush.Document.Draw
where where
-- base -- base
import Data.Coerce
( coerce )
import Data.Functor import Data.Functor
( ($>) ) ( ($>) )
import Data.Semigroup
( First(..) )
-- acts -- acts
import Data.Act import Data.Act
@ -26,8 +31,6 @@ import Data.Act
-- containers -- containers
import Data.Sequence import Data.Sequence
( Seq(..) ) ( Seq(..) )
import qualified Data.Sequence as Seq
( filter, lookup )
-- deepseq -- deepseq
import Control.DeepSeq import Control.DeepSeq
@ -78,7 +81,8 @@ import MetaBrush.Assert
import MetaBrush.Brush import MetaBrush.Brush
( BrushAdaptedTo ) ( BrushAdaptedTo )
import MetaBrush.Document import MetaBrush.Document
( Document(..), DocumentContent(..), Stroke(..), StrokeSpline ( Document(..), DocumentContent(..)
, Stroke(..), StrokeHierarchy(..), StrokeSpline
, FocusState(..), PointData(..) , FocusState(..), PointData(..)
, _selection, _strokeSpline , _selection, _strokeSpline
, coords, overStrokeSpline , coords, overStrokeSpline
@ -118,7 +122,8 @@ getOrCreateDrawAnchor uniqueSupply c doc@( Document { zoomFactor } ) =
case case
( `runState` Nothing ) ( `runState` Nothing )
$ ( field' @"documentContent" . field' @"strokes" . traverse ) $ ( field' @"documentContent" . field' @"strokes" . traverse )
updateStroke doc updateStrokeHierarchy
doc
of of
-- Anchor found: use it. -- Anchor found: use it.
( newDoc, Just ( ( anchor, anchorPt ), anchorName ) ) -> ( newDoc, Just ( ( anchor, anchorPt ), anchorName ) ) ->
@ -144,12 +149,19 @@ getOrCreateDrawAnchor uniqueSupply c doc@( Document { zoomFactor } ) =
newDoc' :: Document newDoc' :: Document
newDoc' newDoc'
= over ( field' @"documentContent" . field' @"strokes" ) = over ( field' @"documentContent" . field' @"strokes" )
( newStroke :<| ) ( StrokeLeaf newStroke :<| )
newDoc newDoc
pure ( newDoc', AnchorAtEnd uniq, c, Nothing ) pure ( newDoc', AnchorAtEnd uniq, c, Nothing )
where where
-- Deselect all points, and try to find a valid anchor for drawing -- Deselect all points, and try to find a valid anchor for drawing
-- (a path start/end point at mouse click point). -- (a path start/end point at mouse click point).
updateStrokeHierarchy :: StrokeHierarchy -> State ( Maybe ( ( DrawAnchor, Point2D Double ), Text ) ) StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) = do
newContents <- traverse updateStrokeHierarchy groupContents
pure ( StrokeGroup { groupContents = newContents, .. } )
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf <$> updateStroke strokeLeaf
updateStroke :: Stroke -> State ( Maybe ( ( DrawAnchor, Point2D Double ), Text ) ) Stroke updateStroke :: Stroke -> State ( Maybe ( ( DrawAnchor, Point2D Double ), Text ) ) Stroke
updateStroke stroke@( Stroke { strokeName, strokeVisible, strokeUnique } ) = _strokeSpline updateStrokeSpline stroke updateStroke stroke@( Stroke { strokeName, strokeVisible, strokeUnique } ) = _strokeSpline updateStrokeSpline stroke
@ -196,10 +208,19 @@ getOrCreateDrawAnchor uniqueSupply c doc@( Document { zoomFactor } ) =
squaredNorm ( c --> p :: Vector2D Double ) < 16 / ( zoomFactor * zoomFactor ) squaredNorm ( c --> p :: Vector2D Double ) < 16 / ( zoomFactor * zoomFactor )
addToAnchor :: DrawAnchor -> StrokeSpline Open () -> Document -> Document addToAnchor :: DrawAnchor -> StrokeSpline Open () -> Document -> Document
addToAnchor anchor newSpline = over ( field' @"documentContent" . field' @"strokes" . mapped ) addToStroke addToAnchor anchor newSpline = over ( field' @"documentContent" . field' @"strokes" . mapped ) updateStrokeHierarchy
where where
addToStroke :: Stroke -> Stroke
addToStroke stroke@( Stroke { strokeUnique } ) updateStrokeHierarchy :: StrokeHierarchy -> StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) =
let
newContents = fmap updateStrokeHierarchy groupContents
in
StrokeGroup { groupContents = newContents, .. }
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf $ updateStroke strokeLeaf
updateStroke :: Stroke -> Stroke
updateStroke stroke@( Stroke { strokeUnique } )
| strokeUnique == anchorStrokeUnique anchor | strokeUnique == anchorStrokeUnique anchor
= =
let let
@ -244,8 +265,18 @@ withAnchorBrushData
) )
-> r -> r
withAnchorBrushData anchor ( Document { documentContent = Content { strokes } } ) f = withAnchorBrushData anchor ( Document { documentContent = Content { strokes } } ) f =
splineAnchor . Seq.lookup 0 $ Seq.filter ( \ Stroke { strokeUnique } -> strokeUnique == anchorStrokeUnique anchor ) strokes splineAnchor . coerce $ foldMap getFirstRelevantStroke strokes
where where
getFirstRelevantStroke :: StrokeHierarchy -> Maybe ( First Stroke )
getFirstRelevantStroke ( StrokeGroup { groupContents } ) =
foldMap getFirstRelevantStroke groupContents
getFirstRelevantStroke ( StrokeLeaf { strokeLeaf } )
| strokeUnique strokeLeaf == anchorStrokeUnique anchor
= Just ( First strokeLeaf )
| otherwise
= Nothing
splineAnchor :: Maybe Stroke -> r splineAnchor :: Maybe Stroke -> r
splineAnchor ( Just ( Stroke { strokeSpline = strokeSpline :: StrokeSpline clo pointData, strokeBrush } ) ) splineAnchor ( Just ( Stroke { strokeSpline = strokeSpline :: StrokeSpline clo pointData, strokeBrush } ) )
| SOpen <- ssplineType @clo | SOpen <- ssplineType @clo

View file

@ -10,6 +10,7 @@
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE ViewPatterns #-}
@ -116,7 +117,7 @@ import Math.Vector2D
import {-# SOURCE #-} MetaBrush.Context import {-# SOURCE #-} MetaBrush.Context
( Modifier(..) ) ( Modifier(..) )
import MetaBrush.Document import MetaBrush.Document
( Document(..), Stroke(..) ( Document(..), Stroke(..), StrokeHierarchy(..)
, PointData(..), DiffPointData , PointData(..), DiffPointData
, FocusState(..), _selection , FocusState(..), _selection
, StrokeSpline, _strokeSpline, overStrokeSpline , StrokeSpline, _strokeSpline, overStrokeSpline
@ -158,8 +159,15 @@ selectionMode = foldMap \case
-- | Updates the selected objects on a single click selection event. -- | Updates the selected objects on a single click selection event.
selectAt :: SelectionMode -> Point2D Double -> Document -> Document selectAt :: SelectionMode -> Point2D Double -> Document -> Document
selectAt selMode c doc@( Document { zoomFactor } ) = selectAt selMode c doc@( Document { zoomFactor } ) =
( `evalState` False ) $ ( field' @"documentContent" . field' @"strokes" . traverse ) updateStroke doc ( `evalState` False ) $ ( field' @"documentContent" . field' @"strokes" . traverse ) updateStrokeHierarchy doc
where where
updateStrokeHierarchy :: StrokeHierarchy -> State Bool StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) = do
newContents <- traverse updateStrokeHierarchy groupContents
pure ( StrokeGroup { groupContents = newContents, .. } )
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf <$> updateStroke strokeLeaf
updateStroke :: Stroke -> State Bool Stroke updateStroke :: Stroke -> State Bool Stroke
updateStroke stroke@( Stroke { strokeVisible } ) = _strokeSpline updateSpline stroke updateStroke stroke@( Stroke { strokeVisible } ) = _strokeSpline updateSpline stroke
where where
@ -222,7 +230,7 @@ dragMoveSelect c doc@( Document { zoomFactor } ) =
let let
res :: WriterT ( Maybe DragMoveSelect ) ( Tardis ( Maybe DragMoveSelect ) ( Maybe DragMoveSelect ) ) Document res :: WriterT ( Maybe DragMoveSelect ) ( Tardis ( Maybe DragMoveSelect ) ( Maybe DragMoveSelect ) ) Document
res = do res = do
newDoc <- ( field' @"documentContent" . field' @"strokes" . traverse ) updateStroke doc newDoc <- ( field' @"documentContent" . field' @"strokes" . traverse ) updateStrokeHierarchy doc
lift $ Tardis.getPast >>= Tardis.sendPast lift $ Tardis.getPast >>= Tardis.sendPast
pure newDoc pure newDoc
in case runIdentity . ( `Tardis.runTardisT` ( Nothing, Nothing ) ) . runWriterT $ res of in case runIdentity . ( `Tardis.runTardisT` ( Nothing, Nothing ) ) . runWriterT $ res of
@ -231,6 +239,12 @@ dragMoveSelect c doc@( Document { zoomFactor } ) =
_ -> Nothing _ -> Nothing
where where
updateStrokeHierarchy :: StrokeHierarchy -> WriterT ( Maybe DragMoveSelect ) ( Tardis ( Maybe DragMoveSelect ) ( Maybe DragMoveSelect ) ) StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) = do
newContents <- traverse updateStrokeHierarchy groupContents
pure ( StrokeGroup { groupContents = newContents, .. } )
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf <$> updateStroke strokeLeaf
updateStroke :: Stroke -> WriterT ( Maybe DragMoveSelect ) ( Tardis ( Maybe DragMoveSelect ) ( Maybe DragMoveSelect ) ) Stroke updateStroke :: Stroke -> WriterT ( Maybe DragMoveSelect ) ( Tardis ( Maybe DragMoveSelect ) ( Maybe DragMoveSelect ) ) Stroke
updateStroke stroke@( Stroke { strokeVisible, strokeUnique } ) = _strokeSpline updateSpline stroke updateStroke stroke@( Stroke { strokeVisible, strokeUnique } ) = _strokeSpline updateSpline stroke
where where
@ -374,11 +388,20 @@ dragMoveSelect c doc@( Document { zoomFactor } ) =
selectRectangle :: SelectionMode -> Point2D Double -> Point2D Double -> Document -> Document selectRectangle :: SelectionMode -> Point2D Double -> Point2D Double -> Document -> Document
selectRectangle selMode ( Point2D x0 y0 ) ( Point2D x1 y1 ) selectRectangle selMode ( Point2D x0 y0 ) ( Point2D x1 y1 )
= over ( field' @"documentContent" . field' @"strokes" . mapped ) = over ( field' @"documentContent" . field' @"strokes" . mapped )
updateStroke updateStrokeHierarchy
where where
xMin, xMax, yMin, yMax :: Double xMin, xMax, yMin, yMax :: Double
( xMin, xMax ) = if x0 <= x1 then ( x0, x1 ) else ( x1, x0 ) ( xMin, xMax ) = if x0 <= x1 then ( x0, x1 ) else ( x1, x0 )
( yMin, yMax ) = if y0 <= y1 then ( y0, y1 ) else ( y1, y0 ) ( yMin, yMax ) = if y0 <= y1 then ( y0, y1 ) else ( y1, y0 )
updateStrokeHierarchy :: StrokeHierarchy -> StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) =
let
newContents = fmap updateStrokeHierarchy groupContents
in
StrokeGroup { groupContents = newContents, .. }
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf $ updateStroke strokeLeaf
updateStroke :: Stroke -> Stroke updateStroke :: Stroke -> Stroke
updateStroke stroke@( Stroke { strokeVisible } ) = updateStroke stroke@( Stroke { strokeVisible } ) =
overStrokeSpline overStrokeSpline
@ -415,8 +438,15 @@ data UpdateInfo
-- Returns the updated document, together with info about how many points were translated. -- Returns the updated document, together with info about how many points were translated.
translateSelection :: Vector2D Double -> Document -> ( Document, UpdateInfo ) translateSelection :: Vector2D Double -> Document -> ( Document, UpdateInfo )
translateSelection t doc = translateSelection t doc =
( `runState` mempty ) . ( `evalStateT` False ) $ ( field' @"documentContent" . field' @"strokes" . traverse ) updateStroke doc ( `runState` mempty ) . ( `evalStateT` False ) $ ( field' @"documentContent" . field' @"strokes" . traverse ) updateStrokeHierarchy doc
where where
updateStrokeHierarchy :: StrokeHierarchy -> StateT Bool ( State UpdateInfo ) StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) = do
newContents <- traverse updateStrokeHierarchy groupContents
pure ( StrokeGroup { groupContents = newContents, .. } )
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf <$> updateStroke strokeLeaf
updateStroke :: Stroke -> StateT Bool ( State UpdateInfo ) Stroke updateStroke :: Stroke -> StateT Bool ( State UpdateInfo ) Stroke
updateStroke stroke@( Stroke { strokeVisible, strokeUnique } ) = _strokeSpline updateSpline stroke updateStroke stroke@( Stroke { strokeVisible, strokeUnique } ) = _strokeSpline updateSpline stroke
where where
@ -506,10 +536,17 @@ deleteSelected :: Document -> ( Document, UpdateInfo )
deleteSelected doc = deleteSelected doc =
( `runState` mempty ) $ ( `runState` mempty ) $
( field' @"documentContent" . field' @"strokes" ) ( field' @"documentContent" . field' @"strokes" )
( traverseMaybe updateStroke ) ( traverseMaybe updateStrokeHierarchy )
doc doc
where where
updateStrokeHierarchy :: StrokeHierarchy -> State UpdateInfo ( Maybe StrokeHierarchy )
updateStrokeHierarchy ( StrokeGroup { .. } ) = do
newContents <- traverseMaybe updateStrokeHierarchy groupContents
pure ( Just $ StrokeGroup { groupContents = newContents, .. } )
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = fmap StrokeLeaf <$> updateStroke strokeLeaf
updateStroke :: Stroke -> State UpdateInfo ( Maybe Stroke ) updateStroke :: Stroke -> State UpdateInfo ( Maybe Stroke )
updateStroke stroke@( Stroke { strokeVisible, strokeUnique } ) = runMaybeT $ _strokeSpline updateSpline stroke updateStroke stroke@( Stroke { strokeVisible, strokeUnique } ) = runMaybeT $ _strokeSpline updateSpline stroke
where where
@ -664,7 +701,7 @@ dragUpdate _ p ( ClickedOnCurve { dragStrokeUnique, dragSegmentIndex, dragSegmen
let let
( newDocument, mbStrokeName ) = ( newDocument, mbStrokeName ) =
( `runState` Nothing ) $ ( `runState` Nothing ) $
( field' @"documentContent" . field' @"strokes" . traverse ) updateStroke doc ( field' @"documentContent" . field' @"strokes" . traverse ) updateStrokeHierarchy doc
in case mbStrokeName of in case mbStrokeName of
Just name -> do Just name -> do
let let
@ -673,6 +710,13 @@ dragUpdate _ p ( ClickedOnCurve { dragStrokeUnique, dragSegmentIndex, dragSegmen
Just ( HistoryChange { newDocument, changeText } ) Just ( HistoryChange { newDocument, changeText } )
_ -> Nothing _ -> Nothing
where where
updateStrokeHierarchy :: StrokeHierarchy -> State ( Maybe Text ) StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) = do
newContents <- traverse updateStrokeHierarchy groupContents
pure ( StrokeGroup { groupContents = newContents, .. } )
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf <$> updateStroke strokeLeaf
updateStroke :: Stroke -> State ( Maybe Text ) Stroke updateStroke :: Stroke -> State ( Maybe Text ) Stroke
updateStroke stroke@( Stroke { strokeUnique, strokeName } ) updateStroke stroke@( Stroke { strokeUnique, strokeName } )
| strokeUnique /= dragStrokeUnique | strokeUnique /= dragStrokeUnique

View file

@ -181,7 +181,7 @@ import MetaBrush.Brush
) )
import MetaBrush.Document import MetaBrush.Document
( Document(..), DocumentContent(..), Guide(..) ( Document(..), DocumentContent(..), Guide(..)
, Stroke(..), StrokeSpline , Stroke(..), StrokeHierarchy(..), StrokeSpline
, PointData(..), FocusState(..) , PointData(..), FocusState(..)
) )
import MetaBrush.MetaParameter.AST import MetaBrush.MetaParameter.AST
@ -694,6 +694,33 @@ decodeStroke uniqueSupply = do
encodeStrokeHierarchy :: Monad f => JSON.Encoder f StrokeHierarchy
encodeStrokeHierarchy = JSON.Encoder.mapLikeObj \case
StrokeGroup { groupName, groupVisible, groupContents } ->
JSON.Encoder.atKey' "tag" JSON.Encoder.text "group"
. JSON.Encoder.atKey' "name" JSON.Encoder.text groupName
. JSON.Encoder.atKey' "visible" JSON.Encoder.bool groupVisible
. JSON.Encoder.atKey' "contents" ( encodeSequence encodeStrokeHierarchy ) groupContents
StrokeLeaf { strokeLeaf } ->
JSON.Encoder.atKey' "tag" JSON.Encoder.text "leaf"
. JSON.Encoder.atKey' "stroke" encodeStroke strokeLeaf
decodeStrokeHierarchy :: MonadIO m => UniqueSupply -> JSON.Decoder m StrokeHierarchy
decodeStrokeHierarchy uniqueSupply = do
tag <- JSON.Decoder.atKey "tag" JSON.Decoder.text
case tag of
"group" -> do
groupName <- JSON.Decoder.atKey "name" JSON.Decoder.text
groupVisible <- JSON.Decoder.atKey "visible" JSON.Decoder.bool
groupContents <- JSON.Decoder.atKey "contents" ( decodeSequence $ decodeStrokeHierarchy uniqueSupply )
pure ( StrokeGroup { groupName, groupVisible, groupContents } )
"leaf" -> do
strokeLeaf <- JSON.Decoder.atKey "leaf" ( decodeStroke uniqueSupply )
pure ( StrokeLeaf { strokeLeaf } )
_ -> throwError ( JSON.ParseFailed $ "Unsupported stroke hierarchy type with tag " <> tag )
encodeGuide :: Applicative f => JSON.Encoder f Guide encodeGuide :: Applicative f => JSON.Encoder f Guide
encodeGuide = JSON.Encoder.mapLikeObj \ ( Guide { guidePoint, guideNormal } ) -> encodeGuide = JSON.Encoder.mapLikeObj \ ( Guide { guidePoint, guideNormal } ) ->
JSON.Encoder.atKey' "point" ( encoder @( Point2D Double ) ) guidePoint JSON.Encoder.atKey' "point" ( encoder @( Point2D Double ) ) guidePoint
@ -713,8 +740,8 @@ decodeGuide uniqueSupply = do
encodeDocumentContent :: Applicative f => JSON.Encoder f DocumentContent encodeDocumentContent :: Applicative f => JSON.Encoder f DocumentContent
encodeDocumentContent = JSON.Encoder.mapLikeObj \ ( Content { guides, strokes } ) -> encodeDocumentContent = JSON.Encoder.mapLikeObj \ ( Content { guides, strokes } ) ->
JSON.Encoder.atKey' "guides" ( encodeUniqueMap encodeGuide ) guides JSON.Encoder.atKey' "guides" ( encodeUniqueMap encodeGuide ) guides
. JSON.Encoder.atKey' "strokes" ( encodeSequence encodeStroke ) strokes . JSON.Encoder.atKey' "strokes" ( encodeSequence encodeStrokeHierarchy ) strokes
decodeDocumentContent :: MonadIO m => UniqueSupply -> JSON.Decoder m DocumentContent decodeDocumentContent :: MonadIO m => UniqueSupply -> JSON.Decoder m DocumentContent
decodeDocumentContent uniqueSupply = do decodeDocumentContent uniqueSupply = do
@ -723,8 +750,8 @@ decodeDocumentContent uniqueSupply = do
unsavedChanges = False unsavedChanges = False
latestChange :: Text latestChange :: Text
latestChange = "Load document" latestChange = "Load document"
strokes <- JSON.Decoder.atKey "strokes" ( decodeSequence ( decodeStroke uniqueSupply ) ) strokes <- JSON.Decoder.atKey "strokes" ( decodeSequence ( decodeStrokeHierarchy uniqueSupply ) )
guides <- JSON.Decoder.atKey "guides" ( decodeUniqueMap ( decodeGuide uniqueSupply ) ) guides <- JSON.Decoder.atKey "guides" ( decodeUniqueMap ( decodeGuide uniqueSupply ) )
pure ( Content { unsavedChanges, latestChange, strokes, guides } ) pure ( Content { unsavedChanges, latestChange, strokes, guides } )

View file

@ -60,7 +60,7 @@ import Math.Module
import Math.Vector2D import Math.Vector2D
( Point2D(..), Vector2D(..), Segment(..) ) ( Point2D(..), Vector2D(..), Segment(..) )
import MetaBrush.Document import MetaBrush.Document
( Document(..), Stroke(..), StrokeSpline ( Document(..), Stroke(..), StrokeHierarchy(..), StrokeSpline
, PointData(..), DiffPointData(..) , PointData(..), DiffPointData(..)
, coords, _strokeSpline , coords, _strokeSpline
) )
@ -78,10 +78,16 @@ subdivide c doc@( Document { zoomFactor } ) =
( updatedDoc, mbSubdivLoc ) = ( updatedDoc, mbSubdivLoc ) =
( `runState` Nothing ) ( `runState` Nothing )
$ ( field' @"documentContent" . field' @"strokes" . traverse ) $ ( field' @"documentContent" . field' @"strokes" . traverse )
updateStroke updateStrokeHierarchy
doc doc
in ( updatedDoc , ) <$> mbSubdivLoc in ( updatedDoc , ) <$> mbSubdivLoc
where where
updateStrokeHierarchy :: StrokeHierarchy -> State ( Maybe Text ) StrokeHierarchy
updateStrokeHierarchy ( StrokeGroup { .. } ) = do
newContents <- traverse updateStrokeHierarchy groupContents
pure ( StrokeGroup { groupContents = newContents, .. } )
updateStrokeHierarchy ( StrokeLeaf { strokeLeaf } ) = StrokeLeaf <$> updateStroke strokeLeaf
updateStroke :: Stroke -> State ( Maybe Text ) Stroke updateStroke :: Stroke -> State ( Maybe Text ) Stroke
updateStroke stroke@( Stroke { strokeVisible, strokeName } ) = _strokeSpline updateSpline stroke updateStroke stroke@( Stroke { strokeVisible, strokeName } ) = _strokeSpline updateSpline stroke

View file

@ -35,8 +35,6 @@ import Data.Functor.Compose
( Compose(..) ) ( Compose(..) )
import Data.Int import Data.Int
( Int32 ) ( Int32 )
import Data.Maybe
( mapMaybe )
import GHC.Exts import GHC.Exts
( Proxy#, proxy# ) ( Proxy#, proxy# )
import GHC.Generics import GHC.Generics
@ -114,7 +112,8 @@ import MetaBrush.Context
import MetaBrush.Document import MetaBrush.Document
( Document(..), DocumentContent(..) ( Document(..), DocumentContent(..)
, mkAABB , mkAABB
, Stroke(..), StrokeSpline , Stroke(..), visibleStrokes
, StrokeSpline
, FocusState(..) , FocusState(..)
, HoverContext(..), Hoverable(..) , HoverContext(..), Hoverable(..)
, PointData(..) , PointData(..)
@ -190,8 +189,8 @@ getDocumentRender
afterDrag :: Maybe DocChange afterDrag :: Maybe DocChange
afterDrag = dragUpdate p0 p1 dragAction alternateMode doc afterDrag = dragUpdate p0 p1 dragAction alternateMode doc
-> case afterDrag of -> case afterDrag of
Just docUpdate -> strokes . documentContent $ newDocument docUpdate Just docUpdate -> foldMap visibleStrokes . strokes . documentContent $ newDocument docUpdate
_ -> strokes content _ -> foldMap visibleStrokes . strokes $ content
| Just ( PartialPath p0 cp0 anchor firstPoint ) <- mbPartialPath | Just ( PartialPath p0 cp0 anchor firstPoint ) <- mbPartialPath
, let , let
mbFinalPoint :: Maybe ( Point2D Double ) mbFinalPoint :: Maybe ( Point2D Double )
@ -230,8 +229,8 @@ getDocumentRender
, strokeName = "Preview stroke (temporary)" , strokeName = "Preview stroke (temporary)"
, strokeBrush = mbBrush , strokeBrush = mbBrush
} }
-> previewStroke :<| strokes content -> previewStroke :<| foldMap visibleStrokes ( strokes content )
_ -> strokes content _ -> foldMap visibleStrokes ( strokes content )
strokesRenderData <- traverseMaybe ( sequenceA . strokeRenderData fitParams ) modifiedStrokes strokesRenderData <- traverseMaybe ( sequenceA . strokeRenderData fitParams ) modifiedStrokes