I'm trying to make a toy application, just to get my head around how to write event driven programs in Haskell. What I'm trying to do is draw a line to a canvas which moves forward every time a key is pressed (so it's sort of a primordial cursor in a text editor).
My problem is I can't work out what the best way to count the number of times the user has pressed a key. Obviously I can't use a global variable like I would in an imperative program so presumably I need to pass the state around on the call stack, but in GTK execution descends into the main loop after each event handler returns and since I don't control the main loop I don't see how I can pass the changed global state from one event handler. So how can one event handler ever pass state onto another event handler?
I have a sort of partial solution here, where the keyboard event re-curries myDraw and sets it as a new the event handler. I'm not sure if this solution can be extended, or even if it's a good idea.
What's the best particle solution to this problem?
import Graphics.UI.Gtk
import Graphics.Rendering.Cairo
main :: IO ()
main= do
initGUI
window <- windowNew
set window [windowTitle := "Hello World",
windowDefaultWidth := 300, windowDefaultHeight := 200]
canvas <- drawingAreaNew
containerAdd window canvas
widgetShowAll window
draWin <- widgetGetDrawWindow canvas
canvas `on` exposeEvent $ do liftIO $ renderWithDrawable draWin (myDraw 10)
return False
window `on` keyPressEvent $ onKeyboard canvas
window `on` destroyEvent $ do liftIO mainQuit
return False
mainGUI
onKeyboard :: DrawingArea -> EventM EKey Bool
onKeyboard canvas = do
liftIO $ do drawWin <- widgetGetDrawWindow canvas
canvas `on` exposeEvent $ do liftIO $renderWithDrawable drawWin (myDraw 20)
return False
widgetQueueDraw canvas
return False
myDraw :: Double -> Render ()
myDraw pos = do
setSourceRGB 1 1 1
paint
setSourceRGB 0 0 0
moveTo pos 0
lineTo pos 20
stroke