{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Geometry.Ipe.Attributes where
import Control.Lens hiding (rmap, Const)
import Data.Colour.SRGB
import Data.Semigroup
import Data.Singletons
import Data.Singletons.TH
import Data.Text (Text)
import Data.Vinyl
import Data.Vinyl.Functor
import Data.Vinyl.TypeLevel
import GHC.Exts
data AttributeUniverse =
Layer | Matrix | Pin | Transformations
| Stroke | Fill | Pen | Size
| Dash | LineCap | LineJoin
| FillRule | Arrow | RArrow | Opacity | Tiling | Gradient
| Clip
deriving (Show,Read,Eq)
genSingletons [ ''AttributeUniverse ]
type CommonAttributes = [ Layer, Matrix, Pin, Transformations ]
type TextLabelAttributes = CommonAttributes
type MiniPageAttributes = CommonAttributes
type ImageAttributes = CommonAttributes
type SymbolAttributes = CommonAttributes ++
[Stroke, Fill, Pen, Size]
type PathAttributes = CommonAttributes ++
[ Stroke, Fill, Dash, Pen, LineCap, LineJoin
, FillRule, Arrow, RArrow, Opacity, Tiling, Gradient
]
type GroupAttributes = CommonAttributes ++ '[ 'Clip]
newtype Attr (f :: TyFun u * -> *)
(label :: u) = GAttr { _getAttr :: Maybe (Apply f label) }
deriving instance Show (Apply f label) => Show (Attr f label)
deriving instance Read (Apply f label) => Read (Attr f label)
deriving instance Eq (Apply f label) => Eq (Attr f label)
deriving instance Ord (Apply f label) => Ord (Attr f label)
makeLenses ''Attr
pattern Attr :: Apply f label -> Attr f label
pattern Attr x = GAttr (Just x)
pattern NoAttr :: Attr f label
pattern NoAttr = GAttr Nothing
instance Semigroup (Attr f l) where
_ <> b@(Attr _) = b
a <> _ = a
instance Monoid (Attr f l) where
mempty = NoAttr
mappend = (<>)
newtype Attributes (f :: TyFun u * -> *) (ats :: [u]) =
Attrs { _unAttrs :: Rec (Attr f) ats }
makeLenses ''Attributes
deriving instance (RecAll (Attr f) ats Show) => Show (Attributes f ats)
instance (RecAll (Attr f) ats Eq) => Eq (Attributes f ats) where
(Attrs a) == (Attrs b) = and . recordToList
. zipRecsWith (\x (Compose (Dict y)) -> Const $ x == y) a
. (reifyConstraint (Proxy :: Proxy Eq)) $ b
instance RecApplicative ats => Monoid (Attributes f ats) where
mempty = Attrs $ rpure mempty
a `mappend` b = a <> b
instance Semigroup (Attributes f ats) where
(Attrs as) <> (Attrs bs) = Attrs $ zipRecsWith mappend as bs
zipRecsWith :: (forall a. f a -> g a -> h a)
-> Rec f as -> Rec g as -> Rec h as
zipRecsWith _ RNil _ = RNil
zipRecsWith f (r :& rs) (s :& ss) = f r s :& zipRecsWith f rs ss
attrLens :: (at ∈ ats) => proxy at -> Lens' (Attributes f ats) (Maybe (Apply f at))
attrLens p = unAttrs.rlens p.getAttr
lookupAttr :: (at ∈ ats) => proxy at -> Attributes f ats -> Maybe (Apply f at)
lookupAttr p = view (attrLens p)
setAttr :: forall proxy at ats f. (at ∈ ats)
=> proxy at -> Apply f at -> Attributes f ats -> Attributes f ats
setAttr _ a (Attrs r) = Attrs $ rput (Attr a :: Attr f at) r
takeAttr :: forall proxy at ats f. (at ∈ ats)
=> proxy at -> Attributes f ats -> ( Maybe (Apply f at)
, Attributes f ats )
takeAttr p ats = (lookupAttr p ats, ats&attrLens p .~ Nothing)
unSetAttr :: forall proxy at ats f. (at ∈ ats)
=> proxy at -> Attributes f ats -> Attributes f ats
unSetAttr p = snd . takeAttr p
attr :: (at ∈ ats, RecApplicative ats)
=> proxy at -> Apply f at -> Attributes f ats
attr p x = setAttr p x mempty
data PinType = No | Yes | Horizontal | Vertical
deriving (Eq,Show,Read)
data TransformationTypes = Affine | Rigid | Translations deriving (Show,Read,Eq)
data IpeValue v = Named Text | Valued v deriving (Show,Eq,Ord,Functor,Foldable,Traversable)
instance IsString (IpeValue v) where
fromString = Named . fromString
newtype IpeSize r = IpeSize (IpeValue r) deriving (Show,Eq,Ord)
newtype IpePen r = IpePen (IpeValue r) deriving (Show,Eq,Ord)
newtype IpeColor r = IpeColor (IpeValue (RGB r)) deriving (Show,Eq)
instance Ord r => Ord (IpeColor r) where
(IpeColor c) `compare` (IpeColor c') = fmap f c `compare` fmap f c'
where
f (RGB r g b) = (r,g,b)
data IpeDash r = DashNamed Text
| DashPattern [r] r
deriving (Show,Eq)
data FillType = Wind | EOFill deriving (Show,Read,Eq)
type IpeOpacity = Text
type IpeTiling = Text
type IpeGradient = Text
data IpeArrow r = IpeArrow { _arrowName :: Text
, _arrowSize :: IpeSize r
} deriving (Show,Eq)
makeLenses ''IpeArrow
normalArrow :: IpeArrow r
normalArrow = IpeArrow "normal" (IpeSize $ Named "normal/normal")
class IpeAttrName (a :: AttributeUniverse) where
attrName :: Proxy a -> Text
instance IpeAttrName Layer where attrName _ = "layer"
instance IpeAttrName Matrix where attrName _ = "matrix"
instance IpeAttrName Pin where attrName _ = "pin"
instance IpeAttrName Transformations where attrName _ = "transformations"
instance IpeAttrName Stroke where attrName _ = "stroke"
instance IpeAttrName Fill where attrName _ = "fill"
instance IpeAttrName Pen where attrName _ = "pen"
instance IpeAttrName Size where attrName _ = "size"
instance IpeAttrName Dash where attrName _ = "dash"
instance IpeAttrName LineCap where attrName _ = "cap"
instance IpeAttrName LineJoin where attrName _ = "join"
instance IpeAttrName FillRule where attrName _ = "fillrule"
instance IpeAttrName Arrow where attrName _ = "arrow"
instance IpeAttrName RArrow where attrName _ = "rarrow"
instance IpeAttrName Opacity where attrName _ = "opacity"
instance IpeAttrName Tiling where attrName _ = "tiling"
instance IpeAttrName Gradient where attrName _ = "gradient"
instance IpeAttrName Clip where attrName _ = "clip"
type family AllSatisfy (c :: k -> Constraint) (xs :: [k]) :: Constraint where
AllSatisfy c '[] = ()
AllSatisfy c (x ': xs) = (c x, AllSatisfy c xs)
writeAttrNames :: AllSatisfy IpeAttrName rs => Rec f rs -> Rec (Const Text) rs
writeAttrNames RNil = RNil
writeAttrNames (x :& xs) = Const (write'' x) :& writeAttrNames xs
where
write'' :: forall f s. IpeAttrName s => f s -> Text
write'' _ = attrName (Proxy :: Proxy s)