Make testProg produce readable (non-overlapping) output.
[matthijs/projects/fpprac.git] / FPPrac.hs
index fcbf33e15c00def5e1ada934f01a03d24b340cdc..306f048001dca25e62b2864c98e2b01fda06af78 100644 (file)
--- a/FPPrac.hs
+++ b/FPPrac.hs
@@ -93,7 +93,7 @@ data TinaProgram = forall s. Main
 testProg = Main
        { initialState    = 1
        , initialRequests = [GfxText red (pt 0 0) "foo", GfxText blue (pt 100 100) "bar"]
-       , eventHandler    = \s e -> (s+1,[GfxText green (pt 50 50) $ show (s,e)])
+       , eventHandler    = \s e -> (s+1,[GfxText green (pt 50 (50 + 10 * s)) $ show (s,e)])
        , windowWidth     = 200
        , windowHeight    = 200
        }
@@ -162,21 +162,32 @@ runGUI w h (IS { .. }) = do
        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 { .. }
        
+       -- Register events
+       Gtk.on window Gtk.exposeEvent $ onExpose buffer
+       Gtk.on window Gtk.configureEvent $ onResize buffer
+       Gtk.on window Gtk.keyPressEvent $ onKeyDown state
+
        -- 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.
+-- | Called when a key is pressed.
+onKeyDown :: IState -> EventM.EventM EventM.EKey Bool
+onKeyDown s = do
+       keyval <- EventM.eventKeyVal
+       case Gtk.keyToChar keyval of
+               Just c -> liftIO $ post s (KeyIn c)
+               Nothing -> return ()
+       return True -- No clue what this means
+
+-- | Called when (part of) the window should be redrawn. 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
@@ -187,6 +198,32 @@ onExpose buffer = do
                Cairo.paint
        return True -- No clue what this means
 
+-- | Called when the window is resized. Resize the given buffer if needed.
+onResize :: IORef Cairo.Surface -> EventM.EventM EventM.EConfigure Bool
+onResize buffer = do
+       -- Get the current buffer and see if it's still big enough
+       current_buffer <- liftIO $ readIORef buffer
+       sw <- Cairo.imageSurfaceGetWidth current_buffer
+       sh <- Cairo.imageSurfaceGetHeight current_buffer
+       -- Get the current drawwindow and its size
+       dw <- EventM.eventWindow
+       (w, h) <- liftIO $ Gtk.drawableGetSize dw
+       when (w > sw || h > sh) $ liftIO $ do
+               -- Buffer is too small, expand it.
+               new_buffer <- Cairo.createImageSurface Cairo.FormatARGB32 w h
+               -- Fill it with white and copy the old buffer
+               Cairo.renderWith new_buffer $ do
+                       Cairo.setSourceRGB 1 1 1
+                       Cairo.paint
+                       Cairo.setSourceSurface current_buffer 0 0
+                       Cairo.paint
+               -- Clean up the old buffer
+               Cairo.surfaceFinish current_buffer
+               -- Store and return the new buffer
+               writeIORef buffer new_buffer
+       return True -- No clue what this means
+                               
+
 {-
 runGUI s IS {..} = do
        sFrame <- frame
@@ -236,6 +273,8 @@ transKey _ _ = return ()
 
 -}
 
+-- | Handlers for various requests.
+miscHandler, winHandler, gfxHandler :: IState -> Request -> Maybe (IO ())
 {-
 miscHandler s@IS {..} (FRead  fn     ) = Just $ readFile fn >>= post s . FileContents fn
 miscHandler   IS {..} (FWrite fn cnts) = Just $ writeFile fn cnts
@@ -261,7 +300,7 @@ winHandler s@IS {..} (WinMenu      ms) = Just $ mkMenu >>= \ms' -> sFrame `set`
 -}
 winHandler _        _                = Nothing
 
-gfxHandler s req = case gfxHandler' req of
+gfxHandler s req = case gfxHandler' req of
        Nothing -> Nothing
        Just render -> Just $ do
                buf <- readIORef (buffer s)
@@ -278,12 +317,19 @@ gfxHandler IS {..} (GfxDisc      col rt)    = Just $ ellipse buffer rt [penColor
 gfxHandler IS {..} (GfxFont      st  sz)    = Just $ buffer `set` [ fontSize := sz, fontFace := st ]
 gfxHandler IS {..} (GfxPicture   fd  pt)    = Just $ bitmapCreateFromFile fd >>= \bm -> drawBitmap buffer bm pt False [] >> bitmapGetSize bm >>= dirtyRect' sPanel pt
 -}
-gfxHandler' IS {..} (GfxText      col (Point x y) st) = Just $ do
+-- | Helper function for gfxHanlder
+gfxHandler' :: Request -> Maybe (Cairo.Render ())
+gfxHandler' (GfxText col (Point x y) st) = Just $ do
+       -- Set the source color, move to the requested position and draw the
+       -- text
        setSourceColor col
        Cairo.moveTo (fromIntegral x) (fromIntegral y)
        Cairo.showText st 
-gfxHandler' IS {..}  GfxClear                = Just $ Cairo.setSourceRGB 1 1 1 >> Cairo.paint
-gfxHandler' _        _                       = Nothing
+gfxHandler' GfxClear = Just $ do
+       -- Set the source to white and paint the entire surface with it
+       Cairo.setSourceRGB 1 1 1
+       Cairo.paint
+gfxHandler' _ = Nothing
 
 -- | Sets the source to a pattern fill of the given color
 setSourceColor :: Color -> Cairo.Render ()