packages feed

monomer-1.6.0.0: src/Monomer/Widgets/Animation/Fade.hs

{-|
Module      : Monomer.Widgets.Animation.Fade
Copyright   : (c) 2018 Francisco Vallarino
License     : BSD-3-Clause (see the LICENSE file)
Maintainer  : fjvallarino@gmail.com
Stability   : experimental
Portability : non-portable

Fade animation widget. Wraps a child widget whose content will be animated.

Messages:

- Accepts an 'AnimationMsg', used to control the state of the animation.
-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE Strict #-}

module Monomer.Widgets.Animation.Fade (
  -- * Configuration
  FadeCfg,
  -- * Constructors
  animFadeIn,
  animFadeIn_,
  animFadeOut,
  animFadeOut_
) where

import Control.Lens ((&), (.~))
import Data.Default
import Data.Maybe

import Monomer.Widgets.Container
import Monomer.Widgets.Animation.Transform

import qualified Monomer.Lens as L

{-|
Configuration options for fade:

- '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.
-}
newtype FadeCfg s e = FadeCfg {
  _fdcTransformCfg :: TransformCfg s e
} deriving (Eq, Show)

instance Default (FadeCfg s e) where
  def = FadeCfg {
    _fdcTransformCfg = def
  }

instance Semigroup (FadeCfg s e) where
  (<>) fc1 fc2 = FadeCfg {
    _fdcTransformCfg = _fdcTransformCfg fc1 <> _fdcTransformCfg fc2
  }

instance Monoid (FadeCfg s e) where
  mempty = def

instance CmbAutoStart (FadeCfg s e) where
  autoStart_ start = def {
    _fdcTransformCfg = autoStart_ start
  }

instance CmbDuration (FadeCfg s e) Millisecond where
  duration dur = def {
    _fdcTransformCfg = duration dur
  }

instance WidgetEvent e => CmbOnFinished (FadeCfg s e) e where
  onFinished handler = def {
    _fdcTransformCfg = onFinished handler
  }

instance CmbOnFinishedReq (FadeCfg s e) s e where
  onFinishedReq req = def {
    _fdcTransformCfg = onFinishedReq req
  }

-- | Animates a widget from not visible state to fully visible.
animFadeIn
  :: WidgetEvent e
  => WidgetNode s e  -- ^ The child node.
  -> WidgetNode s e  -- ^ The created animation container.
animFadeIn managed = animFadeIn_ def managed

-- | Animates a widget from not visible state to fully visible. Accepts config.
animFadeIn_
  :: WidgetEvent e
  => [FadeCfg s e]     -- ^ The config options.
  -> WidgetNode s e  -- ^ The child node.
  -> WidgetNode s e  -- ^ The created animation container.
animFadeIn_ configs managed = makeNode configs managed True
  & L.info . L.widgetType .~ "animFadeIn"

-- | Animates a widget from visible state to not visible.
animFadeOut
  :: WidgetEvent e
  => WidgetNode s e  -- ^ The child node.
  -> WidgetNode s e  -- ^ The created animation container.
animFadeOut managed = animFadeOut_ def managed

-- | Animates a widget from visible state to not visible. Accepts config.
animFadeOut_
  :: WidgetEvent e
  => [FadeCfg s e]     -- ^ The config options.
  -> WidgetNode s e  -- ^ The child node.
  -> WidgetNode s e  -- ^ The created animation container.
animFadeOut_ configs managed = makeNode configs managed False
  & L.info . L.widgetType .~ "animFadeOut"

makeNode
  :: WidgetEvent e
  => [FadeCfg s e]
  -> WidgetNode s e
  -> Bool
  -> WidgetNode s e
makeNode configs managed isFadeIn = node where
  node = animTransform_ [_fdcTransformCfg] f managed
  f t _ = [animGlobalAlpha $ alpha t]
  alpha t = if isFadeIn
    then (currStep t)
    else 1-(currStep t)
  currStep t = clampAlpha $ t/(fromIntegral dur)
  dur = fromMaybe 500 _tfcDuration
  TransformCfg{..} = _fdcTransformCfg
  FadeCfg{..} = mconcat configs