gulcii-0.2.0.1: src/Draw.hs
{-
gulcii -- graphical untyped lambda calculus interpreter
Copyright (C) 2011, 2013 Claude Heiland-Allen
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-}
module Draw (draw) where
import Data.List (genericDrop)
import qualified Data.Map.Strict as M
import Data.Map.Strict (Map)
import Graphics.Rendering.Cairo
import qualified Layout as L
import Evaluation (Strategy(..))
type RGB = (Double, Double, Double)
colour :: L.Term -> RGB
colour (L.Free _ _) = (0, 0.5, 1)
colour (L.Bound _ _) = (0.5, 0, 1)
colour (L.Lambda Strict _ _) = (1, 0, 0)
colour (L.Lambda Lazy _ _) = (1, 0, 0.5)
colour (L.Lambda Copy _ _) = (1, 0, 1)
colour (L.Apply _ _ _) = (1, 0.5, 0)
colour (L.RefInst _ _ _) = (0.5, 1, 0)
colour (L.Reference _ _) = (0, 1, 0.5)
colour (L.Trace _ _ _ _) = (1, 1, 0)
circle :: L.Coords -> RGB -> Render ()
circle (x, y) (r, g, b) = do
save
translate (fromIntegral x) (fromIntegral y)
arc 0 0 0.365 0 (2*pi)
setSourceRGB r g b
fillPreserve
setSourceRGB 0 0 0
stroke
restore
line :: L.Coords -> L.Coords -> Render ()
line (x, y) (x', y') = do
save
moveTo (fromIntegral x ) (fromIntegral y )
lineTo (fromIntegral x') (fromIntegral y')
stroke
restore
draw :: Double -> Double -> L.Layout -> Render ()
draw ww0 hh0 (L.Layout t w h ps) = do
save
translate dx dy
scale s s
translate 0.5 0.5
setLineWidth 0.1
setSourceRGB 0 0 0
drawLinks ps t
drawNodes t
setLineCap LineCapRound
setSourceRGB 0.5 0.5 0.5
drawVLinks [] t
setFontSize (6 / sqrt s)
translate 0 0.5
drawNames t
setSourceRGB 0 0 0
fillPreserve
setLineWidth (0.2 / sqrt s)
setSourceRGB 1 1 1
stroke
restore
where
s = if fromIntegral w * hh <= fromIntegral h * ww then hh / fromIntegral h else ww / fromIntegral w
ww = ww0 - 128
hh = hh0 - 64
dx = (ww0 - s * fromIntegral w) / 2
dy = (hh0 - s * fromIntegral h) / 2
drawNames :: L.Term -> Render ()
drawNames (L.Free s (x,y)) = do
e <- textExtents s
moveTo (fromIntegral x - textExtentsWidth e / 2) (fromIntegral y)
textPath s
drawNames (L.Bound _ _) = return ()
drawNames (L.Lambda _ t _) = drawNames t
drawNames (L.Apply a b _) = drawNames a >> drawNames b
drawNames (L.RefInst _ t _) = drawNames t
drawNames (L.Reference _ _) = return ()
drawNames (L.Trace s a b (x,y)) = do
e <- textExtents s
moveTo (fromIntegral x - textExtentsWidth e / 2) (fromIntegral y)
textPath s
drawNames a
drawNames b
drawLinks :: Map Integer L.Coords -> L.Term -> Render ()
drawLinks _ (L.Free _ _) = return ()
drawLinks _ (L.Bound _ _) = return ()
drawLinks ps (L.Lambda _ t xy) = let x'y' = L.coordinates t
in line xy x'y' >> drawLinks ps t
drawLinks ps (L.Apply a b xy) = let axay = L.coordinates a
bxby = L.coordinates b
in line xy axay >> line xy bxby >> drawLinks ps a >> drawLinks ps b
drawLinks ps (L.RefInst _ t xy) = let x'y' = L.coordinates t
in line xy x'y' >> drawLinks ps t
drawLinks ps (L.Reference p xy) = let Just x'y' = M.lookup p ps
in line xy x'y'
drawLinks ps (L.Trace _ a b xy) =
let axay = L.coordinates a
bxby = L.coordinates b
in line xy axay >> line xy bxby >> drawLinks ps a >> drawLinks ps b
drawVLinks :: [L.Coords] -> L.Term -> Render ()
drawVLinks ls (L.Bound n xy) =
case genericDrop n ls of
[] -> return ()
x'y':_ -> line xy x'y'
drawVLinks ls (L.Lambda _ t xy) = drawVLinks (xy : ls) t
drawVLinks ls (L.Apply s t _) = drawVLinks ls s >> drawVLinks ls t
drawVLinks ls (L.RefInst _ t _) = drawVLinks ls t
drawVLinks ls (L.Trace _ s t _) = drawVLinks ls s >> drawVLinks ls t
drawVLinks _ _ = return ()
drawNodes :: L.Term -> Render ()
drawNodes n@(L.Free _ _) = drawNode n
drawNodes n@(L.Bound _ _) = drawNode n
drawNodes n@(L.Lambda _ t _) = drawNode n >> drawNodes t
drawNodes n@(L.Apply a b _) = drawNode n >> drawNodes a >> drawNodes b
drawNodes n@(L.RefInst _ t _) = drawNode n >> drawNodes t
drawNodes n@(L.Reference _ _) = drawNode n
drawNodes n@(L.Trace _ a b _) = drawNode n >> drawNodes a >> drawNodes b
drawNode :: L.Term -> Render ()
drawNode n = circle (L.coordinates n) (colour n)