diagrams-hsqml-0.0.0.2: src/Diagrams/Backend/HsQML/Tutorial.hs
{-# OPTIONS_GHC -fno-warn-unused-imports #-}
module Diagrams.Backend.HsQML.Tutorial (
-- * DiagramCanvas QML script
-- $diagramcanvas
-- * Context object
-- $contextobject
-- * Main window
-- $mainwindow
-- * Rendering diagrams
-- $rendering
) where
import Graphics.QML
import Diagrams.Backend.HsQML
import Diagrams.Backend.HsQML.DiagramObj.Type
{- $diagramcanvas
To use this backend you first need a custom Canvas object to handle signals coming from Haskell.
Example script to place in your QML search path (can be next to your main QML document):
> -- DiagramCanvas.qml
>import QtQuick 2.4
>
>Canvas {
> id: canvas;
> property variant diagram;
> renderStrategy: Canvas.Threaded;
> renderTarget: Canvas.FramebufferObject;
>
> onDiagramChanged: {
> var context = canvas.getContext('2d');
> if(canvas.diagram && context) {
> console.log("reconnect");
> canvas.diagram.save.connect(function() {canvas.context.save()})
> canvas.diagram.restore.connect(function () {canvas.context.restore()});
> canvas.diagram.text.connect(function (text,x,y) {canvas.context.strokeText(text,x,y)});
> canvas.diagram.beginPath.connect(function () {canvas.context.beginPath()});
> canvas.diagram.closePath.connect(function () {canvas.context.closePath()});
> canvas.diagram.stroke.connect(function () {canvas.context.stroke()});
> canvas.diagram.fill.connect(function() {canvas.context.fill()});
> canvas.diagram.moveTo.connect(function (x,y) {canvas.context.moveTo(x,y)});
> canvas.diagram.lineTo.connect(function (x,y) {canvas.context.lineTo(x,y)});
> canvas.diagram.bezierCurveTo.connect(function(cp1x,cp1y,cp2x,cp2y,x,y)
> {canvas.context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)});
> canvas.diagram.connectLinearGradient.connect(connectLG);
> canvas.diagram.connectRadialGradient.connect(connectRG);
>
> canvas.diagram.setStrokeColour.connect(function(r,g,b,a)
> {canvas.context.strokeStyle = Qt.rgba(r,g,b,a).toString();});
> canvas.diagram.setFillColour.connect(function(r,g,b,a)
> {canvas.context.fillStyle = Qt.rgba(r,g,b,a)});
> canvas.diagram.setFont.connect(function(f) {canvas.context.font = f});
> canvas.diagram.setLineWidth.connect(function(w) {canvas.context.lineWidth = w});
> canvas.diagram.oddEvenFill.connect(function() {canvas.context.fillRule = Qt.OddEvenFill});
> canvas.diagram.windingFill.connect(function() {canvas.context.fillRule = Qt.WindingFill});
> } else {
> console.log("warning! no diagram or context object to connect");
> }
> }
>
> onPaint: {
> if(canvas.diagram) {
> canvas.diagram.reload();
> }
> }
>
> function connectLG(gradient, x0, y0, x1, y1) {
> var grad = canvas.context.createLinearGradient(x0, y0, x1, y1);
> gradient.addStop.connect( function(r,g,b,a, off) {grad.addColorStop(off, Qt.rgba(r,g,b,a))});
> canvas.diagram.setLineGradient.connect(function() {canvas.context.strokeStyle = grad;});
> canvas.diagram.setFillGradient.connect(function() {canvas.context.fillStyle = grad;});
>
> }
>
> function connectRG(gradient, x0, y0, r0, x1, y1, r1) {
> var grad = canvas.context.createRadialGradient(x0, y0, r0, x1, y1, r1);
> gradient.addStop.connect(function(r,g,b,a, off) {grad.addColorStop(off, Qt.rgba(r,g,b,a))});
> canvas.diagram.setLineGradient.connect(function() {canvas.context.strokeStyle = grad;});
> canvas.diagram.setFillGradient.connect(function() {canvas.context.fillStyle = grad;});
> }
>}
-}
{- $contextobject
You can make an 'ObjRef' to a 'DiagramObj' available to the QML script by placing it in a property of your context object:
> -- Main.hs
> module Main where
> import Control.Applicative
> import Control.Concurrent
> import Control.Concurrent.MVar
> import Data.Typeable
> import Diagrams.Prelude
> import Diagrams.Backend.HsQML
> import Graphics.QML
>
>data Repaint deriving Typeable
>
>repaint :: Proxy Repaint
>repaint = Proxy
>
>instance SignalKeyClass Repaint where
> type SignalParams Repaint = IO ()
>
>data MainObj = MainObj
> { diagramObj :: MVar (ObjRef (DiagramObj ()))
> }
> deriving Typeable
>
>instance DefaultClass MainObj where
> classMembers =
> [ defPropertySigRO' "mainDiagram" diagramChanged $ \this ->
> case fromObjRef this of
> MainObj mvar -> readMVar mvar
> , defPropertyConst' "self" return
> , defSignal "repaint" repaint
> ]
-}
{- $mainwindow
Then, place a DiagramCanvas somewhere in your application, and connect it to the controller object:
> -- main.qml
>import QtQuick 2.0
>import QtQuick.Controls 1.3
>import QtQuick.Window 2.2
>
>ApplicationWindow {
> title: "test";
> width: 800;
> height: 800;
> visible: true;
>
> toolBar: ToolBar {
> ToolButton {
> onClicked: canvas.repaint();
> }
> }
>
> DiagramCanvas {
> id: canvas;
> anchors.fill: parent;
>
> function repaint() {
> canvas.diagram = self.mainDiagram;
> canvas.paint(canvas.canvasWindow);
> }
>
> Connections {
> target: self;
> onRepaint: canvas.repaint();
> }
> }
>
>}
-}
{- $rendering
The 'renderHsQML' function creates an 'ObjRef' to the controller object.
> -- Main.hs
>diagram :: Diagram B R2
>diagram = circle 1
>
>main :: IO ()
>main = do
> diag <- renderHsQML (mkSizeSpec (Just 800) (Just 800)) diagram
> mainObj <- MainObj <$> newMVar diag
> ctx <- newObjectDC mainObj
> runEngineLoop defaultEngineConfig
> { initialDocument = fileDocument "qml/main.qml"
> , contextObject = Just $ anyObjRef ctx
> }
-}