{-| Module : Diagrams.Backend.HsQML.DiagramObj.Commands Description : Functions to create a DiagramObj containing a single command. Copyright : (c) Marcin Mrotek, 2015 License : BSD-3 Maintainer : marcin.jan.mrotek@gmail.com Stability : experimental As 'DiagramObj' is a 'Monoid', complex diagrams may be obtained by 'mappend'ing simple ones together. This module provides functions creating 'DiagramObj's containing a single command each. -} module Diagrams.Backend.HsQML.DiagramObj.Commands where import Diagrams.Backend.HsQML.GradientObj import Diagrams.Backend.HsQML.DiagramObj.Type import qualified Diagrams.Backend.HsQML.DiagramObj.Signals as S import Data.Text (pack) import Control.Lens hiding (over) import Control.Monad (forM_) import Control.Monad.IO.Class import Data.Colour import Data.Colour.SRGB import Diagrams.Prelude hiding (over) import Diagrams.TwoD.Attributes import Diagrams.TwoD.Text import Graphics.QML save :: DiagramObj () -- ^Push the current state (style, font, etc) onto the state stack. save = DiagramObj $ fireSignal S.save restore :: DiagramObj () -- ^Pop the current state (style, font, etc) from the state stack. restore = DiagramObj $ fireSignal S.restore text :: String -> Double -> Double -> DiagramObj () -- ^Display text on a specified point. text txt x y = DiagramObj $ \this -> fireSignal S.renderText this (pack txt) x y beginPath :: DiagramObj () -- ^Start assembling a new path. beginPath = DiagramObj $ fireSignal S.beginPath closePath :: DiagramObj () -- ^Connect the current path vertex to the start of the path. closePath = DiagramObj $ fireSignal S.closePath moveTo :: P2 Double -> DiagramObj () -- ^Change the current position. moveTo p = let (x,y) = unp2 p in DiagramObj $ \this -> fireSignal S.moveTo this x y stroke :: DiagramObj () -- ^Stroke the current path. stroke = DiagramObj $ fireSignal S.stroke fill :: DiagramObj () -- ^Fill the current path. Works only on paths that were previously 'close'd. fill = DiagramObj $ fireSignal S.fill lineTo :: P2 Double -> DiagramObj () -- ^Draw a straight line from the current position to a given point. lineTo p = DiagramObj $ \this -> fireSignal S.lineTo this x y where (x,y) = unp2 p bezierCurveTo :: P2 Double -- ^First control point. -> P2 Double -- ^Second control point -> P2 Double -- ^End point. -> DiagramObj () -- ^Draw a bezier curve from the current position to a given point, using two control points. bezierCurveTo cp1 cp2 p = DiagramObj $ \this -> fireSignal S.bezierCurveTo this cp1x cp1y cp2x cp2y x y where (cp1x, cp1y) = unp2 cp1 (cp2x, cp2y) = unp2 cp2 ( x, y) = unp2 p setLineCap :: LineCap -> DiagramObj () -- ^Set the line cap style. setLineCap cap = DiagramObj $ \this -> fireSignal S.setLineCap this . pack $ case cap of LineCapButt -> "butt" LineCapRound -> "round" LineCapSquare -> "square" setLineJoin :: LineJoin -> DiagramObj () -- ^Set the line join style. setLineJoin j = DiagramObj $ \this -> fireSignal S.setLineJoin this . pack $ case j of LineJoinMiter -> "miter" LineJoinRound -> "round" LineJoinBevel -> "bevel" setLineMiterLimit :: LineMiterLimit -> DiagramObj () -- ^Set the miter limit. setLineMiterLimit m = DiagramObj $ \this -> fireSignal S.setLineMiterLimit this (getLineMiterLimit m) setOpacity :: Opacity -> DiagramObj () -- ^Set the global alpha (subject to 'save' and 'restore'). setOpacity o = DiagramObj $ \this -> fireSignal S.setGlobalAlpha this (getOpacity o) setLineWidth :: LineWidth Double -> DiagramObj () -- ^Set the line width (output coordinates assumed). setLineWidth w = DiagramObj $ \this -> fireSignal S.setLineWidth this (getLineWidth w) getRGBA :: SomeColor -> (Double, Double, Double, Double) -- ^Convert a colour to a tuple of (r,g,b,a) components. getRGBA c = (r,g,b,a) where RGB r g b = toSRGB (ac `over` black) a = alphaChannel ac ac = someToAlpha c getLinearGradient :: LGradient Double -> DiagramObj (ObjRef GradientObj) -- ^Create a linear gradient. getLinearGradient lg = DiagramObj $ \this -> do g <- newGradient fireSignal S.connectLinearGradient this g x0 y0 x1 y1 return g where (x0,y0) = unp2.papply (lg^.lGradTrans) $ lg^.lGradStart (x1,y1) = unp2.papply (lg^.lGradTrans) $ lg^.lGradEnd getRadialGradient :: RGradient Double -> DiagramObj (ObjRef GradientObj) -- ^Create a radial gradient. getRadialGradient rg = DiagramObj $ \this -> do g <- newGradient fireSignal S.connectRadialGradient this g x0 y0 r0 x1 y1 r1 return g where (x0,y0) = unp2.papply (rg^.rGradTrans) $ rg^.rGradCenter0 (x1,y1) = unp2.papply (rg^.rGradTrans) $ rg^.rGradCenter1 r0 = rg^.rGradRadius0 r1 = rg^.rGradRadius1 setStrokeColour :: SomeColor -> DiagramObj () -- ^Set stroke style to a flat colour. setStrokeColour c = DiagramObj $ \this -> fireSignal S.setStrokeColour this r g b a where (r,g,b,a) = getRGBA c setLineGradient :: DiagramObj () -- ^Set stroke style to a previously assembled gradient. setLineGradient = DiagramObj $ fireSignal S.setLineGradient setLineTexture :: LineTexture Double -> DiagramObj () -- ^Set stroke style. setLineTexture tex = case getLineTexture tex of SC c -> setStrokeColour c LG l -> getLinearGradient l >>= liftIO.(setGradient $ l^.lGradStops) >> setLineGradient RG r -> getRadialGradient r >>= liftIO.(setGradient $ r^.rGradStops) >> setLineGradient setGradient :: [GradientStop Double] -> ObjRef GradientObj -> IO () -- ^Add colour stops to a gradient. setGradient stops grad = forM_ stops $ \stop -> let (r,g,b,a) = getRGBA (stop^.stopColor) o = stop^.stopFraction in addColourStop grad r g b a o setFillColour :: SomeColor -> DiagramObj () -- ^Set fill style to a flat colour. setFillColour c = DiagramObj $ \this -> fireSignal S.setFillColour this r g b a where (r,g,b,a) = getRGBA c setFillGradient :: DiagramObj () -- ^Set fill style to a previously defined gradient. setFillGradient = DiagramObj $ fireSignal S.setFillGradient setFillTexture :: FillTexture Double -> DiagramObj () -- ^Set fill style. setFillTexture tex = case getFillTexture tex of SC c -> setFillColour c LG l -> getLinearGradient l >>= liftIO.(setGradient $ l^.lGradStops) >> setFillGradient RG r -> getRadialGradient r >>= liftIO.(setGradient $ r^.rGradStops) >> setFillGradient setFont :: Font -> DiagramObj () -- ^Set font. setFont f = DiagramObj $ \this -> fireSignal S.setFont this (pack $ getFont f) setFillRule :: FillRule -> DiagramObj () -- ^Set fill rule. setFillRule EvenOdd = DiagramObj $ fireSignal S.oddEvenFill setFillRule Winding = DiagramObj $ fireSignal S.windingFill