{-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Attributes -- Copyright : (c) 2011 diagrams-lib team (see LICENSE) -- License : BSD-style (see LICENSE) -- Maintainer : diagrams-discuss@googlegroups.com -- -- Diagrams may have /attributes/ which affect the way they are -- rendered. This module defines some common attributes; particular -- backends may also define more backend-specific attributes. -- -- Every attribute type must have a /semigroup/ structure, that is, an -- associative binary operation for combining two attributes into one. -- Unless otherwise noted, all the attributes defined here use the -- 'Last' structure, that is, combining two attributes simply keeps -- the second one and throws away the first. This means that child -- attributes always override parent attributes. -- ----------------------------------------------------------------------------- module Diagrams.Attributes ( -- * Color -- $color Color(..), SomeColor(..), someToAlpha -- ** Opacity , Opacity, getOpacity, opacity -- ** Converting colors , colorToSRGBA, colorToRGBA -- * Line stuff -- ** Cap style , LineCap(..), LineCapA, getLineCap, lineCap -- ** Join style , LineJoin(..), LineJoinA, getLineJoin, lineJoin -- ** Miter limit , LineMiterLimit(..), getLineMiterLimit, lineMiterLimit, lineMiterLimitA ) where import Data.Colour import Data.Colour.RGBSpace (RGB (..)) import Data.Colour.SRGB (toSRGB) import Data.Default.Class import Data.Semigroup import Data.Typeable import Diagrams.Core ------------------------------------------------------------ -- Color ------------------------------------------------- ------------------------------------------------------------ -- $color -- Diagrams outsources all things color-related to Russell O\'Connor\'s -- very nice colour package -- (<http://hackage.haskell.org/package/colour>). For starters, it -- provides a large collection of standard color names. However, it -- also provides a rich set of combinators for combining and -- manipulating colors; see its documentation for more information. -- | The 'Color' type class encompasses color representations which -- can be used by the Diagrams library. Instances are provided for -- both the 'Data.Colour.Colour' and 'Data.Colour.AlphaColour' types -- from the "Data.Colour" library. class Color c where -- | Convert a color to its standard representation, AlphaColour. toAlphaColour :: c -> AlphaColour Double -- | Convert from an AlphaColour Double. Note that this direction -- may lose some information. For example, the instance for -- 'Colour' drops the alpha channel. fromAlphaColour :: AlphaColour Double -> c -- | An existential wrapper for instances of the 'Color' class. data SomeColor = forall c. Color c => SomeColor c deriving Typeable someToAlpha :: SomeColor -> AlphaColour Double someToAlpha (SomeColor c) = toAlphaColour c instance (Floating a, Real a) => Color (Colour a) where toAlphaColour = opaque . colourConvert fromAlphaColour = colourConvert . (`over` black) instance (Floating a, Real a) => Color (AlphaColour a) where toAlphaColour = alphaColourConvert fromAlphaColour = alphaColourConvert instance Color SomeColor where toAlphaColour (SomeColor c) = toAlphaColour c fromAlphaColour c = SomeColor c -- | Convert to sRGBA. colorToSRGBA, colorToRGBA :: Color c => c -> (Double, Double, Double, Double) colorToSRGBA col = (r, g, b, a) where c' = toAlphaColour col c = alphaToColour c' a = alphaChannel c' RGB r g b = toSRGB c colorToRGBA = colorToSRGBA {-# DEPRECATED colorToRGBA "Renamed to colorToSRGBA." #-} alphaToColour :: (Floating a, Ord a, Fractional a) => AlphaColour a -> Colour a alphaToColour ac | alphaChannel ac == 0 = ac `over` black | otherwise = darken (recip (alphaChannel ac)) (ac `over` black) ------------------------------------------------------------ -- Opacity -- | Although the individual colors in a diagram can have -- transparency, the opacity/transparency of a diagram as a whole -- can be specified with the @Opacity@ attribute. The opacity is a -- value between 1 (completely opaque, the default) and 0 -- (completely transparent). Opacity is multiplicative, that is, -- @'opacity' o1 . 'opacity' o2 === 'opacity' (o1 * o2)@. In other -- words, for example, @opacity 0.8@ means \"decrease this diagram's -- opacity to 80% of its previous opacity\". newtype Opacity = Opacity (Product Double) deriving (Typeable, Semigroup) instance AttributeClass Opacity getOpacity :: Opacity -> Double getOpacity (Opacity (Product d)) = d -- | Multiply the opacity (see 'Opacity') by the given value. For -- example, @opacity 0.8@ means \"decrease this diagram's opacity to -- 80% of its previous opacity\". opacity :: HasStyle a => Double -> a -> a opacity = applyAttr . Opacity . Product ------------------------------------------------------------ -- Line stuff ------------------------------------- ------------------------------------------------------------ -- | What sort of shape should be placed at the endpoints of lines? data LineCap = LineCapButt -- ^ Lines end precisely at their endpoints. | LineCapRound -- ^ Lines are capped with semicircles -- centered on endpoints. | LineCapSquare -- ^ Lines are capped with a squares -- centered on endpoints. deriving (Eq,Show,Typeable) newtype LineCapA = LineCapA (Last LineCap) deriving (Typeable, Semigroup, Eq) instance AttributeClass LineCapA instance Default LineCap where def = LineCapButt getLineCap :: LineCapA -> LineCap getLineCap (LineCapA (Last c)) = c -- | Set the line end cap attribute. lineCap :: HasStyle a => LineCap -> a -> a lineCap = applyAttr . LineCapA . Last -- | How should the join points between line segments be drawn? data LineJoin = LineJoinMiter -- ^ Use a \"miter\" shape (whatever that is). | LineJoinRound -- ^ Use rounded join points. | LineJoinBevel -- ^ Use a \"bevel\" shape (whatever -- that is). Are these... -- carpentry terms? deriving (Eq,Show,Typeable) newtype LineJoinA = LineJoinA (Last LineJoin) deriving (Typeable, Semigroup, Eq) instance AttributeClass LineJoinA instance Default LineJoin where def = LineJoinMiter getLineJoin :: LineJoinA -> LineJoin getLineJoin (LineJoinA (Last j)) = j -- | Set the segment join style. lineJoin :: HasStyle a => LineJoin -> a -> a lineJoin = applyAttr . LineJoinA . Last -- | Miter limit attribute affecting the 'LineJoinMiter' joins. -- For some backends this value may have additional effects. newtype LineMiterLimit = LineMiterLimit (Last Double) deriving (Typeable, Semigroup) instance AttributeClass LineMiterLimit instance Default LineMiterLimit where def = LineMiterLimit (Last 10) getLineMiterLimit :: LineMiterLimit -> Double getLineMiterLimit (LineMiterLimit (Last l)) = l -- | Set the miter limit for joins with 'LineJoinMiter'. lineMiterLimit :: HasStyle a => Double -> a -> a lineMiterLimit = applyAttr . LineMiterLimit . Last -- | Apply a 'LineMiterLimit' attribute. lineMiterLimitA :: HasStyle a => LineMiterLimit -> a -> a lineMiterLimitA = applyAttr