mirror of
https://gitlab.com/sheaf/metabrush.git
synced 2024-11-05 14:53:37 +00:00
stroke hierarchy
This commit is contained in:
parent
a5fdce1133
commit
d604d4120e
|
@ -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
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 } )
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue