haskellgtkhaskell-diagrams

How do I use the diagrams library with GTK drawables?


I'm trying to learn how to draw diagrams using the diagrams library and the Cairo / GTK backend. I've got a blank window to appear, but my drawing won't render. What am I doing wrong?

module Main where

import Control.Monad.Trans (liftIO)
import Graphics.UI.Gtk
import Diagrams.Backend.Cairo
import Diagrams.Backend.Cairo.Gtk
import Diagrams.Prelude

main :: IO ()
main = do
  initGUI
  window <- windowNew
  canvas <- drawingAreaNew
  canvas `on` sizeRequest $ return (Requisition 1000 1000)
  set window [ containerBorderWidth := 10,
               containerChild := canvas ]
  canvas `on` exposeEvent $ renderFigure
  onDestroy window mainQuit
  widgetShowAll window
  mainGUI


renderFigure :: EventM EExpose Bool
renderFigure = do
   win <- eventWindow
   liftIO $ renderToGtk win $ toGtkCoords figure
   -- liftIO $ defaultRender win figure
   return True


figure :: Diagram Cairo R2
figure =  unitCircle # scaleX 0.5 # rotateBy (1/6) # scale 50

I've tried using "defaultRender" (as commented out above), but that gives a type error: apparently "win" is not the right type.

I've read the tutorial and user manual for diagram, but it doesn't actually tell you how to use the Cairo backend.

Update: I've got the ellipse to render. The "renderFigure" function now says:

renderFigure :: DrawingArea -> EventM EExpose Bool
renderFigure canvas = do
   -- win <- eventWindow
   liftIO $ do
      -- diagramArea <- widgetGetDrawWindow canvas 
      -- renderToGtk diagramArea $ toGtkCoords figure
      defaultRender canvas figure
   return True

and the DrawingArea passed in is the "canvas" referenced in the "canvas on exposeEvent..." setting.

But I still can't get it to render a fixed size diagram using "renderToGtk".

Update 2: Thanks to Joachim Breitner's answer, I've now got the minimal diagram-on-GTK program looking like this, ready for your cut-and-paste pleasure.

module Main where

import Control.Monad.Trans (liftIO)
import Graphics.UI.Gtk
import Diagrams.Backend.Cairo
import Diagrams.Backend.Cairo.Gtk
import Diagrams.Prelude

main :: IO ()
main = do
  initGUI
  window <- windowNew
  canvas <- drawingAreaNew
  canvas `on` sizeRequest $ return (Requisition 256 256)
  set window [ containerBorderWidth := 10,
               containerChild := canvas ]
  canvas `on` exposeEvent $ renderFigure
  onDestroy window mainQuit
  widgetShowAll window
  mainGUI


renderFigure :: EventM EExpose Bool
renderFigure = do
   win <- eventWindow
   liftIO $ renderToGtk win $ toGtkCoords figure
   return True


figure :: Diagram Cairo R2
figure =  unitCircle # scaleX 0.5 # rotateBy (1/6) # scale 50 # fc red  

Solution

  • Your initial code actually works. But renderToGtk does not scale the image, so it appears rather small, too small to be visible at that line width. But try

    figure :: Diagram Cairo R2
    figure =  unitCircle # scaleX 0.5 # rotateBy (1/6) # scale 50 # fc red
    

    and it will work like a charm!