# 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.