# reflex-gi-gtk
This package provides the necessary plumbing to write reactive GUI
applications using GTK3+ (based on
[gi-gtk](https://hackage.haskell.org/package/gi-gtk/)) and
[reflex](https://hackage.haskell.org/package/reflex/).
While this packes should make working with gi-gtk and reflex together
much easier than using them together without any kind of glue code, it
doesn't provide a lot of abstraction on top of either GTK or
reflex. People familiar with both gi-gtk and reflex separately should
have no trouble using reflex-gi-gtk successfully to build awesome
applications.
## Installation
The package can be compiled with [stack](https://haskellstack.org/)
using the shipped `stack.yaml` as follows:
```Shell
$ stack install
```
The build process has mostly been tested using stack, but it should
also work using [cabal-install](https://www.haskell.org/cabal/) or
other standard `Cabal`-based package managers.
## Quick start
To start writing your reactive GUI application using reflex-gi-gtk, you will farst want to start the reactive part of your application using `runReflexGtk`, something like this:
```Haskell
{-# LANGUAGE OverloadedStrings, OverloadedLabels, FlexibleContexts #-}
import Control.Applicative (liftA2)
import GI.Gtk hiding (main)
import Reflex.GI.Gtk
import System.Environment
import System.Exit
main :: IO ()
main = do
argv <- (:) <$> getProgName <*> getArgs
Just gtkApplication <- applicationNew (Just "org.example.MyAwesomeApp") []
rc <- runReflexGtk gtkApplication (Just argv) $ myReactiveCode gtkApplication
case rc of
0 -> exitSuccess
n -> exitWith $ ExitFailure $ fromIntegral n
```
Inside the call to `runReflexGtk` you can assume that GTK has been
initialized and start creating GTK widgets:
```Haskell
myReactiveCode :: (MonadReflexGtk t m) => Application -> m ()
myReactiveCode gtkApplication = do
window <- runGtk $ applicationWindowNew gtkApplication
box <- runGtk $ boxNew OrientationVertical 0
containerAdd window box
input1 <- runGtk entryNew
input2 <- runGtk entryNew
output <- runGtk $ labelNew Nothing
runGtk $ boxPackStart box input1 False False 0
runGtk $ boxPackStart box input2 False False 0
runGtk $ boxPackStart box output False False 0
```
Note that we use `runGtk` to execute GTK functions instead of relying
on `liftIO`. This is because GTK functions are required to be run with
the correct thread local context. reflex-gi-gtk internally uses
multiple threads in a way that makes it hard to predict in which
thread a given piece of code will run. `runGtk` will ensure that the
lifted `IO` action is always run in the appropriate threading context
for GTK functions.
You can also start obtaining reactive inputs from widget signals:
```Haskell
text1 <- dynamicOnSignal "" input1 #changed $ \fire -> labelGetText input1 >>= fire
text2 <- dynamicOnAttribute input2 #text
```
This creates to `Dynamic`s containing texts. `text1` is constructed
based on the `#changed` event of the first input `Entry` while `text2`
is bound to the attribute `#text` of `input2`, but overall the effect
will be the same. Both `text1` and `text2` will always contain the
text entered into their respective input `Entry`.
Once we have obtained reactive inputs, we can of course manipulate
them just as any other reactive values:
```Haskell
let combinedText = liftA2 (<>) text1 text2
```
In the end, we can also render dynamic values to attributes of GTK
widgets:
```Haskell
sink output [#label :== combinedText]
```
Don't forget to call `widgetShowAll` on your window at an appropriate
time:
```Haskell
_ <- gtkApplication `on` #activate $ widgetShowAll window
pure ()
```
When you compile and run your program above, you should see your two
input boxes and the appropriate, dynamically updated output label.
This is of course a very basic example. For more information you can
look at a more elaborate example in the `example` directory or at the
haddock documentation on hackage.