You must have missed the bit about "congenitally lazy" :-)<br><br>Username requested ...<br><br>cheers,<br>Fraser.<br><br><br><div class="gmail_quote">On Mon, Feb 16, 2009 at 8:10 PM, Lennart Augustsson <span dir="ltr"><<a href="mailto:lennart@augustsson.net">lennart@augustsson.net</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">Put it on hackage!<br>
<br>
2009/2/16 Fraser Wilson <<a href="mailto:blancolioni@gmail.com">blancolioni@gmail.com</a>>:<br>
<div><div></div><div class="Wj3C7c">> Since I'm congenitally lazy, and writing a GUI by hand in the IO monad is<br>
> ... not what I expect from a beautiful program, and because what I often<br>
> need is a GUI that manipulates a state, and because I don't understand<br>
> arrows, and having been intrigued by a recent cafe thread, I threw together<br>
> a prototype GUI library with the following features:<br>
><br>
> - the GUI is defined on three levels: gadgets, widgets and styles<br>
> - gadgets are functions on a state<br>
> - widgets are data structures which define the layout<br>
> - styles are ways to modify the appearance of widgets<br>
><br>
> The following quick example shows a text box and a button. Clicking on the<br>
> button reverses the text in the text box.<br>
><br>
>> module Main where<br>
><br>
>> import Barrie<br>
><br>
>> demoWidget :: Widget<br>
>> demoWidget = vbox [ui "demo entry" textBox,<br>
>> ui "demo command" (labelButton "click me")]<br>
><br>
>> type DemoState = String<br>
><br>
>> type DemoGadget = Gadget DemoState<br>
><br>
>> demoGUI :: DemoGadget<br>
>> demoGUI = localG "demo gui" [editorG "demo entry" id const,<br>
>> commandG "demo command" reverse]<br>
><br>
>> main = gtkMain demoGUI demoWidget "Hello, world"<br>
><br>
> Two gadgets are used:<br>
><br>
> editorG :: String -> (a -> b) -> (b -> a -> a) -> Gadget a<br>
> commandG :: String -> (a -> a) -> Gadget a<br>
><br>
> The editor gadget can show a value from a state, and update a state with a<br>
> value. The command gadget can transform a state to a new state. gtkMain<br>
> connects the gadgets to a widget, which specifies layout using the vbox,<br>
> attaching the editor gadget to a text box, and the command gadget to a<br>
> button.<br>
><br>
> Well, that's all pretty trivial. The key thing for me was that I can easily<br>
> slap a GUI onto the the front of a class of applications, which happen to be<br>
> the sort of applications I've been writing lately. Also, arbitrary parts of<br>
> the GUI can respond to things that happen miles away, without really having<br>
> to worry about it too much. In barrie-0.1 and 0.2, which used stream-based<br>
> approaches, the problem of getting state from one end of the application to<br>
> the other was non-trivial.<br>
><br>
> I'll sketch another quick example:<br>
><br>
>> data BridgeGame = ...<br>
><br>
> And a bunch of things you can do with the state:<br>
><br>
>> makeBid :: Bid -> BridgeGame -> BridgeGame<br>
>> playCard :: Card -> BridgeGame -> BridgeGame<br>
><br>
> For bidding, each bid is represented by a gadget:<br>
><br>
>> bidG :: Bid -> Gadget BridgeGame<br>
>> bidG bid = enabled (bidOK bid) $ CommandG (show bid) (makeBid bid)<br>
><br>
> 'enabled' switches the gadget on if its first argument returns true when<br>
> applied to the current state. However, the decision about what to do with a<br>
> disabled gadget is made by its corresponding widget.<br>
><br>
> We get one button for each bid:<br>
><br>
>> biddingG :: Gadget BridgeGame<br>
>> biddingG = localG "bidding" (map bidG allBids)<br>
><br>
> And they can be displayed in any old order using a widget:<br>
><br>
>> biddingW :: Widget<br>
>> biddingW = vbox (map suitBids [Club, Diamond, Heart, Spade] ++ [ntBids])<br>
>> where suitBids suit = hbox $ map (bidButton . flip Bid suit) [1 .. 7]<br>
>> ntBids = hbox $ map (bidButton . NT) [1 .. 7]<br>
>> bidButton bid = ui (show bid) $ labelButton (show bid)<br>
><br>
> (You're right, double, redouble and pass are not represented. They make the<br>
> lines too long).<br>
><br>
> Screenshot here: <a href="http://thewhitelion.org/images/4D.png" target="_blank">http://thewhitelion.org/images/4D.png</a><br>
><br>
> I've just bid four diamonds, so everything lower than that is automatically<br>
> disabled.<br>
><br>
> Currently, Barrie implements buttons, text boxes, labels,<br>
> vertical/horizontal layout, single-column lists and drop lists. It current<br>
> uses Gtk2hs for rendering, but it's GUI-agnostic (in fact, the first<br>
> renderer was putStrLn/getLine).<br>
><br>
> You can have a look by using darcs:<br>
> darcs get <a href="http://thewhitelion.org/darcs/barrie" target="_blank">http://thewhitelion.org/darcs/barrie</a><br>
><br>
> Or get the tarball at<br>
> <a href="http://thewhitelion.org/haskell/barrie-0.3.0-src.tar.gz" target="_blank">http://thewhitelion.org/haskell/barrie-0.3.0-src.tar.gz</a><br>
><br>
> One note: this is not intended to be a theoretically sound approach, merely<br>
> a way of getting something done quickly. I would expect it to be most<br>
> useful in putting a GUI front-end onto an existing application, in<br>
> particular, an application that is driven by user actions which update a<br>
> state; e.g. a calculator, a bridge game, a 4th edition D&D character creator<br>
> (but that leads to a critical mass of nerdiness, so it's off the table for<br>
> now)<br>
><br>
> cheers,<br>
> Fraser.<br>
><br>
> --<br>
> <a href="http://thewhitelion.org/mysister" target="_blank">http://thewhitelion.org/mysister</a><br>
><br>
</div></div>> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> <a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
> <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
><br>
><br>
</blockquote></div><br><br clear="all"><br>-- <br><a href="http://thewhitelion.org/mysister">http://thewhitelion.org/mysister</a><br>