I'm not so experienced in Haskell and I've just started using Gtk2Hs so this might be a silly question.
I have the following Line
type defined:
type Coord = (Int,Int)
type Line = (Coord,Coord)
And I have a function which draws a list of Line
s on a DrawingArea
. The problem is that this function draws all the Line
s at the same time but I would like to draw them one at a time with a little delay between two Line
s.
render :: [Line] -> IO ()
render lines =
do initGUI
win <- windowNew
windowSetTitle win "Animation"
win `onDestroy` mainQuit
can <- drawingAreaNew
can `onSizeRequest` return (Requisition 400 400)
can `onExpose` drawCanvas lines can
but <- buttonNewWithLabel "Quit"
but `onClicked` mainQuit
hbox <- hBoxNew False 0
boxPackStart hbox but PackRepel 150
vbox <- vBoxNew False 5
containerAdd vbox can
containerAdd vbox hbox
containerAdd win vbox
widgetShowAll win
mainGUI
This function gets called when the DrawingArea
is exposed:
drawCanvas :: [Line] -> DrawingArea -> event -> IO Bool
drawCanvas lines can _evt =
do dw <- widgetGetDrawWindow can
drawWindowClear dw
gc <- gcNew dw
mapM_ (\(a,b) -> drawLine dw gc a b) lines
return True
I have considered using a StateT
to keep track of which Line
s have yet to be drawn but I don't know how to implement the animation. Even if a call widgetShowAll
every time after altering the state, the window doesn't get shown until mainGUI
is called.
Is it possible to make a new thread that continuously updates the state while drawCanvas
somehow takes care of the drawing? If so, could somebody please show me an example of such behavior? Or is there a better approach perhaps?
Gtk2Hs allows to set up "timers" that call functions at regular intervals. So I would do the following:
timeoutAdd
before mainGUI, like this: timeoutAdd (update can lines) 100
to set up a timer that will run every 100 milliseconds and call a new function "update" with the DrawingArea and the IORef/MVar with the animation state as parameters.widgetQueueDraw can
so that the drawing area is re-exposed. That will call "drawCanvas" automatically because it is connected to the expose event. "update" has to return an IO Bool. Returning False will stop the timer.I find it meaningful to update the animation's state and the drawing in separate functions.