packages feed

twentefp-eventloop-graphics (empty) → 0.1.0.0

raw patch · 20 files changed

+806/−0 lines, 20 filesdep +basedep +networkdep +textsetup-changed

Dependencies added: base, network, text, twentefp-number, twentefp-websockets

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Christiaan Baaij
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Christiaan Baaij nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple
+main = defaultMain
+ src/EventLoop.hs view
@@ -0,0 +1,30 @@+module EventLoop(
+    start,
+    Pos,
+    Dimension,
+    Element,
+    
+    InputEvent(..),
+    Keyboard(..),
+    KeyboardButton,
+    Mouse(..),
+    MouseButton(..),
+    SystemMessageIn(..),
+    
+    OutputEvent(..),
+    SystemMessageOut(..),
+    Graphical(..),
+    GObject(..),
+    Primitive(..),
+    Name,
+    Groupname,
+    Color,
+    Font,
+    Relative,
+    outSingle
+) where
+
+import EventLoop.Main
+import EventLoop.CommonTypes
+import EventLoop.Input
+import EventLoop.Output
+ src/EventLoop/CommonTypes.hs view
@@ -0,0 +1,11 @@+module EventLoop.CommonTypes(
+    Pos,
+    Dimension,
+    Element
+) where
+
+import FPPrac
+
+type Pos = (Number, Number) -- (x, y)
+type Dimension = (Number, Number) -- (h, w)
+type Element = [Char]
+ src/EventLoop/Config.hs view
@@ -0,0 +1,102 @@+module EventLoop.Config where
+
+import FPPrac
+
+------------------
+-- Server Settings
+ipadres = "127.0.0.1"
+port = 9161 :: Number
+
+-----------
+-- Response modes
+graphicalS      = "graphical"
+commandS        = "command"
+modeS           = "mode"
+drawS           = "draw"
+movegroupS      = "movegroup"
+moveelementS    = "moveelement"
+removegroupS    = "removegroup"
+removeelementS  = "removeelement"
+
+gobjectS    = "gobject"
+nameS       = "name"
+groupnameS  = "groupname"
+positionS   = "position"
+relativeS   = "relative"
+
+-- GObject options
+containerS  = "containers"
+primS       = "prim"
+childrenS   = "children"
+
+-- JSONObject/Primitive options
+typeS   = "type"
+textS   = "text"
+lineS   = "line"
+rectS   = "rect"
+arcS    = "arc"
+
+edgecolorS      = "edgecolor"
+edgethicknessS  = "edgethickness"
+colorS          = "color"
+positionsS      = "positions"
+
+sizeS = "size"
+fontS = "font"
+fromcenterS = "fromcenter"
+
+widthS = "width"
+heightS = "height"
+radiusS = "radius"
+startangS = "startang"
+endangS = "endang"
+
+-- Color
+rS = "r"
+bS = "b"
+gS = "g"
+
+-- Position
+xS = "x"
+yS = "y"
+
+----------
+-- Request options
+
+buttonS = "button"
+
+-- Mouse
+mouseS = "mouse"
+mousetypeS = "mousetype"
+mouseclickS = "mouseclick"
+mouseupS = "mouseup"
+mousedownS = "mousedown"
+leftS = "left"
+middleS = "middle"
+rightS = "right"
+elementS = "element"
+
+-- Keyboard
+keyboardS = "keyboard"
+
+-- SystemMessage
+systemmessageS = "systemmessage"
+backgroundS = "background"
+setupS = "setup"
+timeS = "time"
+
+-- SystemMessageAnswers
+sysmessageanswersS = "systemmessageanswers"
+sysmessageanswerS = "systemmessageanswer"
+messageS = "message"
+answersS = "answers"
+canvassetupS = "canvassetup"
+dimensionS = "dimension"
+timerS = "timer"
+useS = "use"
+closeS = "close"
+
+
+-- Dimension
+hS = "h"
+wS = "w"
+ src/EventLoop/EventProcessor.hs view
@@ -0,0 +1,63 @@+module EventLoop.EventProcessor(eventloop, IOMessage, readRequest, sendResponse) where
+
+import qualified Network.WebSockets as WS
+import Control.Exception (handle, fromException, AsyncException(..), onException)
+import qualified Data.Text as T
+import Data.String (String)
+import Data.Char (isLower, isDigit)
+import Control.Monad (sequence)
+
+import EventLoop.Json
+import EventLoop.Config
+
+import Debug.Trace
+
+type IOMessage = JSONMessage
+
+-- Start connection
+eventloop :: (a -> IOMessage -> ([IOMessage], a)) -> a -> IO ()
+eventloop eh beginState = WS.runServer ipadres (fromIntegral port) $ application eh beginState
+
+application :: (a -> IOMessage -> ([IOMessage], a)) -> a -> WS.PendingConnection -> IO ()
+application eh beginState pending = do
+                        conn <- WS.acceptRequest pending
+                        onException (doEvents eh beginState conn) (putStrLn "text1")
+                        --handle (catchUserInterrupt conn) $ handle (catchDisconnect conn) $ doEvents eh beginState conn
+                        return ()
+
+-- Connection functions
+catchDisconnect :: WS.Connection -> WS.ConnectionException -> IO ()
+catchDisconnect conn e = case e of
+                          WS.ConnectionClosed         -> putStrLn "Connection closed!"
+                          WS.CloseRequest code reason -> putStrLn "test1"
+
+-- User Interrupt
+catchUserInterrupt :: WS.Connection -> AsyncException -> IO()
+catchUserInterrupt conn e = case e of
+                             UserInterrupt -> putStrLn "test2"
+                             ThreadKilled  -> putStrLn "test3"
+
+-- Event Loop
+doEvents :: (a -> IOMessage -> ([IOMessage], a)) -> a -> WS.Connection -> IO ()
+doEvents eh state conn = do
+                    request <- readRequest conn
+                    let
+                        (resp, state') = eh state request 
+                        sendActions = map (sendResponse conn)  resp
+                    sequence sendActions
+                    doEvents eh state' conn
+                
+readRequest :: WS.Connection -> IO IOMessage                
+readRequest conn = do
+                    msg <- WS.receiveData conn
+                    let
+                        string = T.unpack msg
+                        request = stringToJsonObject string
+                    return request
+                    
+sendResponse :: WS.Connection -> IOMessage -> IO ()
+sendResponse conn response = do
+                        let
+                            string = show response
+                            text = T.pack string
+                        WS.sendTextData conn text                      
+ src/EventLoop/Input.hs view
@@ -0,0 +1,13 @@+module EventLoop.Input(
+    InputEvent(..),
+    Keyboard(..),
+    KeyboardButton,
+    Mouse(..),
+    MouseButton(..),
+    SystemMessageIn(..)
+) where
+
+import EventLoop.Input.InputEvent
+import EventLoop.Input.Keyboard
+import EventLoop.Input.Mouse
+import EventLoop.Input.SystemMessage
+ src/EventLoop/Input/InputEvent.hs view
@@ -0,0 +1,18 @@+module EventLoop.Input.InputEvent where
+
+import EventLoop.Config
+import EventLoop.Json
+import EventLoop.Input.Keyboard
+import EventLoop.Input.Mouse
+import EventLoop.Input.SystemMessage
+
+data InputEvent = InMouse Mouse       
+                | InKeyboard Keyboard
+                | InSysMessage SystemMessageIn
+             
+instance FromJSON InputEvent where
+    fromJsonMessage obj@(JSONObject ms) | keyboardS == type'      = InKeyboard (fromJsonMessage obj)
+                                        | mouseS == type'         = InMouse (fromJsonMessage obj)
+                                        | systemmessageS == type' = InSysMessage (fromJsonMessage obj) 
+                                          where
+                                              JSONString type' = retrieveError typeS ms
+ src/EventLoop/Input/Keyboard.hs view
@@ -0,0 +1,20 @@+module EventLoop.Input.Keyboard(
+    Keyboard(..),
+    KeyboardButton
+) where
+
+import EventLoop.Json
+import EventLoop.Config
+
+-- Possible messages:
+-- {"type": "keyboard", "button": "<kkey>"}
+-- <kkey> = a | b | c .. | z | shift | caps ..
+
+-- Keyboard Messages In
+data Keyboard = KeyPress KeyboardButton
+type KeyboardButton = [Char]
+
+instance FromJSON Keyboard where
+    fromJsonMessage (JSONObject ms) = KeyPress button
+                                    where
+                                        JSONString button = retrieveError buttonS ms
+ src/EventLoop/Input/Mouse.hs view
@@ -0,0 +1,43 @@+module EventLoop.Input.Mouse(
+    Mouse(..),
+    MouseButton(..)
+) where
+
+import EventLoop.Json
+import EventLoop.Config
+import EventLoop.CommonTypes
+
+
+-- Possible messages:
+-- {"type":"mouse","button":"<mkey>","x":<number>,"y":<number>,"element":"<name>"}
+-- <mkey> = left | right | middle
+-- <name> = (a | b | c | ... | z | A | B | C ...)+
+-- <numbers> = (1 | 2 | 3 | ... | 0)+
+
+-- Mouse Messages In
+data Mouse = MouseClick MouseButton Pos Element
+           | MouseUp MouseButton Pos Element
+           | MouseDown MouseButton Pos Element
+           deriving Show
+           
+data MouseButton = MLeft | MRight | MMiddle
+                    deriving Show
+
+instance FromJSON Mouse where
+    fromJsonMessage (JSONObject ms) | mouseType == mouseclickS = MouseClick button pos element
+                                    | mouseType == mouseupS    = MouseUp button pos element
+                                    | mouseType == mousedownS  = MouseDown button pos element
+                                    where
+                                        JSONString mouseType = retrieveError mousetypeS ms
+                                        JSONNumber x = retrieveError xS ms
+                                        JSONNumber y = retrieveError yS ms
+                                        pos = (x, y)
+                                        JSONString element = retrieveError elementS ms
+                                        jsonButton = retrieveError buttonS ms
+                                        button = fromJsonMessage jsonButton
+       
+instance FromJSON MouseButton where
+    fromJsonMessage (JSONString but) | leftS   == but = MLeft
+                                     | middleS == but = MMiddle
+                                     | rightS  == but = MRight
+                                     | otherwise = error ("Could not create a mouse button from value: " ++ but)
+ src/EventLoop/Input/SystemMessage.hs view
@@ -0,0 +1,18 @@+module EventLoop.Input.SystemMessage(
+    SystemMessageIn(..)
+) where
+
+import EventLoop.Json
+import EventLoop.Config
+
+-- System Messages In
+data SystemMessageIn = Setup
+                     | Background
+                     | Time
+                     
+instance FromJSON SystemMessageIn where
+    fromJsonMessage (JSONObject ms) | message == setupS      = Setup
+                                    | message == backgroundS = Background
+                                    | message == timeS       = Time
+                                      where
+                                          JSONString message = retrieveError messageS ms                     
+ src/EventLoop/Json.hs view
@@ -0,0 +1,118 @@+module EventLoop.Json(JSONMember(..), JSONMessage(..), retrieve, retrieveError, FromJSON(..), JSONAble(..), stringToJsonObject)  where
+
+import Data.Char (isDigit, isLower, isUpper)
+import FPPrac
+
+data JSONMember = JSONMember [Char] JSONMessage
+
+data JSONMessage = JSONNumber Number
+                | JSONString [Char]
+                | JSONBool Bool
+                | JSONObject [JSONMember]
+                | JSONArray [JSONMessage]
+                
+
+retrieve :: [Char] -> [JSONMember] -> Maybe JSONMessage
+retrieve search [] = Nothing
+retrieve search ((JSONMember name member):list) | search == name = Just member
+                                               | otherwise = retrieve search list                
+                
+retrieveError :: [Char] -> [JSONMember] -> JSONMessage
+retrieveError search members = case (retrieve search members) of
+                                Nothing -> error ("Could not find " ++ search ++ " in JSON members")
+                                Just result -> result
+
+class FromJSON a where
+    fromJsonMessage :: JSONMessage -> a
+    
+instance Show JSONMessage where    
+    show (JSONNumber n)      = show n
+    show (JSONString s)      = "\"" ++ s ++ "\""
+    show (JSONBool bool)     | bool        = "true"
+                             | otherwise = "false"
+    show (JSONObject (r:rs)) = "{" ++ rows ++ "}"
+                                    where
+                                        rows = foldl insertComma (show r) (map show rs)
+    show (JSONArray [])       = "[]"
+    show (JSONArray (x:xs))     = "[" ++ list ++ "]"
+                                    where
+                                        list = foldl insertComma (show x) (map show xs)
+
+insertComma :: [Char] -> [Char] -> [Char]
+insertComma a b = a ++ "," ++ b                
+
+instance Show JSONMember where
+    show (JSONMember name m) = "\"" ++ name ++ "\": " ++ (show m)
+
+
+
+
+class JSONAble a where
+    toJsonMessage :: a -> JSONMessage
+  
+-- JSON Grammar for 1 object
+-- Grammar returns (Rest, JSONObject [JSONRow])
+-- O: '{' R+ '}'
+-- R: '"' W '"' ':' V
+-- V: '"' (JSONInt N | JSONString W) '"'
+-- N: ('1' | '2' | '3' | ... | '0')+
+-- W: ('a' | 'b' | 'c' | ... | 'z') (N | W | -)
+
+data Grammer = O | R
+type Rest = [Char]
+
+stringToJsonObject :: [Char] -> JSONMessage
+stringToJsonObject string = snd $ parse O string (JSONObject [])
+
+errorMsg :: [Char] -> [Char] -> [Char]
+errorMsg exp act = "Fault at parsing, expected '" ++ exp ++ "' but found '" ++ act ++ "'"
+
+parse :: Grammer -> Rest -> JSONMessage -> (Rest, JSONMessage)
+parse O [] _ = error (errorMsg "something" "premature end (start of message)")
+parse O (c1:cs) (JSONObject rows)     | c1 == '{' = result
+                                    | otherwise = error (errorMsg "{" [c1])
+                                    where
+                                        ((c1':cs'), object) = parse R cs (JSONObject rows)
+                                        result     | c1' == '}' = (cs', object)
+                                                | otherwise = error (errorMsg "}" [c1'])
+
+parse R [] _ = error (errorMsg "something" "premature end (reading a row)")                                        
+parse R (t:ts) (JSONObject rows) = object
+                                    where
+                                        ((r:rs), rowName) | t == '"' = parseWord ts                 -- Read row name
+                                                          | otherwise = error (errorMsg "\"" [t])  
+                                        rs'    | r == ':' = rs                                         -- Read row delimiter
+                                            | otherwise = error (errorMsg ":" [r])
+                                        ((r'':rs''), var2) = parseVariable rs'                      -- Read variable for row
+                                        rows' = rows ++ [(JSONMember rowName var2)]                 -- Add found result to other rows
+                                        object     | r'' == '}' = ((r'':rs''), JSONObject rows')       -- End, return result
+                                                | r'' == ',' = parse R rs'' (JSONObject rows')      -- Read next row
+                                                | otherwise = error (errorMsg "',' or '}'" [r''])                                    
+
+-- Possibilities:
+-- "\"string123value\"" -> JSONString "string123value" or "12345" -> JSONInt 12345                                    
+parseVariable :: Rest -> (Rest, JSONMessage)                                        
+parseVariable [] = error (errorMsg "something" "premature end")
+parseVariable [c1] = error (errorMsg "longer variable" (c1:" and premature end"))                
+parseVariable (c1:c2:cs)    | c1 == '"' && ((isLower c2) || (isUpper c2)) = (r1, JSONString word)
+                            | isDigit c1 = (r2, JSONNumber (read number))
+                            | otherwise = error (errorMsg "\"" [c1])
+                            where
+                                (r1, word)   = parseWord (c2:cs)
+                                (r2, number) = parseNumber (c1:c2:cs)
+
+parseWord :: Rest -> (Rest, [Char])
+parseWord [] = error (errorMsg "something" "premature end")
+parseWord (c1:cs)     | (isLower c1) || (isDigit c1) || (isUpper c1) = (r1, c1:result')
+                    | c1 == '"' = (cs, [])
+                    | otherwise = error (errorMsg "letter or number" [c1])
+                    where
+                        (r1, result') = parseWord cs
+
+parseNumber :: Rest -> (Rest, [Char])                         
+parseNumber [] = error (errorMsg "something" "premature end")                         
+parseNumber (c1:cs) | isDigit c1 || c1 == '.' = (r1, c1:result')
+                    | c1 == ',' || c1 == '}' = (c1:cs, [])
+                    | otherwise = error (errorMsg "number" [c1])
+                            where
+                                (r1, result') = parseNumber cs
+ src/EventLoop/Main.hs view
@@ -0,0 +1,18 @@+module EventLoop.Main(start) where
+
+import EventLoop.EventProcessor
+import EventLoop.Input.InputEvent
+import EventLoop.Output.OutputEvent
+import EventLoop.Json
+         
+start :: (a -> InputEvent -> ([OutputEvent], a)) -> a -> IO()
+start handler beginstate = eventloop handler' beginstate
+                        where
+                            handler' = changeTypes handler
+
+
+changeTypes :: (a -> InputEvent -> ([OutputEvent], a)) -> a -> IOMessage -> ([IOMessage], a)
+changeTypes f state message = (map toJsonMessage oEvents, state')
+                    where
+                        iEvent = fromJsonMessage message
+                        (oEvents, state') = f state iEvent
+ src/EventLoop/Output.hs view
@@ -0,0 +1,18 @@+module EventLoop.Output(
+    OutputEvent(..),
+    SystemMessageOut(..),
+    Graphical(..),
+    GObject(..),
+    Primitive(..),
+    Name,
+    Groupname,
+    Color,
+    Font,
+    Relative,
+    outSingle
+) where
+
+import EventLoop.Output.OutputEvent
+import EventLoop.Output.SystemMessage
+import EventLoop.Output.Graphical
+import EventLoop.Output.Single
+ src/EventLoop/Output/Graphical.hs view
@@ -0,0 +1,12 @@+module EventLoop.Output.Graphical(
+    Graphical(..),
+    GObject(..),
+    Primitive(..),
+    Name,
+    Groupname,
+    Color,
+    Font,
+    Relative
+) where
+
+import EventLoop.Output.Graphical.Graphical
+ src/EventLoop/Output/Graphical/Graphical.hs view
@@ -0,0 +1,146 @@+module EventLoop.Output.Graphical.Graphical(
+        Graphical(..),
+        GObject(..),
+        Primitive(..),
+        Name,
+        Groupname,
+        Color,
+        Font,
+        Relative
+) where
+
+import EventLoop.Json
+import EventLoop.Config
+import EventLoop.CommonTypes
+import FPPrac
+
+-- Options
+type Name = [Char]
+type Groupname = [Char]
+type Color = (Number, Number, Number) -- (r, g, b)
+type Font = [Char]
+type Relative = Bool -- Move relative to old spot or not
+
+-- Graphical Responses Out
+data Graphical = Draw GObject Groupname
+                | MoveGroup Groupname Pos Relative
+                | MoveElement Name Pos Relative
+                | RemoveGroup Groupname
+                | RemoveElement Name        
+                
+instance JSONAble Graphical where
+    toJsonMessage (Draw gObject gName)              = JSONObject [(JSONMember modeS      (JSONString drawS)),
+                                                               (JSONMember gobjectS   (toJsonMessage gObject)),     
+                                                               (JSONMember groupnameS (JSONString gName))]
+                                                               
+    toJsonMessage (MoveGroup gName pos rel)      = JSONObject [(JSONMember modeS      (JSONString movegroupS)),
+                                                               (JSONMember groupnameS (JSONString gName)), 
+                                                               (JSONMember positionS  (positionToJsonMessage pos)), 
+                                                               (JSONMember relativeS  (JSONBool rel))]
+                                                                                      
+    toJsonMessage (MoveElement name pos rel)     = JSONObject [(JSONMember modeS      (JSONString moveelementS)),
+                                                               (JSONMember nameS      (JSONString name)),       
+                                                               (JSONMember positionS  (positionToJsonMessage pos)), 
+                                                               (JSONMember relativeS  (JSONBool rel))]
+                                                               
+    toJsonMessage (RemoveGroup gName)              = JSONObject [(JSONMember modeS       (JSONString removegroupS)),
+                                                               (JSONMember groupnameS  (JSONString gName))]
+    
+    toJsonMessage (RemoveElement name)              = JSONObject [(JSONMember modeS (JSONString removeelementS)),
+                                                               (JSONMember nameS (JSONString name))]
+                
+
+
+-- Graphical Object Wrapper
+data GObject = GObject    { name :: Name
+                        , prim :: Primitive
+                        , children :: [GObject]
+                        }
+             | Container { children :: [GObject]
+                         }
+                        deriving (Show)
+
+instance JSONAble GObject where
+    toJsonMessage (GObject name prim children) = JSONObject [(JSONMember typeS     (JSONString gobjectS)), 
+                                                             (JSONMember primS     (toJsonMessage prim)), 
+                                                             (JSONMember nameS     (JSONString name)), 
+                                                             (JSONMember childrenS (JSONArray (map toJsonMessage children)))]
+                                                             
+    toJsonMessage (Container children)         = JSONObject [(JSONMember childrenS (JSONArray (map toJsonMessage children)))]
+                        
+-- Primitive graphical structures                        
+data Primitive = Text    { edgeColor :: Color
+                        , edgeThickness :: Number
+                        , color :: Color
+                        , position :: Pos
+                        , size :: Number
+                        , font :: Font
+                        , text :: [Char]
+                        , fromCenter :: Bool
+                        }
+                | Line     { edgeColor :: Color
+                        , edgeThickness :: Number
+                        , positions :: [Pos]
+                        }
+                | Rect    { edgeColor :: Color
+                        , edgeThickness :: Number
+                        , color :: Color
+                        , position :: Pos -- Topleft corner
+                        , dimensions :: Dimension
+                        }
+                | Arc     { edgeColor :: Color
+                        , edgeThickness :: Number
+                        , color :: Color
+                        , position :: Pos
+                        , radius :: Number
+                        , startAng :: Number -- In degrees
+                        , endAng :: Number -- In degrees
+                        }
+                    deriving (Show, Eq)
+
+
+instance JSONAble Primitive where
+    toJsonMessage (Text ec et color position size font text fromcenter) = JSONObject [(JSONMember typeS           (JSONString textS)), 
+                                                                                      (JSONMember edgecolorS      (colorToJsonMessage ec)), 
+                                                                                      (JSONMember edgethicknessS  (JSONNumber et)), 
+                                                                                      (JSONMember colorS          (colorToJsonMessage color)), 
+                                                                                      (JSONMember positionS       (positionToJsonMessage position)), 
+                                                                                      (JSONMember sizeS           (JSONNumber size)), 
+                                                                                      (JSONMember fontS           (JSONString font)), 
+                                                                                      (JSONMember textS           (JSONString text)), 
+                                                                                      (JSONMember fromcenterS     (JSONBool fromcenter))]
+                                                                            
+    toJsonMessage (Line ec et positions) = JSONObject [(JSONMember typeS           (JSONString lineS)), 
+                                                       (JSONMember edgecolorS      (colorToJsonMessage ec)), 
+                                                       (JSONMember edgethicknessS  (JSONNumber et)), 
+                                                       (JSONMember positionsS      (JSONArray (map positionToJsonMessage positions)))]
+                                                                                     
+    toJsonMessage (Rect ec et color position dim) = JSONObject [(JSONMember typeS           (JSONString rectS)), 
+                                                                         (JSONMember edgecolorS      (colorToJsonMessage ec)), 
+                                                                         (JSONMember edgethicknessS  (JSONNumber et)), 
+                                                                         (JSONMember colorS          (colorToJsonMessage color)), 
+                                                                         (JSONMember positionS       (positionToJsonMessage position)),
+                                                                         (JSONMember dimensionS      (dimensionToJsonMessage dim))]
+                                                                
+    toJsonMessage (Arc ec et color position radius startAng endAng) = JSONObject [(JSONMember typeS          (JSONString arcS)),  
+                                                                                  (JSONMember edgecolorS     (colorToJsonMessage ec)), 
+                                                                                  (JSONMember edgethicknessS (JSONNumber et)), 
+                                                                                  (JSONMember colorS         (colorToJsonMessage color)), 
+                                                                                  (JSONMember positionS      (positionToJsonMessage position)), 
+                                                                                  (JSONMember radiusS        (JSONNumber radius)), 
+                                                                                  (JSONMember startangS      (JSONNumber startAng)), 
+                                                                                  (JSONMember endangS        (JSONNumber endAng))]
+
+-- Support Functions                                                                                
+colorToJsonMessage :: Color -> JSONMessage
+colorToJsonMessage (r, g, b) = JSONObject [(JSONMember rS (JSONNumber r)), 
+                                           (JSONMember gS (JSONNumber g)), 
+                                           (JSONMember bS (JSONNumber b))]
+
+positionToJsonMessage :: Pos -> JSONMessage
+positionToJsonMessage (x, y) = JSONObject [(JSONMember xS (JSONNumber x)), 
+                                           (JSONMember yS (JSONNumber y))] 
+
+dimensionToJsonMessage :: Dimension -> JSONMessage                                           
+dimensionToJsonMessage (h, w) = JSONObject [(JSONMember heightS (JSONNumber h)), 
+                                            (JSONMember widthS  (JSONNumber w))]
+ src/EventLoop/Output/OutputEvent.hs view
@@ -0,0 +1,14 @@+module EventLoop.Output.OutputEvent where
+
+import EventLoop.Output.Graphical.Graphical
+import EventLoop.Output.SystemMessage
+import EventLoop.Config
+import EventLoop.Json
+
+data OutputEvent = OutGraphical Graphical
+                 | OutSysMessage [SystemMessageOut]
+                
+                
+instance JSONAble OutputEvent where
+    toJsonMessage (OutGraphical graph)   = JSONObject [(JSONMember modeS (JSONString graphicalS)), (JSONMember commandS (toJsonMessage graph))]
+    toJsonMessage (OutSysMessage ms)  = JSONObject [(JSONMember modeS (JSONString sysmessageanswersS)), (JSONMember answersS (JSONArray (map toJsonMessage ms)))]
+ src/EventLoop/Output/Single.hs view
@@ -0,0 +1,67 @@+module EventLoop.Output.Single (outSingle) where
+
+import qualified Network.Socket     as S
+import qualified Network.WebSockets as WS
+import qualified Data.Text          as T
+
+import EventLoop.EventProcessor (sendResponse, IOMessage)
+import EventLoop.Output.OutputEvent
+import EventLoop.Output.Graphical
+import EventLoop.Output.SystemMessage
+import EventLoop.Config
+import EventLoop.Json
+import EventLoop.CommonTypes
+
+outSingle :: OutputEvent -> IO ()
+outSingle out = S.withSocketsDo $ do
+                                    sock <- WS.makeSocket ipadres (fromIntegral port)
+                                    pendingConn <- WS.makePendingConnection sock
+                                    conn <- WS.acceptRequest pendingConn
+                                    sendResponse conn setup
+                                    sendResponse conn out'
+                                    sendResponse conn close
+                                    WS.sendClose conn (T.pack "")
+                                    WS.closeSocket sock
+                                    return ()
+                where
+                    setup = toIOMessage (setupMessage out)
+                    out' = toIOMessage out 
+                    close = toIOMessage closeMessage
+    
+setupMessage :: OutputEvent -> OutputEvent
+setupMessage (OutGraphical (Draw g _)) = OutSysMessage [CanvasSetup dim]
+                                    where
+                                        dim = maxDimensions g
+setupMessage _ = OutSysMessage [CanvasSetup (512, 512)]                                        
+
+closeMessage :: OutputEvent
+closeMessage = OutSysMessage [Close]
+    
+toIOMessage :: OutputEvent -> IOMessage
+toIOMessage = toJsonMessage
+
+maxDimensions :: GObject -> Dimension
+maxDimensions (GObject _ prim [])     = maxDimensionsPrim prim
+maxDimensions (GObject n prim (c:cs)) = (max h h', max w w')
+                                        where
+                                            (h, w) = maxDimensions c
+                                            (h', w') = maxDimensions (GObject n prim cs)
+maxDimensions (Container [])          = (0, 0)
+maxDimensions (Container (c:cs))      = (max h h', max w w')
+                                        where
+                                            (h, w) = maxDimensions c
+                                            (h', w') = maxDimensions (Container cs)
+
+maxDimensionsPrim :: Primitive -> Dimension
+maxDimensionsPrim (Text _ _ _ (x, y) size _ str fromCenter) | fromCenter = (y + size / 2, x + (fromIntegral $ length str * 10) / 2)
+                                                            | otherwise  = (y + size, x + (fromIntegral $ length str * 10))
+maxDimensionsPrim (Line _ _ [])                             = (0, 0)                                                                    
+maxDimensionsPrim (Line _ _ [(x, y)])                       = (y, x)
+maxDimensionsPrim (Line ec et ((x, y):xs))                  = (max y y', max x x')
+                                                        where
+                                                            (y', x') = maxDimensionsPrim (Line ec et xs) 
+maxDimensionsPrim (Rect _ _ _ (x, y) (h, w))                = (y + h / 2, x + w / 2) 
+maxDimensionsPrim (Arc _ _ _ (x, y) r _ _)                  = (y + r, x + r)
+    
+
+
+ src/EventLoop/Output/SystemMessage.hs view
@@ -0,0 +1,19 @@+module EventLoop.Output.SystemMessage(SystemMessageOut(..)) where
+
+import EventLoop.Json
+import EventLoop.Config
+import EventLoop.CommonTypes
+
+-- System Messages Out
+data SystemMessageOut = CanvasSetup Dimension
+                      | Timer Bool
+                      | Close
+                               
+instance JSONAble SystemMessageOut where
+    toJsonMessage (CanvasSetup dim) = JSONObject [(JSONMember sysmessageanswerS (JSONString canvassetupS)), (JSONMember dimensionS (dimensionToJsonMessage dim))]
+    toJsonMessage (Timer bool)      = JSONObject [(JSONMember sysmessageanswerS (JSONString timerS)), (JSONMember useS (JSONBool bool))]
+    toJsonMessage (Close)           = JSONObject [(JSONMember sysmessageanswerS (JSONString closeS))]
+    
+-- Support Function
+dimensionToJsonMessage :: Dimension -> JSONMessage
+dimensionToJsonMessage (h, w) = JSONObject [(JSONMember hS (JSONNumber h)), (JSONMember wS (JSONNumber w))]
+ twentefp-eventloop-graphics.cabal view
@@ -0,0 +1,44 @@+name:                twentefp-eventloop-graphics
+version:             0.1.0.0
+synopsis:            An eventloop based graphical IO system. Used as Lab Assignments Environment at Univeriteit Twente
+description:         An eventloop based graphical IO system. It uses websockets as a way to communicate with IO devices; a browser in this case. This system is used in the Graphical submodule to be able to express graphical output using the eventloop system for a browser. 
+license:             BSD3
+license-file:        LICENSE
+author:              Sebastiaan la Fleur
+maintainer:          sebastiaan.la.fleur@gmail.com
+-- copyright:           
+category:            Graphics, Education
+build-type:          Simple
+cabal-version:       >=1.8
+
+library
+  exposed-modules:
+    EventLoop, 
+    EventLoop.Output, 
+    EventLoop.Input,
+    EventLoop.Output.Graphical,
+    EventLoop.Output.Single,
+    EventLoop.CommonTypes
+    
+  other-modules:
+    EventLoop.Main, 
+    EventLoop.Json, 
+    EventLoop.EventProcessor, 
+    EventLoop.Config, 
+    EventLoop.Output.SystemMessage, 
+    EventLoop.Output.OutputEvent, 
+    EventLoop.Output.Graphical.Graphical, 
+    EventLoop.Input.SystemMessage, 
+    EventLoop.Input.Mouse, 
+    EventLoop.Input.Keyboard, 
+    EventLoop.Input.InputEvent
+    
+  build-depends:
+    base                >= 4.6.0.1   && < 5, 
+    twentefp-websockets >= 0.1.0.0,
+    twentefp-number     >= 0.1.0.0,
+    text                >= 0.11.3.1,
+    network             >= 2.3       && < 2.6
+    
+  hs-source-dirs:
+    src