Another part of my experiments with GTK4 and Haskell was to investigate printing. That brought in the Cairo, Pango and PangoCairo C libraries, and the gi-cairo, gi-cairo-render, gi-cairo-connector, gi-pango, and gi-pangocairo Haskell packages.
PrintOperation
At the heart was to create a value of type PrintOperation, specifying its nPages and unit attributes and its handler of the drawPage signal, and use its run method with PrintOperationActionPrintDialog:
|
1 2 3 4 5 6 7 8 9 |
let onPrintButtonClicked :: IO () onPrintButtonClicked = do printOperation <- Gtk.new Gtk.PrintOperation [ #nPages := 1 , #unit := Gtk.UnitPoints , On #drawPage onDrawPage ] void $ #run printOperation Gtk.PrintOperationActionPrintDialog (Just window) |
renderWithContext
PrintOperationDrawPageCallback is a type synonym for PrintContext -> Int32 -> IO (), and overloaded method getCairoContext yields a value of type GI.Cairo.Structs.Context.Context (package gi-cairo). However, package gi-cairo-render provides no function to render to a Context. The solution is package gi-cairo-connector, which provides renderWithContext to bridge the gap.
|
1 2 3 4 |
let onDrawPage :: Gtk.PrintOperationDrawPageCallback onDrawPage printContext _pageNr = do context <- #getCairoContext printContext Cairo.renderWithContext exampleRender context |
exampleRender
Cairo has basic text functionality and Pango provides complex text functionality. My exampleRender used both:
|
1 2 3 4 5 6 7 8 9 10 11 12 |
exampleRender :: Cairo.Render () exampleRender = do Cairo.moveTo 72 72 Cairo.setFontSize 10 Cairo.showText ("Hello, Printer!" :: Text) Cairo.moveTo 72 144 Cairo.toRender $ \context -> do layout <- Pango.createLayout context #setText layout "Hello, Printer!" (-1) fontDescription <- Pango.fontDescriptionFromString "Cambria 14" #setFontDescription layout (Just fontDescription) Pango.showLayout context layout |
The Cario origin is the top left corner of the printable area. The printable area excludes the margins specified by the PageSetup.
Cairo’s showText renders text so that, by default, it is left-aligned and baseline-aligned.
Package gi-cairo-connector also provides toRender with type (GI.Cairo.Context -> IO ()) -> Render ().
Pango’s showLayout renders text so that the top-left corner of the Layout corresponds to the current point.