fix time-travel issue in deletion code

This commit is contained in:
sheaf 2020-09-11 00:37:39 +02:00
parent dc11c1af15
commit 087c29aef3

View file

@ -58,7 +58,7 @@ import Control.Lens
-- tardis -- tardis
import Control.Monad.Trans.Tardis import Control.Monad.Trans.Tardis
( Tardis, TardisT ) ( Tardis )
import qualified Control.Monad.Trans.Tardis as Tardis import qualified Control.Monad.Trans.Tardis as Tardis
( TardisT(..) ( TardisT(..)
, getPast, getFuture, sendPast, sendFuture , getPast, getFuture, sendPast, sendFuture
@ -68,8 +68,8 @@ import qualified Control.Monad.Trans.Tardis as Tardis
import Control.Monad.Trans.Class import Control.Monad.Trans.Class
( lift ) ( lift )
import Control.Monad.Trans.State.Strict import Control.Monad.Trans.State.Strict
( StateT(..) ( StateT(..), State, runState, evalState
, State, runState, evalState, get, put, modify' , get, put, modify
) )
-- MetaBrush -- MetaBrush
@ -296,15 +296,24 @@ data UpdateInfo
deriving ( Semigroup, Monoid ) deriving ( Semigroup, Monoid )
via Generically UpdateInfo via Generically UpdateInfo
recordPointUpdate :: Unique -> StrokePoint d -> State UpdateInfo () -- Update the info to record a modification.
recordPointUpdate uniq ( PathPoint {} ) = modify' --
( over ( field' @"pathPointsAffected" ) (<>1) -- Needs to be lazy in the given Boolean, to avoid time paradoxes.
. over ( field' @"strokesAffected" ) ( Set.insert uniq ) recordPointUpdate :: Monad m => Bool -> Unique -> StrokePoint d -> StateT UpdateInfo m ()
) recordPointUpdate doUpdate uniq ( PathPoint {} ) = modify $
recordPointUpdate uniq ( ControlPoint {} ) = modify' if doUpdate
then
( over ( field' @"pathPointsAffected" ) (<>1)
. over ( field' @"strokesAffected" ) ( Set.insert uniq )
)
else id
recordPointUpdate doUpdate uniq ( ControlPoint {} ) = modify $
if doUpdate
then
( over ( field' @"controlPointsAffected" ) (<>1) ( over ( field' @"controlPointsAffected" ) (<>1)
. over ( field' @"strokesAffected" ) ( Set.insert uniq ) . over ( field' @"strokesAffected" ) ( Set.insert uniq )
) )
else id
-- | Translate all selected points by the given vector. -- | Translate all selected points by the given vector.
-- --
@ -330,7 +339,7 @@ translateSelection mode t doc =
updateStrokePoint :: HasType FocusState pt => Unique -> StrokePoint pt -> State UpdateInfo ( StrokePoint pt ) updateStrokePoint :: HasType FocusState pt => Unique -> StrokePoint pt -> State UpdateInfo ( StrokePoint pt )
updateStrokePoint uniq pt updateStrokePoint uniq pt
| Selected <- view _selection pt | Selected <- view _selection pt
= recordPointUpdate uniq pt = recordPointUpdate True uniq pt
$> pt { coords = t coords pt } $> pt { coords = t coords pt }
| otherwise | otherwise
= pure pt = pure pt
@ -339,16 +348,15 @@ translateSelection mode t doc =
-- --
-- Returns the updated document, together with info about how many points were deleted. -- Returns the updated document, together with info about how many points were deleted.
deleteSelected :: Mode -> Document -> ( Document, UpdateInfo ) deleteSelected :: Mode -> Document -> ( Document, UpdateInfo )
deleteSelected mode doc = ( newDoc, updateInfo ) deleteSelected mode doc = deletionResult
where where
newDoc :: Document deletionResult :: ( Document, UpdateInfo )
updateInfo :: UpdateInfo deletionResult
( ( newDoc, _ ), updateInfo ) = fst . runIdentity . ( `Tardis.runTardisT` ( False, False ) ) . ( `runStateT` mempty )
= runIdentity . ( `runStateT` mempty ) . ( `Tardis.runTardisT` ( False, False ) )
$ ( field' @"documentContent" . field' @"strokes" . traverse ) updateStroke doc $ ( field' @"documentContent" . field' @"strokes" . traverse ) updateStroke doc
updateStroke :: Stroke -> TardisT Bool Bool ( State UpdateInfo ) Stroke updateStroke :: Stroke -> StateT UpdateInfo ( Tardis Bool Bool ) Stroke
updateStroke stroke@( Stroke { strokeVisible, strokeUnique } ) updateStroke stroke@( Stroke { strokeVisible, strokeUnique } )
| not strokeVisible | not strokeVisible
= pure stroke = pure stroke
@ -365,24 +373,24 @@ deleteSelected mode doc = ( newDoc, updateInfo )
:: forall pt :: forall pt
. HasType FocusState pt . HasType FocusState pt
=> Unique -> Seq ( StrokePoint pt ) => Unique -> Seq ( StrokePoint pt )
-> TardisT Bool Bool ( State UpdateInfo ) ( Seq ( StrokePoint pt ) ) -> StateT UpdateInfo ( Tardis Bool Bool ) ( Seq ( StrokePoint pt ) )
updateStrokePoints _ Empty = pure Empty updateStrokePoints _ Empty = pure Empty
updateStrokePoints uniq ( p :<| ps ) = case p of updateStrokePoints uniq ( p :<| ps ) = case p of
PathPoint {} PathPoint {}
| Selected <- selectionState | Selected <- selectionState
-> do -> do
Tardis.sendPast True lift ( Tardis.sendPast True )
Tardis.sendFuture True lift ( Tardis.sendFuture True )
lift ( recordPointUpdate uniq p ) recordPointUpdate True uniq p
updateStrokePoints uniq ps updateStrokePoints uniq ps
| otherwise | otherwise
-> do -> do
Tardis.sendPast False lift ( Tardis.sendPast False )
Tardis.sendFuture False lift ( Tardis.sendFuture False )
( p :<| ) <$> updateStrokePoints uniq ps ( p :<| ) <$> updateStrokePoints uniq ps
_ -> do _ -> do
prevPathPointDeleted <- Tardis.getPast prevPathPointDeleted <- lift Tardis.getPast
nextPathPointDeleted <- Tardis.getFuture nextPathPointDeleted <- lift Tardis.getFuture
rest <- updateStrokePoints uniq ps rest <- updateStrokePoints uniq ps
let let
-- Control point must be deleted: -- Control point must be deleted:
@ -391,17 +399,13 @@ deleteSelected mode doc = ( newDoc, updateInfo )
-- - if the next path point is going to be deleted. -- - if the next path point is going to be deleted.
-- --
-- Need to be lazy in "nextPathPointDeleted" to avoid looping. -- Need to be lazy in "nextPathPointDeleted" to avoid looping.
res :: Seq ( StrokePoint pt ) needsDeletion :: Bool
stateAction :: State UpdateInfo () needsDeletion
( res, stateAction ) = selectionState == Selected
| selectionState == Selected
|| prevPathPointDeleted || prevPathPointDeleted
|| nextPathPointDeleted || nextPathPointDeleted
= ( rest, recordPointUpdate uniq p ) recordPointUpdate needsDeletion uniq p
| otherwise pure $ if needsDeletion then rest else ( p :<| rest )
= ( p :<| rest, pure () )
lift stateAction
pure res
where where
selectionState :: FocusState selectionState :: FocusState
selectionState = view _selection p selectionState = view _selection p