craftwerk-0.1: src/Graphics/Craftwerk/Core/Style.hs
-- |
-- Module : Graphics.Craftwerk.Core.Style
-- Copyright : (c) Malte Harder 2011
-- License : MIT
-- Maintainer : Malte Harder <malte.harder@gmail.com>
--
-- 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)