package bogue-tutorials
Bogue tutorial — Hello world.
In this tutorial we will learn how to open a graphical window displaying a short text, like "Hello world". We then take advantage of this to familiarise with basic Bogue concepts.
Hello world
Let's start right ahead with the "minimal code" mentionned in Bogue's documentation:
open Bogue
let () =
Widget.label "Hello world"
|> Layout.resident
|> Bogue.of_layout
|> Bogue.run
We can copy this code in an OCaml toplevel and execute it; see here for general instructions.
A small window should pop up like this:
So, how does this work? Let go through this again line by line.
First, instead of using the convenient |>
operator, let's give names to the various steps; we have the following equivalent code:
let () =
let widget = Widget.label "Hello world" in
let layout = Layout.resident widget in
let board = Bogue.of_layout layout in
Bogue.run board
Bogue uses the "housing" metaphor: a GUI is a big house with inhabitants living in various rooms, (and potentially communicating with each other).
The inhabitants are the "widgets". The rooms are the "layouts". There are several kinds of widgets; here we create only one widget, of label
type:
let widget = Widget.label "Hello world" in
and we install it in a layout, as in single resident:
let layout = Layout.resident widget in
Finally, this layout is the only "room" in our house, so we use it to create our "board" (which is our complete GUI):
let board = Bogue.of_layout layout in
This board can be seen as our application, we run it using:
Bogue.run board
Simple, isn't it?
More space
Well, of course there is more to it. For instance, you may find that the text label is a bit tight and needs more space around it. (In other words, the resident needs a larger room ;) )
So let's have a look at the documentation for the function Layout.resident:
val resident :
?name:string -> ?x:int -> ?y:int -> ?w:int -> ?h:int ->
?background:background ->
?draggable:bool ->
?canvas:Draw.canvas ->
?keyboard_focus:bool -> Widget.t -> t
We spot the optional parameters ?w
and ?h
which should set the desired widht and height of our layout. Let's try:
let () =
Widget.label "Hello world"
|> Layout.resident ~w:300 ~h:150
|> Bogue.of_layout
|> Bogue.run
Several widgets in a layout
Great, but the text feels alone... Suppose we want to display an image below our label.
Can we fit several residents in a room? Well, not really. Strictly speaking, a room can contain only one resident (widget). But, the trick is that a layout can in fact contain several rooms. Thus, an element of type Layout.t
can either be:
- a true "room" (containing a single resident), or
- a "house" containing several rooms.
To summarize, in Bogue, the complete GUI is simply a tree of layouts, and the leaves contain a widget.
The trunk of the tree (our main house, if you wish), will correspond to the layout associated with the window of the GUI. In Bogue we often call this special layout the "top layout", or "top house". (Yes, this may sound weird: our tree grows top-down...)
So, we want to display an image below the label. Our label is a widget:
let hello = Widget.label "Hello world"
An image is also a widget:
let image = Widget.image "bogue-icon.png"
Now, to put one on top of the other, we use the function Layout.tower_of_w
(short for "tower of widget") which constructs a "tower":
let () =
let hello = Widget.label "Hello world" in
let image = Widget.image "bogue-icon.png" in
let layout = Layout.tower_of_w [hello; image] in
let board = Bogue.of_layout layout in
Bogue.run board
This opens a window like this:
What exactly does this function Layout.tower_of_w
? It takes a list of widgets, and for each one, installs it in a room, as a resident. Then it constructs a new layout by piling up the rooms vertically.
The doc for tower_of_w
shows interesting options. For instance, to center everything horizontally, use ~align:Draw.Center
:
Exercise: vertical text
What about applying what we've just learned to write "Hello world" vertically?
Solution: Let's use Layout.tower_of_w
to build a "tower" of letters.
let vertical text =
Array.init (String.length text) (String.get text)
|> Array.to_list
|> List.map (String.make 1)
|> List.map Widget.label
|> Layout.tower_of_w
let () =
vertical "Hello world"
|> Bogue.of_layout
|> Bogue.run
Et voila !
We now know enough Bogue to play with layouts full of text and image. But, of course, a crucial part of a GUI is missing: user interaction. This will be the goal of the "counter" tutorial.