{-# OPTIONS_GHC -fno-warn-unused-imports #-}

module Graphics.QML.DataModel.Tutorial 
  ( -- * Haskell side
    -- $hsk

    -- * QML side
    -- $qml
  ) where

import Graphics.QML.DataModel
import Graphics.QML.DataModel.TH
import Graphics.QML
import GHC.Generics

{- $hsk
Any data type with a single constructor and marshallable fields can be used in a QML data model. For example:

@
  data Row = Row {foo :: Int, bar :: String, baz :: Double}
    deriving Generic
@

To use the data type in a model, first you need to declare the necessary instances.
All the necessary classes have default implementations using 'Generic'.
To further automate the process, there's a Template Haskell macro that declares them all:

@ 
 dataModelInstances Row
@ 

If you don't want to use TH, you can declare them manually:

@
 instance QtTable      Row
 instance CountFields  Row
 instance SetupColumns Row
@

Finally, in your 'main' function, register the data model as a QML type, set up the delegate and its callbacks, and provide a way for QML to access it.

@
setTVarCallbacks 
  :: QtTable a 
  => DataModel a 
  -> TVar [a]
  -> IO ()
setTVarCallbacks model tv = do
  setRowCountCallback model $      length <$> readTVarIO tv
  setDataCallback     model $ \i -> (!!i) <$> readTVarIO tv

main = do
    registerHaskellModel   

    storage <- newTVarIO [Row 1 "a" 3.0, Row 2 "b" 4.2]
    model <- setupDataModel
    setTVarCallbacks model storage

    skey <- newSignalKey

    toplevel'class <- newClass 
       [ defPropertyConst' "haskellModelDelegate" $ \_ -> return (delegate model)
       , defPropertyConst' "self" return 
       , defSignal "updateTable" skey 
       ]
    toplevel'obj <- newObject toplevel'class ()

    runEngineLoop defaultEngineConfig 
      { initialDocument = "path//to//your//main.qml"
      , contextObject = Just $ anyObjRef toplevel'obj
      }
@

-}


{- $qml
Using the model in QML is simple as that:

@
  HaskellModel {
    id: haskellModel;
    delegate: haskellModelDelegate;
  }

  TableView {
    id: hsView;
    model: haskellModel;

    TableViewColumn {
      title: \"A\";
      role: "baz";
    }

    TableViewColumn {
      title: \"B\";
      role: "foo";
    }
  }
@

Record fields become roles, and you can use them in any order any with any names you like.
Views other than TableView can be used too, of course.

You will also need to reset the model every time you make changes from the Haskell side.
This can be done by connecting the modelReset method to a signal fired from Haskell:

@
  Connections {
    target: self;
    onUpdateTable: hsView.model.modelReset()  
  }
@

-}