}
data IState = forall s. IS
- { {-sFrame :: Frame ()
- , sPanel :: Panel ()
- , buffer :: MemoryDC ()
- , -}postponed :: IORef [Request]
+ { window :: Gtk.Window
+ , buffer :: IORef Cairo.Surface
+ , postponed :: IORef [Request]
, usrState :: IORef s
, usrProg :: TinaStep s
}
runTina Main {..} = do
usrState <- newIORef initialState
postponed <- newIORef (GfxText (rgb 0 0 0) (pt 50 50) "foo" : GfxClear :initialRequests)
- let state = IS { usrProg = eventHandler, .. }
- runGUI {-(sz windowWidth windowHeight) -}state
+ let state = IS { window = undefined, buffer = undefined, usrProg = eventHandler, .. }
+ runGUI windowWidth windowHeight state
-runGUI :: {-Size ->-} IState -> IO ()
-runGUI s = do
+runGUI :: Int -> Int -> IState -> IO ()
+runGUI w h (IS { .. }) = do
-- Init GTK.
Gtk.initGUI
-- Create a window, which will make the mainloop terminated when
-- it is closed.
window <- Gtk.windowNew
+
Gtk.set window [ Gtk.containerBorderWidth := 10
- , Gtk.windowTitle := "FP Practicum" ]
+ , Gtk.windowTitle := "FP Practicum"
+ , Gtk.windowDefaultWidth := w
+ , Gtk.windowDefaultHeight := h
+ ]
Gtk.onDestroy window Gtk.mainQuit
+ -- Create a buffer to draw on (name the actual buffer buffer', so we
+ -- can use IS { .. } syntax below to pack the state. Using a record update
+ -- wouldn't work, probably because Cairo.Surface contains an existential
+ -- type...
+ -- We put the buffer in an IORef, so we can change it for a new one
+ -- later on (on window resizes).
+ buffer' <- Cairo.createImageSurface Cairo.FormatARGB32 w h
+ buffer <- newIORef buffer'
+
+ -- Register the expose event
+ Gtk.on window Gtk.exposeEvent $ onExpose buffer
+
+ -- Repack state
+ let state = IS { .. }
+
+ -- Process any initial requests
+ processPostponed state
+
-- Show the window and start the Gtk mainloop.
Gtk.widgetShowAll window
Gtk.mainGUI
+
+-- | Copy the given surface to the exposed window on an expose event.
+onExpose :: IORef Cairo.Surface -> EventM.EventM EventM.EExpose Bool
+onExpose buffer = do
+ current_buffer <- liftIO $ readIORef buffer
+ dw <- EventM.eventWindow
+ -- Copy the buffer to the window
+ liftIO $ Gtk.renderWithDrawable dw $ do
+ Cairo.setSourceSurface current_buffer 0 0
+ Cairo.paint
+ return True -- No clue what this means
{-
runGUI s IS {..} = do
-}
winHandler _ _ = Nothing
+gfxHandler s req = case gfxHandler' s req of
+ Nothing -> Nothing
+ Just render -> Just $ do
+ buf <- readIORef (buffer s)
+ Cairo.renderWith buf render
+ Gtk.widgetQueueDraw (window s)
+
{-
gfxHandler IS {..} (GfxLines col ps) = Just $ polyline buffer ps [penColor := col] >> dirtyPts sPanel ps
gfxHandler IS {..} (GfxPolygon col ps) = Just $ polygon buffer ps [penColor := col, brushColor := col] >> dirtyPts sPanel ps
gfxHandler IS {..} (GfxEllipse col rt) = Just $ ellipse buffer rt [penColor := col, brushKind := BrushTransparent] >> dirtyRect sPanel rt
gfxHandler IS {..} (GfxDisc col rt) = Just $ ellipse buffer rt [penColor := col, brushColor := col] >> dirtyRect sPanel rt
gfxHandler IS {..} (GfxFont st sz) = Just $ buffer `set` [ fontSize := sz, fontFace := st ]
-gfxHandler IS {..} GfxClear = Just $ dcClear buffer >> windowRefresh sPanel False
gfxHandler IS {..} (GfxPicture fd pt) = Just $ bitmapCreateFromFile fd >>= \bm -> drawBitmap buffer bm pt False [] >> bitmapGetSize bm >>= dirtyRect' sPanel pt
-}
-gfxHandler _ _ = Nothing
+gfxHandler' IS {..} GfxClear = Just $ Cairo.setSourceRGB 1 1 1 >> Cairo.paint
+gfxHandler' _ _ = Nothing
{-
dirtyPts :: Window a -> [Point] -> IO ()