monomer-1.6.0.0: src/Monomer/Widgets/Animation/Wipe.hs
{-|
Module : Monomer.Widgets.Animation.Wipe
Copyright : (c) 2023 Ruslan Gadeev, Francisco Vallarino
License : BSD-3-Clause (see the LICENSE file)
Maintainer : fjvallarino@gmail.com
Stability : experimental
Portability : non-portable
Wipe animation widget. Wraps a child widget whose content will be animated.
Messages:
- Accepts a 'AnimationMsg', used to control the state of the animation.
-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE Strict #-}
module Monomer.Widgets.Animation.Wipe (
-- * Configuration
WipeCfg,
wipeLeft,
wipeRight,
wipeTop,
wipeBottom,
wipeDoorH,
wipeDoorV,
wipeRect,
-- * Constructors
animWipeIn,
animWipeIn_,
animWipeOut,
animWipeOut_
) where
import Control.Applicative ((<|>))
import Control.Lens ((&), (.~))
import Data.Default
import Data.Maybe
import Monomer.Helper
import Monomer.Widgets.Container
import Monomer.Widgets.Animation.Transform
import qualified Monomer.Lens as L
data WipeDirection
= WipeLeft
| WipeRight
| WipeTop
| WipeBottom
| WipeDoorH
| WipeDoorV
| WipeRect
deriving (Eq, Show)
{-|
Configuration options for wipe:
- 'autoStart': whether the first time the widget is added, animation should run.
- 'duration': how long the animation lasts in ms.
- 'onFinished': event to raise when animation is complete.
- 'onFinishedReq': 'WidgetRequest' to generate when animation is complete.
- Individual combinators for direction.
-}
data WipeCfg s e = WipeCfg {
_wpcDirection :: Maybe WipeDirection,
_wpcTransformCfg :: TransformCfg s e
} deriving (Eq, Show)
instance Default (WipeCfg s e) where
def = WipeCfg {
_wpcDirection = Nothing,
_wpcTransformCfg = def
}
instance Semigroup (WipeCfg s e) where
(<>) wc1 wc2 = WipeCfg {
_wpcDirection = _wpcDirection wc2 <|> _wpcDirection wc1,
_wpcTransformCfg = _wpcTransformCfg wc1 <> _wpcTransformCfg wc2
}
instance Monoid (WipeCfg s e) where
mempty = def
instance CmbAutoStart (WipeCfg s e) where
autoStart_ start = def {
_wpcTransformCfg = autoStart_ start
}
instance CmbDuration (WipeCfg s e) Millisecond where
duration dur = def {
_wpcTransformCfg = duration dur
}
instance WidgetEvent e => CmbOnFinished (WipeCfg s e) e where
onFinished handler = def {
_wpcTransformCfg = onFinished handler
}
instance CmbOnFinishedReq (WipeCfg s e) s e where
onFinishedReq req = def {
_wpcTransformCfg = onFinishedReq req
}
-- | Wipe from/to left.
wipeLeft :: WipeCfg s e
wipeLeft = def { _wpcDirection = Just WipeLeft }
-- | Wipe from/to right.
wipeRight :: WipeCfg s e
wipeRight = def { _wpcDirection = Just WipeRight }
-- | Wipe from/to top.
wipeTop :: WipeCfg s e
wipeTop = def { _wpcDirection = Just WipeTop }
-- | Wipe from/to bottom.
wipeBottom :: WipeCfg s e
wipeBottom = def { _wpcDirection = Just WipeBottom }
-- | Wipe horizontally in a door shape.
wipeDoorH :: WipeCfg s e
wipeDoorH = def { _wpcDirection = Just WipeDoorH }
-- | Wipe vertically in a door shape.
wipeDoorV :: WipeCfg s e
wipeDoorV = def { _wpcDirection = Just WipeDoorV }
-- | Wipe in a rectangle shape.
wipeRect :: WipeCfg s e
wipeRect = def { _wpcDirection = Just WipeRect }
-- | Animates a widget from the left to fully visible.
animWipeIn
:: WidgetEvent e
=> WidgetNode s e -- ^ The child node.
-> WidgetNode s e -- ^ The created animation container.
animWipeIn managed = animWipeIn_ def managed
-- | Animates a widget from the provided direction to fully visible (defaults
-- to left). Accepts config.
animWipeIn_
:: WidgetEvent e
=> [WipeCfg s e] -- ^ The config options.
-> WidgetNode s e -- ^ The child node.
-> WidgetNode s e -- ^ The created animation container.
animWipeIn_ configs managed = makeNode configs managed True
& L.info . L.widgetType .~ "animWipeIn"
-- | Animates a widget to the left from visible to not visible.
animWipeOut
:: WidgetEvent e
=> WidgetNode s e -- ^ The child node.
-> WidgetNode s e -- ^ The created animation container.
animWipeOut managed = animWipeOut_ def managed
-- | Animates a widget to the provided direction from visible to not
-- visible (defaults to left). Accepts config.
animWipeOut_
:: WidgetEvent e
=> [WipeCfg s e] -- ^ The config options.
-> WidgetNode s e -- ^ The child node.
-> WidgetNode s e -- ^ The created animation container.
animWipeOut_ configs managed = makeNode configs managed False
& L.info . L.widgetType .~ "animWipeOut"
makeNode
:: WidgetEvent e
=> [WipeCfg s e]
-> WidgetNode s e
-> Bool
-> WidgetNode s e
makeNode configs managed isWipeIn = node where
node = animTransform_ [_wpcTransformCfg] f managed
f t (Rect x y w h) = [animScissor vp] where
vp = case dir of
WipeLeft -> Rect x y dw h
WipeRight -> Rect (x+(1-(step t))*w) y dw h
WipeTop -> Rect x y w dh
WipeBottom -> Rect x (y+(1-(step t))*h) w dh
WipeDoorH -> Rect dx y dw h
WipeDoorV -> Rect x dy w dh
WipeRect -> Rect dx dy dw dh
(dx, dy) = (x+(1-(step t))*w/2, y+(1-(step t))*h/2)
(dw, dh) = ((step t)*w, (step t)*h)
step t = if isWipeIn
then fwdStep t
else 1-(fwdStep t)
fwdStep t = clamp 0 1 $ t/(fromIntegral dur)
dir = fromMaybe WipeLeft _wpcDirection
dur = fromMaybe 500 _tfcDuration
TransformCfg{..} = _wpcTransformCfg
WipeCfg{..} = mconcat configs