Page
Library
Module
Module type
Parameter
Class
Class type
Source
If you already followed the Hello world tutorial, you know how to display widgets. But what about user interaction?
In this tutorial, in the purest tradition of GUI tutorials, we will create a small app displaying the number of requested cookies; and the user can request more by clicking a button.
We need a label with the word "Cookies", another one displaying the number of cookies, and a button displaying the text "Click for more". So we have 3 widgets. Let's place them horizontally in a layout, using the function Layout.flat_of_w.
flat_of_w (for: "flat of widgets") constructs a flat house from a list of widgets. Each widget will be installed in a room, and the house (of type Layout.t) is built by placing the rooms next to each other. Ok, so let's try this.
open Bogue
module W = Widget
let () =
let label = W.label "Cookies:" in
let count = W.label "0" in
let button = W.button "Click for more" in
Layout.flat_of_w ~name:"Counter tutorial"
~align:Draw.Center [label; count; button]
|> Bogue.of_layout
|> Bogue.runNotice how we aliased the Widget module by W. This saves space and time, and improves readability.
flat_of_w. The ~name will be displayed as the window name by your window manager. The ~align parameter ensures that the 3 widgets are vertically centered (the default would by to align them by their tops. Try removing this option to see the difference.) Here is what we get:

Of course, we didn't code any logic or user interaction. So this is just a dumb GUI that does nothing!
When designing a GUI, it's often useful to do the opposite: try to think about the logic, without worrying about display. Well, in our case the logic is really minimal:
We need a mutable variable for the number of cookies:
let x = ref 0and a function to increase this:
let add_cookie () = incr xThat's about it for the pure logic. Of course, in a real app we would do something with x, for instance order the correct amount of chocolate chips.
It remains to give life to our GUI inhabitants! The button widget should be able to talk to the count widget. How do we do this?
There are two aspects:
In our case, the count widget must be updated when x changes. Let's write a generic function for this:
let update c n =
W.set_text c (string_of_int n)update will be called with arguments count !x. But it could be applied to any type of widget for which the function W.set_text makes sense. If we wanted to restrict to widgets of "label" type, we could have done:let _update_label c n =
Label.set (W.get_label c) (string_of_int n)Finally, concerning user interaction, well, this is actually easy. The function Widget.button has an optional parameter ~action which executes the function action : bool -> unit each time the button is activated by the user.
Here is our complete GUI:
let () =
let label = W.label "Cookies:" in
let count = W.label "0 " in
let action _ = add_cookie (); update count !x in
let button = W.button ~action "Click for more" in
Layout.flat_of_w ~name:"Counter tutorial"
~align:Draw.Center [label; count; button]
|> Bogue.of_layout
|> Bogue.run
How cool is that! ;)