packages feed

ige-0.1.0.0: src/IGE/Types.hs

module IGE.Types where

import Protolude
import Data.Complex
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Lens.Micro.Platform
import Control.Concurrent.STM
import Conduit
import Graphics.UI.Gtk (KeyVal)
import Graphics.Rendering.Cairo
import qualified Data.Map.Strict as Map

-- Refactoring ideas:
-- - Use typeclass-based EditorState
-- - Use StateT based Keybinding -- use hoisting to promote pure functions
-- - 

type ℂ = Complex Double

class Translation a where
  _x :: Lens' a Double
  _y :: Lens' a Double

class Amplitwist a where
  _r :: Lens' a Double
  _θ :: Lens' a Double

instance Translation ℂ where
  _x f (x :+ y) = (:+ y) <$> f x
  _y f (x :+ y) = (x :+) <$> f x

instance Amplitwist ℂ where
  _r f z = (* z) . (:+ 0) . (/ r) <$> f r
    where r = magnitude z
  _θ f z = (* z) . cis . (+ (-θ)) <$> f θ
    where θ = phase z

class (Translation a, Amplitwist a) => RigidMotion a where
  (^.^) :: a -> a -> a
  (^*) :: a -> ℂ -> ℂ
  -- law = (a ^.^ b) ^* z = a ^* (b ^* c)

data RM = RM { rmAT :: ℂ, rmTrans :: ℂ } -- rigid motion
  deriving (Eq, Show)

makeLensesFor [("rmAT", "_at"), ("rmTrans", "_trans")] ''RM

instance Translation RM where
  _x f (RM at trans) = (RM at) <$> _x f trans
  _y f (RM at trans) = (RM at) <$> _y f trans

instance Amplitwist RM where
  _r f (RM at trans) = (flip RM trans) <$> _r f at
  _θ f (RM at trans) = (flip RM trans) <$> _θ f at

instance RigidMotion RM where
  (RM at1 trans1) ^.^ (RM at2 trans2) = RM (at1 * at2) (trans1 + (at1 * trans2))
  (RM at trans) ^* z = (z * at) + trans

class Renderable a where
  render :: a -> ℂ -> Render ()

class Renderable a => RenderNode a where
  renderNode :: a -> ℂ -> Render ()
  renderNode = render

class Renderable a => RenderEdge a where
  renderEdge :: a -> ℂ -> Render ()
  renderEdge = render

data EditorState n e = EditorState {
    esGraph :: Gr n e
  , esRM :: RM
  , esNum :: Int
  , esCommand :: [Char] -- stored backwards
  , esLabels :: [([Char], Node)]
  , esNodeMap :: Map.Map Node ℂ
  }

makeLensesFor [
    ("esGraph", "_graph")
  , ("esRM", "_rm")
  , ("esNum", "_num")
  , ("esCommand", "_cmd")
  , ("esLabels", "_labels")
  , ("esNodeMap", "_nodeMap")] ''EditorState

newtype IGEM n e a = IGEM { unIGEM :: ReaderT (TVar (EditorState n e)) IO a }
  deriving (Functor, Applicative, Monad, MonadIO, MonadReader (TVar (EditorState n e)))

runIGEM :: TVar (EditorState n e) -> IGEM n e a -> IO a
runIGEM v m = runReaderT (unIGEM m) v

type EditorM n e = State (EditorState n e)

runTVarState :: (MonadReader (TVar s) m, MonadIO m) => State s a -> m a
runTVarState action = do
  stateVar <- ask
  liftIO $ atomically $ do
    s <- readTVar stateVar
    let (a, s') = runState action s
    writeTVar stateVar s'
    return a

runTVarReader :: (MonadReader (TVar s) m, MonadIO m) => Reader s a -> m a
runTVarReader action = do
  stateVar <- ask
  s <- liftIO $ readTVarIO stateVar
  return $ runReader action s

data RefreshType = LayoutChange | NoLayoutChange
  deriving (Show, Eq)

type KeyBinding n e = ConduitM KeyVal RefreshType (IGEM n e)