Windows GUI

I was looking for an easy to use GUI library for Haskell that worked on Windows. I’m sorry to say but the whole experience was very frustrating. Various native bindings are a nightmare to setup and more often than not, just decide not to work.

So naturally, I decided to write my own solution.

How it works

One part of the library is the .NET component written in F#. It’s an executable that manipulates the controls, handles events and communicates over standard IO. The Haskell component starts that host process and maps Haskell code into appropriate messages over std. IO, as well as mapping responses and events back to the Haskell world.

Example usage

The main idea was that the library should feel like a native Haskell one. Here’s a code example.

main :: IO ()
main = do
    startHost False
    form <- newForm
    pb   <- newPictureBox
    controls form >>= add pb
    bmp  <- newBitmap 500 500
    image pb #= bmp
    red  <- newSolidBrush $ color 255 0 0 255
    graphicsFromImage bmp >>= drawString "test" (font "Consolas" 12) red (pointF 0 0)
    refresh form

Result

Interop

The interop layer is actually pretty feature rich. It handles marshaling of data on both ends. Simple objects (like Point, Size…) get serialized to strings while more complex ones (like controls) are kept on the .NET end and get assigned IDs which are then used by the Haskell side to refer to them.

In the above example, the newX functions create objects on the .NET side. The controls function is the analog of the Controls property that returns a collection of child controls. This collection is also an object that needs to be marshaled, and it does. Then the add function is called on it passing in the pb object. The Haskell code looks pretty much how it would look in C#/F#.

In this example you can see that using GDI functions works without a problem.

It’s important to note that the bindings are nowhere near complete at this point. Only a couple of functions and classes are supported. This isn’t because it’s a lot of work to bind things. It just wasn’t a priority to make a binding generator.

I’ve tried to mirror the OOP hierarchy as close as possible. In the example I’m creating a new Bitmap object but I’m assigning it to a property that expects an Image. This works because of the subclassing.

Events

Events are supported and (as it turns out) actually more typesafe than their .NET counterparts.

main :: IO ()
main = do
    startHost False
    form <- newForm
    btn  <- newButton
    controls form >>= add btn
    click btn >>= handle (\_ _ -> putStrLn "Test")

Here the first argument to the event handler isn’t just some object. It’s a Button.

Performance

…was not a concern. This doesn’t mean that the bindings are slow, but serializing everything to strings and piping over std. IO can’t be too efficient. However, it really should be workable for pretty much everything where you just need a UI (as opposed to a complicated rendering system). The serialization is very much modularized so if there’s actual need, it can always be replaced with a more efficient system.

Technicalities

I’ve spend a decent amount of effort adjusting the implementation so it’s as convenient as possible to use.

For example,

main :: IO ()
main = do
    form <- newForm
    btn  <- newButton
    controls form >>= add btn
    text btn #= "Test"
    test <- text btn

the text property the first time it’s used behaves like a setter (since #= can be used with it), while the second time behaves like an IO String and is bound to a name.

The bindings have support for get-only properties.

Take a look at Controls.hs to see what the bindings look like. They basically just connect the untyped, stringy layer to meaningful types.

The code as it looks at the time of the writing is available here.