Created
October 9, 2014 14:29
-
-
Save leftaroundabout/a999a9c0aab1eb0d40ed to your computer and use it in GitHub Desktop.
Simple example of rendering diagrams to a GTK window. Being an updated version of https://groups.google.com/forum/#!topic/diagrams-discuss/IWSGyN--AlM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE NoMonomorphismRestriction #-} | |
{- | A first example of drawing diagrams from within GTK. This | |
program draws a Koch snowflake with the depth controllable | |
via a GTK widget. | |
-} | |
module Main where | |
import Graphics.UI.Gtk | |
import Diagrams.Prelude | |
import Diagrams.TwoD.Size (requiredScaleT) | |
import Diagrams.Backend.Gtk | |
import Diagrams.Backend.Cairo (Cairo) | |
import qualified Data.Colour as C | |
-- Our drawing code, copied from | |
-- projects.haskell.org/diagrams/gallery/Pentaflake.html | |
colors = iterate (C.blend 0.1 white) blue | |
p = regPoly 5 1 # lwO 0 | |
-- | create a snowflake diagram of depth @n@ | |
-- | |
-- specifying a type here because the monoidal query type needs to be specified | |
-- for @drawToGtk@, otherwise get a "No instance for (PathLike ..." error. | |
pentaflake :: Int -> Diagram Cairo R2 | |
pentaflake 0 = p | |
pentaflake n = appends (p' # fc (colors !! (n-1))) | |
(zip vs (repeat (rotateBy (1/2) p'))) | |
where vs = take 5 . iterate (rotateBy (1/5)) | |
. (if odd n then negateV else id) $ unitY | |
p' = pentaflake (n-1) | |
pentaflake' n = pentaflake n # fc (colors !! n) | |
-- end of diagrams code | |
-- A function to set up the main window and signal handlers | |
createMainWindow = do | |
win <- windowNew | |
onDestroy win mainQuit | |
drawArea <- drawingAreaNew | |
depthWidget <- spinButtonNewWithRange 1 10 1 | |
-- when the spinButton changes, redraw the window | |
depthWidget `onValueSpinned` (widgetQueueDraw drawArea) | |
-- handle the drawArea's @onExpose@ signal. We provide a function | |
-- that takes an area marked as dirty and redraws it. | |
-- This program simply redraws the entire drawArea. | |
-- | |
-- Many gtk signal handlers return True if the signal was handled, and False | |
-- otherwise (in which case the signal will be propagated to the parent). | |
drawArea `onExpose` \_dirtyRect -> do | |
-- can't draw to a drawArea directly (this is a limitation of gtk2hs), | |
-- so first we retrieve the drawWindow and render to that instead. | |
-- Drawing to GTK requires that we manually specify the size | |
-- and positioning, | |
-- | |
-- however we can use @adjustSize@ to calculate the necessary rescaling | |
-- for a full-scale image | |
-- | |
-- the @toGtkCoords@ function performs two tasks. It centers the diagram | |
-- in the drawWindow, and reflects it about the Y-axis. The Y-axis | |
-- reflection is due to an orientation mismatch between Cairo and | |
-- diagrams. | |
(canvasX,canvasY) <- widgetGetSize drawArea -- size in pixels (Int) | |
curDepth <- spinButtonGetValueAsInt depthWidget | |
let dia = pentaflake curDepth | |
fI = fromIntegral | |
spec = mkSizeSpec (Just $ fI canvasX) (Just $ fI canvasY) | |
scaledDia = toGtkCoords $ transform (requiredScaleT spec (size2D dia)) dia | |
drawWindow <- widgetGetDrawWindow drawArea | |
renderToGtk drawWindow scaledDia | |
return True | |
-- add the depthWidget control and drawArea to the main window | |
hbox <- hBoxNew False 0 | |
boxPackStart hbox depthWidget PackNatural 0 | |
boxPackStart hbox drawArea PackGrow 0 | |
containerAdd win hbox | |
return win | |
-- Gtk application | |
-- | |
-- initial the library, create and show the main window, | |
-- finally enter the main loop | |
main :: IO () | |
main = do | |
initGUI | |
win <- createMainWindow | |
widgetShowAll win | |
onDestroy win mainQuit | |
onSizeRequest win $ return (Requisition 200 200) -- request minimum size | |
mainGUI | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment