I am hunting for a library to write a GUI on top of GLFW and OpenGL. I'm doing this because I am dissatisfied with the common UI library bindings which I feel are too imperative, and I would also like tight control of the look and feel of my UIs. I'd like a declarative approach to defining UI's. I am experimenting with reactive-banana (and temporarily reactive-banana-wx) to see if it meets my needs. I have a problem with defining recursive widgets. Here's my simplest test case:
The first and third widget have a recursive relationship. The first widget is intuitively a stepper
of a union
of events fed from the two buttons. However, the reset button is an fmap
of the counter, and then the event stream relies on the reset button! What is to be done?
Beyond this question I have a concern about event handling: Since I want to handle device input and input focus within my code instead of relying on a framework, I see difficulties ahead in correctly dispatching events in a scalable way. Ideally I would define a data
that encapsulates the hierarchical structure of a widget, a way to install event callbacks between the elements, and then write a function that traverses that data structure in order to define device input processing and graphical output. I am not sure how to take an event stream and split it as easily as event streams can be merged.
Recursion is allowed, as long as it is mutual recursion between a Behavior
and an Event
. The nice thing about Behavior
s is that sampling them at the time of an update will return the old value.
For instance, your example can be expressed as follows
eClick1, eClick2 :: Event t ()
bCounter :: Behavior t Int
bCounter = accumB 0 $ mconcat [eIncrement, eReset]
eIncrement = (+1) <$ eClick1
eReset = (const 0) <$ whenE ((> 0) <$> bCounter) eClick2
See also the question "Can reactive-banana handle cycles in the network?"
As for your second question, you seem to be looking for the function filterE
and its cousins filterApply
and whenE
?
As for your overall goal, I think it is quite ambitious. From what little experience I have gained so far, it seems to me that binding to an existing framework feels quite different from making an "clean-state" framework in FRP. Most likely, there are still some undiscovered (but exciting!) abstractions lurking there. I once started to write an application called BlackBoard that contains a nice abstraction about time-varying drawings.
However, if you care more about the result rather than the adventure, I would recommend a conservative approach: create the GUI toolkit in an imperative style and hook reactive-banana on top of that to get the benefits of FRP.
In case you just wish for any GUI, I am currently focussing on the web browser as a GUI. Here some preliminary experiments with Ji. The main benefit over wxHaskell is that it's a lot easier to get up and running and any API design efforts will benefit a very wide audience.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With