{-# 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() } @ -}