-- | -- Module : Graphics.Craftwerk.Core.Style -- Copyright : (c) Malte Harder 2011 -- License : MIT -- Maintainer : Malte Harder -- -- Styles in craftwerk are nodes in the figure tree and the style at the node is -- applied to all subnodes. If a field of a style is empty (i.e its value -- is 'Nothing') the value of the next parent style node is applied. module Graphics.Craftwerk.Core.Style ( -- * Data types StyleProperties(..) , LineCap(..) , LineJoin(..) , ArrowTip(..) -- * Named styles , emptyStyle , newStyle , defaultStyle , setLineWidth , fillOnly , strokeOnly -- * Property values , yes , no , rgb , width , verythin , thin , semithick , thick , verythick , ultrathick , limit , phase -- * Property access and merging , getProperty , mergeProperties -- * Arrow functions , arrow , (<=>) , (===) , (==>) , (<==) ) where import Graphics.Craftwerk.Core.Color import Data.Maybe data ArrowDummy = ArrowDummy deriving Show data ArrowTip = TipNone | TipDefault deriving (Show,Eq) type ArrowTips = (ArrowTip, ArrowTip) data LineCap = CapRect | CapButt | CapRound deriving (Show,Eq) data LineJoin = JoinRound | JoinBevel | JoinMiter deriving (Show,Eq) -- | A record holding all possible properties. data StyleProperties = StyleProperties { lineWidth :: Maybe Double , lineColor :: Maybe FigureColor , fillColor :: Maybe FigureColor , fill :: Maybe Bool , stroke :: Maybe Bool , clip :: Maybe Bool , closePath :: Maybe Bool , dashes :: Maybe [Double] , dashPhase :: Maybe Double , lineCap :: Maybe LineCap , lineJoin :: Maybe LineJoin , miterLimit :: Maybe Double , arrowTips :: Maybe ArrowTips } deriving (Show, Eq) -- | A style where no property has been set. emptyStyle :: StyleProperties emptyStyle = StyleProperties Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing Nothing -- | Alias for empty style, makes style construction nicer. newStyle :: StyleProperties newStyle = emptyStyle -- | The default style used at the root node of any 'Figure'. defaultStyle :: StyleProperties defaultStyle = StyleProperties { lineWidth = Just 1.0 , lineColor = Just black , fillColor = Just white , stroke = Just True , fill = Just False , clip = Just False , closePath = Just False , dashes = Just [] :: Maybe [Double] , dashPhase = Just 0.0 , lineCap = Just CapButt , lineJoin = Just JoinMiter , miterLimit = Just 10.0 , arrowTips = Just (TipNone, TipNone) } setLineWidth :: Maybe Double -> StyleProperties setLineWidth a = newStyle { lineWidth = a } fillOnly :: StyleProperties fillOnly = newStyle { fill = yes, stroke = no } strokeOnly :: StyleProperties strokeOnly = newStyle { fill = no, stroke = yes} -- | Alias for 'Just True' to make style specification more convenient. yes :: Maybe Bool yes = Just True -- | Alias for 'Just False' to make style specification more convenient. no :: Maybe Bool no = Just False -- | Make a rgb color property. rgb :: Double -> Double -> Double -> Maybe FigureColor rgb r g b = Just $ sRGB r g b -- | Alias for 'Just' width :: Double -> Maybe Double width = Just -- | Width 0.2. verythin :: Maybe Double verythin = width 0.2 -- | Width 0.4. thin :: Maybe Double thin = width 0.4 -- | Width 0.6. semithick :: Maybe Double semithick = width 0.6 -- | Width 0.8. thick :: Maybe Double thick = width 0.8 -- | Width 1.2. verythick :: Maybe Double verythick = width 1.2 -- | Width 1.6. ultrathick :: Maybe Double ultrathick = width 1.6 -- | Alias for 'Just'. limit :: Double -> Maybe Double limit = width -- | Alias for 'Just'. phase :: Double -> Maybe Double phase = width -- | Read a property from a style property record returning the value of -- the default style if the value is 'Nothing'. getProperty :: StyleProperties -> (StyleProperties -> Maybe a) -> a getProperty s f = fromMaybe (fromJust $ f defaultStyle) (f s) mergeProperty :: StyleProperties -> StyleProperties -> (StyleProperties -> Maybe a) -> Maybe a mergeProperty s t f = case f t of Nothing -> f s x -> x -- | Merge two property records, where the second argument overwrites fields of -- the first unless a field is 'Nothing'. mergeProperties :: StyleProperties -> StyleProperties -> StyleProperties mergeProperties s t = StyleProperties { lineWidth = mergeProperty s t lineWidth , lineColor = mergeProperty s t lineColor , fillColor = mergeProperty s t fillColor , fill = mergeProperty s t fill , stroke = mergeProperty s t stroke , clip = mergeProperty s t clip , closePath = mergeProperty s t closePath , dashes = mergeProperty s t dashes , dashPhase = mergeProperty s t dashPhase , lineCap = mergeProperty s t lineCap , lineJoin = mergeProperty s t lineJoin , miterLimit = mergeProperty s t miterLimit , arrowTips = mergeProperty s t arrowTips } -- * Arrow styles -- | Arrow tip styles can be specified by using the notation 'arrow (<==)' arrow :: (ArrowDummy -> ArrowTips) -> Maybe ArrowTips arrow f = Just (f ArrowDummy) (<=>) :: ArrowDummy -> ArrowTips (<=>) _ = (TipDefault, TipDefault) (===) :: ArrowDummy -> ArrowTips (===) _ = (TipNone, TipNone) (==>) :: ArrowDummy -> ArrowTips (==>) _ = (TipNone, TipDefault) (<==) :: ArrowDummy -> ArrowTips (<==) _ = (TipDefault, TipNone)