How do I use the diagrams library with GTK drawables?

1.1k views Asked by At

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  
2

There are 2 answers

0
Joachim Breitner On BEST ANSWER

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!

0
tobiasBora On

You can note that in recent versions of diagrams, you should use

import Diagrams.Backend.Gtk

instead of

import Diagrams.Backend.Cairo.Gtk

and

figure :: Diagram Cairo

instead of

figure :: Diagram Cairo R2

The result now looks like :

module Main where

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

main :: IO ()
main = do
  initGUI
  window <- windowNew
  canvas <- drawingAreaNew
  canvas `on` sizeRequest $ return (Requisition 256 256)
  Graphics.UI.Gtk.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
figure =  unitCircle # scaleX 0.5 # rotateBy (1/6) # scale 50 # fc red