wumpus-basic-0.4.0: src/Wumpus/Basic/Monads/Drawing.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS -Wall #-}
--------------------------------------------------------------------------------
-- |
-- Module : Wumpus.Basic.Monads.Drawing
-- Copyright : (c) Stephen Tetley 2010
-- License : BSD3
--
-- Maintainer : stephen.tetley@gmail.com
-- Stability : unstable
-- Portability : GHC
--
-- Graphic types and lifters...
--
--
--
--------------------------------------------------------------------------------
module Wumpus.Basic.Monads.Drawing
(
AGraphic(..)
, ANode
, AFreeGraphic
, AConnector
, node
, nodeAt
, at
, liftAFG
, connect
, connect_
, props
-- doodle
, thick
) where
import Wumpus.Basic.Graphic
import Wumpus.Basic.Graphic.DrawingAttr
import Wumpus.Basic.Monads.DrawingCtxClass
import Wumpus.Basic.Monads.TraceClass
import Wumpus.Basic.Monads.TurtleClass
import Wumpus.Core -- package: wumpus-core
import Control.Applicative
-- | AGraphic
--
-- param typically @Point2 u@ or @()@
--
-- If the param is a point it will be supplied by the drawing
-- mode / drawing monad (e.g. the Turtle monad which supplies
-- the current point).
--
data AGraphic param u a = AGraphic
{ agDrawF :: DrawingAttr -> param -> Graphic u
, agMakeF :: DrawingAttr -> param -> a
}
-- | ANode is drawn a a point supplied by the drawing
-- (e.g. current node of Turtle).
--
type ANode u a = AGraphic (Point2 u) u a
-- /Free/ graphic
--
type AFreeGraphic u a = AGraphic () u a
type AConnector u a = Point2 u -> Point2 u -> AFreeGraphic u a
instance Functor (AGraphic pm u) where
fmap f (AGraphic df mf) = AGraphic df (\pt attr -> f $ mf pt attr)
instance Applicative (AGraphic pm u) where
pure a = AGraphic (\_ _ -> id) (\_ _ -> a)
(AGraphic df1 mf1) <*> (AGraphic df2 mf2) = AGraphic df mf
where
df attr pt = df2 attr pt . df1 attr pt
mf attr pt = mf1 attr pt $ mf2 attr pt
-- This doesn't work like at on MGraphicF, as the point is not
-- scaled w.r.t. TurtleScaleM ...
--
at :: ANode u a -> Point2 u -> ANode u a
at (AGraphic df mf) pt = AGraphic (\attr _ -> df attr pt)
(\attr _ -> mf attr pt)
-- getPos should be a class method outside of Turtle
-- those Bivariate context from PSC could implement it...
node :: (Num u, TraceM m u, DrawingCtxM m, TurtleScaleM m u)
=> ANode u a -> m a
node (AGraphic df mf) =
askDrawingCtx >>= \attr ->
getPos >>= \pt ->
trace (df attr pt) >> return (mf attr pt)
nodeAt :: (Num u, TraceM m u, DrawingCtxM m)
=> ANode u a -> Point2 u -> m a
nodeAt (AGraphic df mf) pt =
askDrawingCtx >>= \attr ->
trace (df attr pt) >> return (mf attr pt)
liftAFG :: (Num u, TraceM m u, DrawingCtxM m)
=> AFreeGraphic u a -> m a
liftAFG (AGraphic df mf) =
askDrawingCtx >>= \attr -> trace (df attr ()) >> return (mf attr ())
connect :: (Num u, TraceM m u, DrawingCtxM m)
=> AConnector u a -> Point2 u -> Point2 u -> m a
connect conn p1 p2 = let (AGraphic df mf) = conn p1 p2 in
askDrawingCtx >>= \attr -> trace (df attr ()) >> return (mf attr ())
-- This is a bit unfortunate - with a connector we can\'t touch
-- the drawingAttr inside the AGraphic becase a connecter is
--
-- > pt -> pt -> AGraphic
--
-- and not
--
-- > AGraphic
--
--
-- Maybe AGraphic shouldn\'t have the agAttrF field?
--
--
--
connect_ :: (Num u, TraceM m u, DrawingCtxM m)
=> (DrawingAttr -> DrawingAttr)
-> AConnector u a -> Point2 u -> Point2 u -> m a
connect_ fn conn p1 p2 = let (AGraphic df mf) = conn p1 p2 in
askDrawingCtx >>= \a0 ->
let attr = fn $ a0 in trace (df attr ()) >> return (mf attr ())
infixr 7 `props`
props :: AGraphic pm u a -> (DrawingAttr -> DrawingAttr) -> AGraphic pm u a
props (AGraphic df mf) upd = AGraphic (\attr p -> df (upd attr) p)
(\attr p -> mf (upd attr) p)