packages feed

ige-0.1.0.0: src/IGE/Render.hs

module IGE.Render
  ( renderEditorState )
  where

import Protolude
import IGE.Types
import IGE.Layout
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Graphics.Rendering.Cairo
import Lens.Micro.Platform
import qualified Data.Map.Strict as Map

-- Refactoring ideas:
-- - Use diagrams

instance Renderable Text where
  render s (x :+ y) = do
    extents <- textExtents s
    rectangle
      (x - textMargin)
      (y - (textExtentsHeight extents + textMargin))
      (textExtentsWidth extents + (2 * textMargin))
      (textExtentsHeight extents + (2 * textMargin))
    setSourceRGB 0.1 0.1 0.1
    fill
    setSourceRGB 0.9 0.9 0.9
    moveTo x y
    showText s

instance Renderable () where
  render () (x :+ y) = do
    arc x y nodeSize 0 (2 * pi)
    fill

instance RenderNode Text where

instance RenderEdge Text where

instance RenderNode () where

instance RenderEdge () where
  renderEdge _ _ = return ()

nodeSize :: Double
nodeSize = 4

renderBackground :: Render ()
renderBackground = do
  setSourceRGB 0.1 0.1 0.1
  paint
  setSourceRGB 0.9 0.9 0.9
  selectFontFace ("monospace" :: Text) FontSlantNormal FontWeightNormal
  setFontSize 15

renderNodes :: (RenderNode a) => [(ℂ, a)] -> Render ()
renderNodes nodes = mapM_ (uncurry $ flip renderNode) nodes

renderEdges :: (RenderEdge a) => [(ℂ, ℂ, a)] -> Render ()
renderEdges edges =
  forM_ edges $ \(p1@(x0 :+ y0), p2@(x1 :+ y1), label) -> do
    moveTo x0 y0
    lineTo x1 y1
    stroke
    renderEdge label $ (p1 + p2) / (2 :+ 0)

renderCommand :: (Int, Int) -> [Char] -> Render ()
renderCommand (w, h) s = do
  let s' = reverse s
  extents <- textExtents s'
  moveTo 0 ((fromIntegral h) - (textExtentsHeight extents))
  showText s'

textMargin = 3

renderLabels :: [([Char], ℂ)] -> Render ()
renderLabels labels =
  forM_ labels $ \(s, x :+ y) -> do
    extents <- textExtents s
    rectangle
      (x - textMargin)
      (y - (textExtentsHeight extents + textMargin))
      (textExtentsWidth extents + (2 * textMargin))
      (textExtentsHeight extents + (2 * textMargin))
    setSourceRGB 0.7 0.7 0.2
    fill
    setSourceRGB 0.1 0.1 0.1
    moveTo x y
    showText s

renderEditorState :: (RenderNode n, RenderEdge e) => EditorState n e -> (Int, Int) -> Render ()
renderEditorState es dims = do
  let rm = es^._rm
  let graph = es^._graph
  let labels = es^._labels
  let nodeMap = (rm ^*) <$> es^._nodeMap
  renderBackground
  renderEdges $ ((_1 %~ (nodeMap Map.!)) . (_2 %~ (nodeMap Map.!))) <$> labEdges graph
  renderNodes $ (_1 %~ (nodeMap Map.!)) <$> labNodes graph
  renderCommand dims (es^._cmd)
  renderLabels $ over _2 (nodeMap Map.!) <$> labels