A Comprehensive
Pure-Haskell
Native Desktop
Reflex-based
Functional Reactive Programming
GUI Framework
+ Example Application


Project Reports

Project Plan

What is an Interim Report? - HKWJ Tax Law

Interim Report

Business people in an office building — Stock Photo © Rawpixel #52467683

Final Report

Exhibition Poster


Download Black, Background, Texture. Royalty-Free Stock ...

Let’s create a reactive button

buildMainElement :: ::
  forall t sig m.
  (HasRgxGui t sig m) =>
  ElementBuild t m
buildMainElement :: env = mdo
  let font = "Sans Serif 24"

  -- Accumulate number of clicks
  numClicks :: Dynamic t Int <-
    foldDyn ($) 0 (btn.clicked $> (+ 1))

  -- Create a text label
  let
    labelText = numClicks <&> \numClicks ->
      "Click me! " <> show numClicks <> " click(s)"
  labelModel <- newOnelineModel font labelText

  -- Create a button
  (btn, btnModel) <- newButton Prelude.id labelModel

  -- Instantiate
  btnModel.build env

… then align the text label to the center

buildMainElement ::
  forall t sig m.
  (HasRgxGui t sig m) =>
  ElementBuild t m
buildMainElement env = mdo
  let font = "Sans Serif 24"

  -- Accumulate number of clicks
  numClicks :: Dynamic t Int <-
    foldDyn ($) 0 (btn.clicked $> (+ 1))

  -- Create a text label
  let
    labelText = numClicks <&> \numClicks ->
      "Click me! " <> show numClicks <> " click(s)"
  labelModel <- newOnelineModel font labelText

  -- Create a button
  (btn, btnModel) <-
    newButton Prelude.id
      $ positionSimple alignCenterXY
      $ labelModel

  -- Instantiate
  btnModel.build env

… and add some margins around the button

buildMainElement ::
  forall t sig m.
  (HasRgxGui t sig m) =>
  ElementBuild t m
buildMainElement env = mdo
  let font = "Sans Serif 24"

  -- Accumulate number of clicks
  numClicks :: Dynamic t Int <-
    foldDyn ($) 0 (btn.clicked $> (+ 1))

  -- Create a text label
  let
    labelText =
      numClicks <&> \numClicks ->
        "Click me! " <> show numClicks <> " click(s)"
  labelModel <- newOnelineModel font labelText

  -- Create a button
  (btn, btnModel) <-
    newButton Prelude.id
      $ positionSimple alignCenterXY
      $ labelModel

  -- Add padding + a cyan background for empty spaces
  paddedModel <-
    pure
      $ backgroundSimple (Colour.opaque Colour.cyan)
      $ positionSimple (marginAll 32)
      $ btnModel

  -- Instantiate
  paddedModel.build env

… factorize the button as a “reusable widget”

# BEFORE

buildMainElement ::
  forall t sig m.
  (HasRgxGui t sig m) =>
  ElementBuild t m
buildMainElement env = mdo
  let font = "Sans Serif 24"

  -- Accumulate number of clicks
  numClicks :: Dynamic t Int <-
    foldDyn ($) 0 (btn.clicked $> (+ 1))

  -- Create a text label
  let
    labelText =
      numClicks <&> \numClicks ->
        "Click me! " <> show numClicks <> " click(s)"
  labelModel <- newOnelineModel font labelText

  -- Create a button
  (btn, btnModel) <-
    newButton Prelude.id
      $ positionSimple alignCenterXY
      $ labelModel

  -- Add padding + a cyan background for empty spaces
  paddedModel <-
    pure
      $ backgroundSimple (Colour.opaque Colour.cyan)
      $ positionSimple (marginAll 32)
      $ btnModel

  -- Instantiate
  paddedModel.build env
# AFTER

buildMainElement ::
  forall t sig m.
  (HasRgxGui t sig m) =>
  ElementBuild t m
buildMainElement env = do
  let font = "Sans Serif 24"

  let
    newMyButton :: T.Text -> m (Model t m WH)
    newMyButton txt = mdo
      -- Accumulate number of clicks
      numClicks :: Dynamic t Int <-
        foldDyn ($) 0 (btn.clicked $> (+ 1))

      -- Create a text label
      let
        labelText =
          numClicks <&> \numClicks ->
            txt <> show numClicks <> " click(s)"
      labelModel <- newOnelineModel font labelText

      -- Create a button
      (btn, btnModel) <-
        newButton Prelude.id
          $ positionSimple alignCenterXY
          $ labelModel

      pure btnModel

  -- Create a button
  btnModel <- newMyButton "Click me! "

  -- Add padding + a cyan background for empty spaces
  paddedModel <-
    pure
      $ backgroundSimple (Colour.opaque Colour.cyan)
      $ positionSimple (marginAll 32)
      $ btnModel

  -- Instantiate
  paddedModel.build env

… and now make 3 buttons stacked on top of each other

buildMainElement ::
  forall t sig m.
  (HasRgxGui t sig m) =>
  ElementBuild t m
buildMainElement env = do
  let font = "Sans Serif 24"

  let
    newMyButton :: T.Text -> m (Model t m WH)
    newMyButton txt = mdo
      -- Accumulate number of clicks
      numClicks :: Dynamic t Int <-
        foldDyn ($) 0 (btn.clicked $> (+ 1))

      -- Create a text label
      let
        labelText =
          numClicks <&> \numClicks ->
            txt <> show numClicks <> " click(s)"
      labelModel <- newOnelineModel font labelText

      -- Create a button
      (btn, btnModel) <-
        newButton Prelude.id
          $ positionSimple alignCenterXY
          $ labelModel

      pure btnModel

  -- Create a button
  btn1Model <- newMyButton "Click me! "
  btn2Model <- newMyButton "Me too! "
  btn3Model <- newMyButton "Me three! "

  -- Stack all buttons vertically with
  -- flexbox "flex" factors 1, 2, & 3.
  buttonsModel <-
    newLinearLayoutSimple
      (constDyn Axis2D.Y)
      [ Linear 1 <$> btn1Model
      , Linear 2 <$> btn2Model
      , Linear 3 <$> btn3Model
      ]

  -- Add padding + a cyan background for empty spaces
  paddedModel <-
    pure
      $ backgroundSimple (Colour.opaque Colour.cyan)
      $ positionSimple (marginAll 32)
      $ buttonsModel

  -- Instantiate
  paddedModel.build env

RGX offers much more.

RGX has many useful built-in widgets such as:

  • Multi-line paragraphs (+ mouse selection, multilingual support, text wrapping, etc., thanks for the library Pango)
  • Text fields (and you can input with your Input Method Editors)
  • Checkboxes
  • SVG icons
  • Image displays

You can also create new widgets and extend RGX just by writing pure-Haskell code and using the library Reflex!

RGXSyncthing Video Demo

(A partial replica of Syncthing’s Official Web UI)