{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Diagrams.TwoD.Attributes (
Texture(..), solid, _SC, _AC, _LG, _RG, defaultLG, defaultRG
, GradientStop(..), stopColor, stopFraction, mkStops
, SpreadMethod(..), lineLGradient, lineRGradient
, LGradient(..), lGradStops, lGradTrans, lGradStart, lGradEnd
, lGradSpreadMethod, mkLinearGradient
, RGradient(..), rGradStops, rGradTrans
, rGradCenter0, rGradRadius0, rGradCenter1, rGradRadius1
, rGradSpreadMethod, mkRadialGradient
, LineTexture(..), _LineTexture, getLineTexture, lineTexture, lineTextureA
, mkLineTexture, _lineTexture
, lineColor, lc, lcA
, FillTexture(..), _FillTexture, getFillTexture, fillTexture
, mkFillTexture, _fillTexture, _fillTextureR
, fillColor, fc, fcA, recommendFillColor
, splitTextureFills
) where
import Control.Lens hiding (transform)
import Data.Colour hiding (AffineSpace, over)
import Data.Data
import Data.Default.Class
import Data.Monoid.Recommend
import Data.Semigroup
import Diagrams.Attributes
import Diagrams.Attributes.Compile
import Diagrams.Core
import Diagrams.Core.Types (RTree)
import Diagrams.Located (unLoc)
import Diagrams.Path (Path, pathTrails)
import Diagrams.Trail (isLoop)
import Diagrams.TwoD.Types
import Diagrams.Util
data GradientStop d = GradientStop
{ _stopColor :: SomeColor
, _stopFraction :: d
}
makeLensesWith (lensRules & generateSignatures .~ False) ''GradientStop
stopColor :: Lens' (GradientStop n) SomeColor
stopFraction :: Lens' (GradientStop n) n
data SpreadMethod = GradPad | GradReflect | GradRepeat
data LGradient n = LGradient
{ _lGradStops :: [GradientStop n]
, _lGradStart :: Point V2 n
, _lGradEnd :: Point V2 n
, _lGradTrans :: Transformation V2 n
, _lGradSpreadMethod :: SpreadMethod }
type instance V (LGradient n) = V2
type instance N (LGradient n) = n
makeLensesWith (lensRules & generateSignatures .~ False) ''LGradient
instance Fractional n => Transformable (LGradient n) where
transform = over lGradTrans . transform
lGradStops :: Lens' (LGradient n) [GradientStop n]
lGradTrans :: Lens' (LGradient n) (Transformation V2 n)
lGradStart :: Lens' (LGradient n) (Point V2 n)
lGradEnd :: Lens' (LGradient n) (Point V2 n)
lGradSpreadMethod :: Lens' (LGradient n) SpreadMethod
data RGradient n = RGradient
{ _rGradStops :: [GradientStop n]
, _rGradCenter0 :: Point V2 n
, _rGradRadius0 :: n
, _rGradCenter1 :: Point V2 n
, _rGradRadius1 :: n
, _rGradTrans :: Transformation V2 n
, _rGradSpreadMethod :: SpreadMethod }
makeLensesWith (lensRules & generateSignatures .~ False) ''RGradient
type instance V (RGradient n) = V2
type instance N (RGradient n) = n
instance Fractional n => Transformable (RGradient n) where
transform = over rGradTrans . transform
rGradStops :: Lens' (RGradient n) [GradientStop n]
rGradCenter0 :: Lens' (RGradient n) (Point V2 n)
rGradRadius0 :: Lens' (RGradient n) n
rGradCenter1 :: Lens' (RGradient n) (Point V2 n)
rGradRadius1 :: Lens' (RGradient n) n
rGradTrans :: Lens' (RGradient n) (Transformation V2 n)
rGradSpreadMethod :: Lens' (RGradient n) SpreadMethod
data Texture n = SC SomeColor | LG (LGradient n) | RG (RGradient n)
deriving Typeable
type instance V (Texture n) = V2
type instance N (Texture n) = n
makePrisms ''Texture
_AC :: Prism' (Texture n) (AlphaColour Double)
_AC = _SC . _SomeColor
instance Floating n => Transformable (Texture n) where
transform t (LG lg) = LG $ transform t lg
transform t (RG rg) = RG $ transform t rg
transform _ sc = sc
solid :: Color a => a -> Texture n
solid = SC . SomeColor
defaultLG :: Fractional n => Texture n
defaultLG = LG LGradient
{ _lGradStops = []
, _lGradStart = mkP2 (-0.5) 0
, _lGradEnd = mkP2 0.5 0
, _lGradTrans = mempty
, _lGradSpreadMethod = GradPad
}
defaultRG :: Fractional n => Texture n
defaultRG = RG RGradient
{ _rGradStops = []
, _rGradCenter0 = mkP2 0 0
, _rGradRadius0 = 0.0
, _rGradCenter1 = mkP2 0 0
, _rGradRadius1 = 0.5
, _rGradTrans = mempty
, _rGradSpreadMethod = GradPad
}
mkStops :: [(Colour Double, d, Double)] -> [GradientStop d]
mkStops = map (\(x, y, z) -> GradientStop (SomeColor (withOpacity x z)) y)
mkLinearGradient :: Num n => [GradientStop n] -> Point V2 n -> Point V2 n -> SpreadMethod -> Texture n
mkLinearGradient stops start end spreadMethod
= LG (LGradient stops start end mempty spreadMethod)
mkRadialGradient :: Num n => [GradientStop n] -> Point V2 n -> n
-> Point V2 n -> n -> SpreadMethod -> Texture n
mkRadialGradient stops c0 r0 c1 r1 spreadMethod
= RG (RGradient stops c0 r0 c1 r1 mempty spreadMethod)
newtype LineTexture n = LineTexture (Last (Texture n))
deriving (Typeable, Semigroup)
instance (Typeable n) => AttributeClass (LineTexture n)
type instance V (LineTexture n) = V2
type instance N (LineTexture n) = n
_LineTexture :: Iso (LineTexture n) (LineTexture n')
(Texture n) (Texture n')
_LineTexture = iso getLineTexture (LineTexture . Last)
instance Floating n => Transformable (LineTexture n) where
transform t (LineTexture (Last tx)) = LineTexture (Last $ transform t tx)
instance Default (LineTexture n) where
def = _LineTexture . _SC ## SomeColor black
mkLineTexture :: Texture n -> LineTexture n
mkLineTexture = LineTexture . Last
getLineTexture :: LineTexture n -> Texture n
getLineTexture (LineTexture (Last t)) = t
lineTexture :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => Texture n -> a -> a
lineTexture = applyTAttr . LineTexture . Last
lineTextureA :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => LineTexture n -> a -> a
lineTextureA = applyTAttr
_lineTexture :: (Floating n, Typeable n) => Lens' (Style V2 n) (Texture n)
_lineTexture = atTAttr . anon def isDef . _LineTexture
where
isDef = anyOf (_LineTexture . _AC) (== opaque black)
lineColor :: (InSpace V2 n a, Color c, Typeable n, Floating n, HasStyle a) => c -> a -> a
lineColor = lineTexture . SC . SomeColor
lc :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => Colour Double -> a -> a
lc = lineColor
lcA :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => AlphaColour Double -> a -> a
lcA = lineColor
lineLGradient :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => LGradient n -> a -> a
lineLGradient g = lineTexture (LG g)
lineRGradient :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => RGradient n -> a -> a
lineRGradient g = lineTexture (RG g)
newtype FillTexture n = FillTexture (Recommend (Last (Texture n)))
deriving (Typeable, Semigroup)
instance Typeable n => AttributeClass (FillTexture n)
_FillTexture :: Iso' (FillTexture n) (Recommend (Texture n))
_FillTexture = iso getter setter
where
getter (FillTexture (Recommend (Last t))) = Recommend t
getter (FillTexture (Commit (Last t))) = Commit t
setter (Recommend t) = FillTexture (Recommend (Last t))
setter (Commit t) = FillTexture (Commit (Last t))
type instance V (FillTexture n) = V2
type instance N (FillTexture n) = n
instance Floating n => Transformable (FillTexture n) where
transform = over (_FillTexture . _recommend) . transform
instance Default (FillTexture n) where
def = mkFillTexture $ _AC ## transparent
getFillTexture :: FillTexture n -> Texture n
getFillTexture (FillTexture tx) = getLast . getRecommend $ tx
fillTexture :: (InSpace V2 n a, Typeable n, Floating n, HasStyle a) => Texture n -> a -> a
fillTexture = applyTAttr . mkFillTexture
mkFillTexture :: Texture n -> FillTexture n
mkFillTexture = FillTexture . Commit . Last
_fillTextureR :: (Typeable n, Floating n) => Lens' (Style V2 n) (Recommend (Texture n))
_fillTextureR = atTAttr . anon def isDef . _FillTexture
where
isDef = anyOf (_FillTexture . _Recommend . _AC) (== transparent)
_fillTexture :: (Typeable n, Floating n) => Lens' (Style V2 n) (Texture n)
_fillTexture = _fillTextureR . committed
fillColor :: (InSpace V2 n a, Color c, Typeable n, Floating n, HasStyle a) => c -> a -> a
fillColor = fillTexture . SC . SomeColor
recommendFillColor :: (InSpace V2 n a, Color c, Typeable n, Floating n, HasStyle a) => c -> a -> a
recommendFillColor =
applyTAttr . FillTexture . Recommend . Last . SC . SomeColor
fc :: (InSpace V2 n a, Floating n, Typeable n, HasStyle a) => Colour Double -> a -> a
fc = fillColor
fcA :: (InSpace V2 n a, Floating n, Typeable n, HasStyle a) => AlphaColour Double -> a -> a
fcA = fillColor
data FillTextureLoops n = FillTextureLoops
instance Typeable n => SplitAttribute (FillTextureLoops n) where
type AttrType (FillTextureLoops n) = FillTexture n
type PrimType (FillTextureLoops n) = Path V2 n
primOK _ = all (isLoop . unLoc) . pathTrails
splitTextureFills
:: forall b v n a. (
Typeable n) => RTree b v n a -> RTree b v n a
splitTextureFills = splitAttr (FillTextureLoops :: FillTextureLoops n)