I am currently redesigning a piece of legacy wxHaskell using the reactive-banana and reactive-banana-wx packages. However, in order to avoid dynamic network construction (where I ran into a thread block on an MVar), I now mimic this by preconstructing a fixed set of wxHaskell widgets of which I set visibility as necessary. Visibility is set by the sink
function taking a Behavior
. However, wxHaskell requires that after all these widgets have been appropriately modified via sink
, a subsequent change of the layout of the panel holding these widgets is required. That would mean that sink
-ing actually should be part of a network, so it is an event which can be triggered and waited upon for a layout change. As it currently is, a sink
takes you 'out' of the event network, it is not possible to trigger an event after the sink
action is completed. I did try to adapt sink
to something like this:
sink' :: Frameworks t =>
w -> [Prop' t w] -> Moment t (Event t ())
sink' widget props = do
es <- mapM sink1 props
return $ unions es
where
sink1 (attr :== b) = do
x <- initial b
liftIOLater $ set widget [attr := x]
e <- changes b
return $ (\x -> unsafePerformIO $ set widget [attr := x]) <$> e
However, the unsafePerformIO
did not get executed. How can the desired behavior be achieved, i.e. allow a (wxHaskell) IO to be waited on by means of an Event
?
Basically, it appears that you want to ensure that the IO actions in reactimate
are executed in a certain order? Namely, you want to make sure that the layout is set after the widget properties have been set.
There are several methods to specify order:
union
, unionWith
and/or collect
to determine the order of simultaneous events.reactimate
are executed in the order they appear in the Moment
monad. (Though strictly speaking, this is no longer true when you use the observeE
combinator from dynamic event switching.)In your particular case, these ideas can be applied as follows.
For 1, you can make an event that contains an IO action and combine it with the layout later
sink' :: Frameworks t =>
w -> [Prop' t w] -> Moment t (Event t (IO ()))
sink' widget props = do
es <- mapM sink1 props
return $ foldr1 (unionWith (>>)) es
where
sink1 (attr :== b) = do
x <- initial b
liftIOLater $ set widget [attr := x]
e <- changes b
return $ (\x -> set widget [attr := x]) <$> e
For 2, you can simply use the ordinary sink
functions and just make sure that the layout is set last.
do
sink widget1 [ visible :== bBool ]
sink window1 [ layout :== bLayout ]
The ordering of the sink
functions in the monad guarantees that the layout is set last.
Also note that since reactive-banana 0.7, you can use dynamic event switching to model a variable set of widgets. See the BarTab.hs example for a demonstration. This example also sets the layout.
You indicated that you run into an MVar block when you use dynamic networks. This is probably because you create widgets in a way that triggers another event in the network. Unfortunately, this is semantically unsound — it corresponds to values depending on future versions of themselves — and the program responds by plunging into rock bottom.
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