
From: Chris Smith
On Fri, 2011-07-08 at 08:08 +0200, Heinrich Apfelmus wrote:
Do you know any *small GUI programs* that you would *like* to see *implemented with Functional Reactive Programming?*
This isn't really a specific application, but what I'd like to see most from FRP is an example of something that involves moving between windows and dialog boxes. All of the GUI-based FRP examples I've seen so far involve interactions in a specific GUI layout. It's unclear to me how FRP extends into a situation like:
- There's a starting window showing several options for what to do - When the user chooses an option, that window closes, and a new one opens with that activity. - In response to some actions, dialog boxes appear with their own interactions.
It's not clear to me if anyone in FRP has an idea of how stuff like this fits in. Is there some FRP trick to handle this declaratively? Or would you just say each move to a new window ends or pauses one network of events and behaviors, and starts a new one?
I can show you how I've been handling this with reactive-banana and gtk2hs. As a small example, the "File->Open" command is meant to open a new project. The codez:
maybeEvent0 :: Typeable a => Action -> IO (Maybe a) -> NetworkDescription (Event a) maybeEvent0 act ops = do (addHandler, runHandlers) <- liftIO newAddHandler liftIO $ on act actionActivated $ ops >>= maybe (return ()) runHandlers fromAddHandler addHandler
-- | Load a saved project file openHandler :: ActionGroup -> Window -> NetworkDescription (Event (String, HTree)) openHandler actGrp _win = do act <- liftIO openAction liftIO $ actionGroupAddActionWithAccel actGrp act Nothing maybeEvent0 act openProjectDialog
openProjectDialog :: IO (Maybe (String, HTree)) openProjectDialog = do fc <- fileChooserDialogNew (Just "Select a project file") Nothing FileChooserActionOpen [] fileChooserSetSelectMultiple fc False dialogAddButton fc stockCancel ResponseCancel dialogAddButton fc stockOk ResponseOk widgetShowAll fc resp <- dialogRun fc case resp of ResponseOk -> runMaybeT $ do fp <- MaybeT $ fileChooserGetFilename fc liftIO $ widgetDestroy fc (fp, ) <$> liftIO (readProject fp) _ -> widgetDestroy fc >> return Nothing
The `openHandler` function connects the Gtk signal to the reactive-banana framework. This uses the helper `maybeEvent0`, which filters an IO action and triggers a reactive-banana Event when that IO action actually returns a value. I've been using this pattern for most of my modal dialogs, and I think it works very well. The one dialog I haven't used it for is the starting window, which is straight-line imperative code. I don't yet have any non-modal dialogs or alternate windows, but there shouldn't be a problem. There's nothing special about which window a widget is in; it can be connected to the FRP framework just like a widget in the main window. John L.