content: {-# LANGUAGE NoImplicitPrelude #-}
  {-# LANGUAGE OverloadedStrings #-}
  module Main (main) where
  
  import           Data.Text (Text)
  import qualified Data.Text as Text
  import qualified Data.Text.IO as Text.IO
  
  import           Graphics.Blank
  import qualified Graphics.Blank.Style as Style
  
  import           Paths_blank_canvas_examples
  
  import           Prelude.Compat
  
  main :: IO ()
  main = do
   dat <- getDataDir
   print dat
   blankCanvas 3000 { events = ["mousedown"]
                    , debug = True
                    , root = dat
                    } $ \ canvas -> do
    princessURL <- staticURL canvas "type/jpeg" "/images/princess.jpg"
    fanURL      <- staticURL canvas "type/jpeg" "/images/fan.jpg"
    sequence_ [ -- blank the screeen
  
                do send canvas $ do
                        let (w,h) = size canvas
                        clearRect (0,0,w,h)
                        beginPath()
                        globalAlpha 1.0 -- reset this global property
  
                   -- run this example
                   send canvas $ do
                        save()
  
                   example $ EC { ecCanvas      = canvas
                                , ecPrincessURL = princessURL
                                , ecFanURL      = fanURL
                                }
  
                   send canvas $ do
                        restore()
  
                   -- draw the watermark in corner
                   send canvas $ message canvas name
  
                   -- wait for a mouse press
                   wait canvas
  
              | (example,name) <- drop 15 $ cycle (map wrap examples ++ io_examples)
              ]
      where wrap (example,name) = (\ec -> send (ecCanvas ec) (example ec), name)
  
  examples :: [(ExampleContext -> Canvas (), Text)]
  examples =
          -- Lines
          [ (example_1_2_1,"1.2.1 Line")
          , (example_1_2_2,"1.2.2 Line Width")
          , (example_1_2_3,"1.2.3 Line Color")
          , (example_1_2_4,"1.2.4 Line Cap")
          -- Curves
          , (example_1_3_1,"1.3.1 Arc")
          , (example_1_3_2,"1.3.2 Quadratic Curve")
          , (example_1_3_3,"1.3.3 Bezier Curve")
          -- Paths
          , (example_1_4_1,"1.4.1 Path")
          , (example_1_4_2,"1.4.2 Line Join")
          , (example_1_4_3,"1.4.3 Rounded Corners")
          -- Shapes
          , (example_1_5_1,"1.5.1 Custom Shape")
          , (example_1_5_2,"1.5.2 Rectangle")
          , (example_1_5_3,"1.5.3 Circle")
          , (example_1_5_4,"1.5.4 Semicircle")
          -- Fill Styles
          , (example_1_6_1,"1.6.1 Shape Fill")
          , (example_1_6_2,"1.6.2 Linear Gradient")
          , (example_1_6_3,"1.6.3 Radial Gradient")
          , (example_1_6_4,"1.6.4 Pattern")
          -- Images
          , (example_1_7_1,"1.7.1 Image")
          , (example_1_7_2,"1.7.2 Image Size")
          , (example_1_7_3,"1.7.3 Image Crop")
          , (example_1_7_4,"1.7.4 Image Loader")
          -- Text
          , (example_1_8_1,"1.8.1 Text Font & Size")
          , (example_1_8_2,"1.8.2 Text Color")
          , (example_1_8_3,"1.8.3 Text Stroke")
          , (example_1_8_4,"1.8.4 Text Align")
          , (example_1_8_5,"1.8.5 Text Baseline")
          , (example_1_8_6,"1.8.6 Text Metrics")
          , (example_1_8_7,"1.8.7 Text Wrap")
          -- Transformations 2.1
          , (example_2_1_1,"2.1.1 Translate Transform")
          -- Composites 2.2
          , (example_2_2_1,"2.2.1 Shadow")
          , (example_2_2_2,"2.2.2 Global Alpha")
          , (example_2_2_3,"2.2.3 Clipping Region")
          , (example_2_2_4,"2.2.4 Global Composite Operations")
          -- Image Data & URLs 2.3
  --        , (example_2_3_1,"2.3.1 Image Data")
  --        , (example_2_3_2,"2.3.2 Invert Image Colors")
  --        , (example_2_3_3,"2.3.3 Grayscale Image Colors")
          -- Animation 2.4
          -- Mouse Detection 2.5
          ]
  
  io_examples :: [(ExampleContext -> IO (), Text)]
  io_examples =
          [ (example_2_3_4,"2.3.4 Get Image Data URL")
          , (example_2_3_5,"2.3.5 Load Image Data URL")
          ]
  
  data ExampleContext = EC
    { ecCanvas      :: DeviceContext
    , ecPrincessURL :: URL
    , ecFanURL      :: URL
    }
  
  -- Examples taken from http://www.html5canvastutorials.com/tutorials/html5-canvas-tutorials-introduction/
  
  {- For example, here is the JavaScript for 1.2.1
            moveTo(100, 150);
            lineTo(450, 50);
            stroke();
  -}
  example_1_2_1, example_1_2_2, example_1_2_3, example_1_2_4,
      example_1_3_1, example_1_3_2, example_1_3_3,
      example_1_4_1, example_1_4_2, example_1_4_3,
      example_1_5_1, example_1_5_2, example_1_5_3, example_1_5_4,
      example_1_6_1, example_1_6_2, example_1_6_3, example_1_6_4,
      example_1_7_1, example_1_7_2, example_1_7_3, example_1_7_4,
      example_1_8_1, example_1_8_2, example_1_8_3, example_1_8_4, example_1_8_5, example_1_8_6, example_1_8_7,
      example_2_1_1,
      example_2_2_1, example_2_2_2, example_2_2_3, example_2_2_4
    :: ExampleContext -> Canvas ()
  
  example_1_2_1 _ = do
          moveTo(100,150)
          lineTo(450,50)
          stroke()
  
  example_1_2_2 _ = do
          moveTo(100,150)
          lineTo(450,50)
          lineWidth 15
          stroke()
  
  example_1_2_3 _ = do
          moveTo(100,150)
          lineTo(450,50)
          lineWidth 5
          strokeStyle "#ff0000"
          stroke()
  
  example_1_2_4 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
  
          sequence_
             [ do beginPath()
                  moveTo(200, h / 2 + n)
                  lineTo(w - 200, h / 2 + n)
                  lineWidth 20
                  strokeStyle "#0000ff"
                  lineCap cap
                  stroke()
             | (cap,n) <- zip ["butt","round","square"] [-50,0,50]
             ]
  
  example_1_3_1 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          let centerX = w / 2;
          let centerY = h / 2;
          let radius = 75;
          let startingAngle = 1.1 * pi
          let endingAngle = 1.9 * pi
          let counterclockwise = False
          arc(centerX, centerY, radius, startingAngle, endingAngle, counterclockwise)
          lineWidth 15
          strokeStyle "black"
          stroke()
  
  example_1_3_2 _ = do
          beginPath()
          moveTo(188, 150)
          quadraticCurveTo(288, 0, 388, 150)
          lineWidth 10
          -- line color
          strokeStyle "black"
          stroke()
  
  example_1_3_3 _ = do
          beginPath()
          moveTo(188, 150)
          bezierCurveTo(140, 10, 388, 10, 388, 170)
          lineWidth 10
          -- line color
          strokeStyle "black"
          stroke()
  
  example_1_4_1 _ = do
  
          beginPath()
          moveTo(100, 20)
          -- line 1
          lineTo(200, 160)
          -- quadratic curve
          quadraticCurveTo(230, 200, 250, 120)
          -- bezier curve
          bezierCurveTo(290, -40, 300, 200, 400, 150)
          -- line 2
          lineTo(500, 90)
          lineWidth 5
          strokeStyle "blue"
          stroke()
  
  
  example_1_4_2 _ = do
          lineWidth 25;
  
        -- miter line join (left)
          beginPath();
          moveTo(99, 150);
          lineTo(149, 50);
          lineTo(199, 150);
          lineJoin "miter";
          stroke();
  
        -- round line join (middle)
          beginPath();
          moveTo(239, 150);
          lineTo(289, 50);
          lineTo(339, 150);
          lineJoin "round";
          stroke();
  
        -- bevel line join (right)
          beginPath();
          moveTo(379, 150);
          lineTo(429, 50);
          lineTo(479, 150);
          lineJoin "bevel";
          stroke();
  
  example_1_4_3 _ = do
          lineWidth 25;
  
          let rectWidth = 200;
          let rectHeight = 100;
          let rectX = 189;
          let rectY = 50;
          let cornerRadius = 50;
  
          beginPath();
          moveTo(rectX, rectY);
          lineTo(rectX + rectWidth - cornerRadius, rectY);
          arcTo(rectX + rectWidth, rectY, rectX + rectWidth, rectY + cornerRadius, cornerRadius);
          lineTo(rectX + rectWidth, rectY + rectHeight);
          lineWidth 5;
          stroke();
  
  example_1_5_1 _ = do
          beginPath();
          moveTo(170, 80);
          bezierCurveTo(130, 100, 130, 150, 230, 150);
          bezierCurveTo(250, 180, 320, 180, 340, 150);
          bezierCurveTo(420, 150, 420, 120, 390, 100);
          bezierCurveTo(430, 40, 370, 30, 340, 50);
          bezierCurveTo(320, 5, 250, 20, 250, 50);
          bezierCurveTo(200, 5, 150, 20, 170, 80);
        -- complete custom shape
          closePath();
          lineWidth 5;
          strokeStyle "blue";
          stroke();
  
  example_1_5_2 _ = do
          beginPath();
          rect(188, 50, 200, 100);
          fillStyle "yellow";
          fill();
          lineWidth 7;
          strokeStyle "black";
          stroke();
  
  example_1_5_3 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          let centerX = w / 2
          let centerY = h / 2
          let radius = 70
  
          beginPath()
          arc(centerX, centerY, radius, 0, 2 * pi, False)
          fillStyle "#8ED6FF"
          fill()
          lineWidth  5
          strokeStyle "black"
          stroke()
  
  example_1_5_4 _ = do
          beginPath();
          arc(288, 75, 70, 0, pi, False);
          closePath();
          lineWidth 5;
          fillStyle "red";
          fill();
          strokeStyle "#550000";
          stroke();
  
  example_1_6_1 _ = do
          beginPath();
          moveTo(170, 80);
          bezierCurveTo(130, 100, 130, 150, 230, 150);
          bezierCurveTo(250, 180, 320, 180, 340, 150);
          bezierCurveTo(420, 150, 420, 120, 390, 100);
          bezierCurveTo(430, 40, 370, 30, 340, 50);
          bezierCurveTo(320, 5, 250, 20, 250, 50);
          bezierCurveTo(200, 5, 150, 20, 170, 80);
  
        -- complete custom shape
          closePath();
          lineWidth 5;
          fillStyle "#8ED6FF";
          fill();
          strokeStyle "blue";
          stroke();
  
  example_1_6_2 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          rect(0, 0, w, h)
          grd <- createLinearGradient(0, 0, w, h)
          -- light blue
          grd # addColorStop(0, "#8ED6FF")
          -- dark blue
          grd # addColorStop(1, "#004CB3")
          Style.fillStyle grd;
          fill();
  
  example_1_6_3 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          rect(0, 0, w, h)
          grd <- createRadialGradient (238, 50, 10, 238, 50, 300)
          -- light blue
          grd # addColorStop(0, "#8ED6FF")
          -- dark blue
          grd # addColorStop(1, "#004CB3")
          Style.fillStyle grd;
          fill();
  
  example_1_6_4 EC{ecCanvas = canvas, ecFanURL = fanURL} = do
          let (w,h) = size canvas
          imageObj <- newImage fanURL
          pattern <- createPattern (imageObj,"repeat")
          rect(0, 0, w, h);
          Style.fillStyle pattern;
          fill();
  
  example_1_7_1 EC{ecPrincessURL = princessURL} = do
          img <- newImage princessURL
          drawImage(img,[69,50])
  
  example_1_7_2 EC{ecPrincessURL = princessURL} = do
          img <- newImage princessURL
          drawImage(img,[69,50,97,129])
  
  example_1_7_3 EC{ecPrincessURL = princessURL} = do
          img <- newImage princessURL
          drawImage(img,[400,200,300,400,100,100,150,200])
  
  example_1_7_4 EC{ecPrincessURL = princessURL, ecFanURL = fanURL} = do
          img1 <- newImage princessURL
          img2 <- newImage fanURL
          drawImage(img1,[69,50,97,129])
          drawImage(img2,[400,50])
  
  example_1_8_1 _ = do
          font "40pt Calibri"
          fillText("Hello World!", 150, 100)
  
  example_1_8_2 _ = do
          font "40pt Calibri"
          fillStyle "#0000ff"
          fillText("Hello World!", 150, 100)
  
  example_1_8_3 _ = do
          font "60pt Calibri"
          lineWidth 3
          strokeStyle "blue"
          strokeText("Hello World!", 80, 110)
  
  example_1_8_4 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          let x = w / 2
          let y = h / 2
          font "30pt Calibri"
          textAlign "center"
          fillStyle "blue"
          fillText("Hello World!", x, y)
  
  example_1_8_5 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          let x = w / 2
          let y = h / 2
          font "30pt Calibri"
          textAlign "center"
          textBaseline "middle"
          fillStyle "blue"
          fillText("Hello World!", x, y)
  
  example_1_8_6 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          let x = w / 2
          let y = h / 2 - 10;
          let text = "Hello World!"
          font "30pt Calibri"
          textAlign "center"
          fillStyle "blue"
          fillText(text, x, y)
  
          TextMetrics w' <- measureText text
          font "20pt Calibri"
          textAlign "center"
          fillStyle "#555"
          fillText("(" <> Text.pack (show w') <> "px wide)", x, y + 40)
  
  example_1_8_7 EC{ecCanvas = canvas} = do
          let w = width canvas
          font "lighter 16pt Calibri"
          fillStyle "#000"
          let maxWidth = w / 3
          wrapText 0 (Text.words message') ((w - maxWidth) / 2) 60 maxWidth 25
      where
  
          message' = "All the world's a stage, and all the men and women merely players. " <>
                    "They have their exits and their entrances; And one man in his time plays many parts."
  
          wrapText _  []   _ _ _        _          = return ()
          wrapText wc text x y maxWidth lineHeight = do
               TextMetrics testWidth <- measureText $ Text.unwords $ take (wc+1) $ text
               if (testWidth > maxWidth && wc > 0) || length text <= wc
               then do fillText(Text.unwords $ take wc $ text,x,y)
                       wrapText 0      (drop wc text) x (y + lineHeight) maxWidth lineHeight
               else do wrapText (wc+1) text           x y                maxWidth lineHeight
  
  
  example_2_1_1 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas
          let rectWidth = 150;
          let rectHeight = 75;
          translate(w / 2, h / 2);
          fillStyle "blue";
          fillRect(rectWidth / (-2), rectHeight / (-2), rectWidth, rectHeight);
  
  example_2_2_1 _ = do
          rect(188, 40, 200, 100);
          fillStyle "red";
          shadowColor "#999";
          shadowBlur 20;
          shadowOffsetX 15;
          shadowOffsetY 15;
          fill()
  
  example_2_2_2 _ = do
        -- draw blue rectangle
        beginPath();
        rect(200, 20, 100, 100);
        fillStyle "blue";
        fill();
  
        -- draw transparent red circle
        globalAlpha 0.5;
        beginPath();
        arc(320, 120, 60, 0, 2 * pi, False);
        fillStyle "red";
        fill();
  
  example_2_2_3 EC{ecCanvas = canvas} = do
        let (w,h) = size canvas
        let x = w / 2;
        let y = h / 2;
        let radius = 75;
        let offset = 50;
  
        {-
         * save() allows us to save the canvas context before
         * defining the clipping region so that we can return
         * to the default state later on
         -}
        save();
        beginPath();
        arc(x, y, radius, 0, 2 * pi, False);
        clip();
  
        -- draw blue circle inside clipping region
        beginPath();
        arc(x - offset, y - offset, radius, 0, 2 * pi, False);
        fillStyle "blue";
        fill();
  
        -- draw yellow circle inside clipping region
        beginPath();
        arc(x + offset, y, radius, 0, 2 * pi, False);
        fillStyle "yellow";
        fill();
  
        -- draw red circle inside clipping region
        beginPath();
        arc(x, y + offset, radius, 0, 2 * pi, False);
        fillStyle "red";
        fill();
  
        {-
         * restore() restores the canvas context to its original state
         * before we defined the clipping region
         -}
        restore();
        beginPath();
        arc(x, y, radius, 0, 2 * pi, False);
        lineWidth 10;
        strokeStyle "blue";
        stroke();
  
  example_2_2_4 EC{ecCanvas = canvas} = do
          let (w,h) = size canvas :: (Double, Double)
          tempCanvas <- newCanvas (round w,round h)
          console_log tempCanvas
          let (w',h') = size tempCanvas
          console_log $ Text.pack $ show $ (w',h')
  
          sync
  
          let squareWidth = 55;
          let circleRadius = 35;
          let shapeOffset = 50;
          -- let operationOffset = 150;
  
          let compss =
               [["source-atop", "source-in", "source-out", "source-over"]
               ,["destination-atop","destination-in","destination-out","destination-over"]
               ,["lighter","darker","xor","copy"]
               ]
  
          -- translate context to add 10px padding
          translate(10, 10);
  
  
          sequence_ [
               do
  
                  -- clear temp context
                  with tempCanvas $ do
                          save();
  
                          clearRect(0, 0, w', h');
                          -- draw rectangle (destination)
                          beginPath();
                          rect(0, 0, squareWidth, squareWidth);
                          fillStyle "blue";
                          fill();
  
                          -- set global composite
                          globalCompositeOperation thisOperation;
  
                          -- draw circle (source)
                          beginPath();
                          arc(shapeOffset, shapeOffset, circleRadius, 0, 2 * pi, False);
                          fillStyle "red";
                          fill();
  
                          restore();
  
                          font "10pt Verdana";
                          fillStyle "black";
                          fillText(thisOperation, 0, squareWidth + 45);
  
                  drawImage(tempCanvas, [x * 125, y * 125]);
  
  
                | (comps,y)         <- compss `zip` [0..]
                , (thisOperation,x) <- comps  `zip` [0..]
                ]
  
  example_2_3_4, example_2_3_5 :: ExampleContext -> IO ()
  
  example_2_3_4 EC{ecCanvas = canvas} = do
     url <- send canvas $ do
          beginPath();
          moveTo(170, 80);
          bezierCurveTo(130, 100, 130, 150, 230, 150);
          bezierCurveTo(250, 180, 320, 180, 340, 150);
          bezierCurveTo(420, 150, 420, 120, 390, 100);
          bezierCurveTo(430, 40, 370, 30, 340, 50);
          bezierCurveTo(320, 5, 250, 20, 250, 50);
          bezierCurveTo(200, 5, 150, 20, 170, 80);
        -- complete custom shape
          closePath();
          lineWidth 5;
          strokeStyle "blue";
          stroke();
          toDataURL();
  
     send canvas $ do
          font "18pt Calibri"
          fillText(Text.pack $ show $ Text.take 50 $ url, 10, 300)
  
  example_2_3_5 EC{ecCanvas = canvas} = do
     fileName <- getDataFileName "static/data/dataURL.txt"
     url <- Text.IO.readFile fileName
     send canvas $ do
             img <- newImage (URL url)
             drawImage (img,[0,0])
  
  -- example_last :: Canvas ()
  -- example_last = do
  --         todo  -- marker for the scanning sof the examples
  
  ---------------------------------------------------------------------------
  
  -- todo :: Canvas ()
  -- todo = do
  --         font "40pt Calibri"
  --         fillText("(TODO)", 150, 100)
  
  -- Small "watermark-like text in the bottom corner"
  message :: DeviceContext -> Text -> Canvas ()
  message canvas msg = do
          save()
          let h = height canvas
          font "30pt Calibri"
          textAlign "left"
          fillStyle "#8090a0"
          fillText(msg, 10, h - 10)
          restore()
  
  size :: (Image image, Num a, Num b) => image -> (a, b)
  size image = (width image, height image)
  