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, our tree grows top-down, like family trees.) See the "Layouts" tutorial for more details.
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's 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
In Bogue, there are mainly two types of objects: widgets and layouts. Widgets are small graphics elements (buttons, images, etc.) and they can be combined into a Layout. Roughly speaking:
- widget = content
- layout = container.
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
Why is this function called "resident"? Well, if you browse Bogue's API, you will notice that Bogue uses a "housing" metaphor: a GUI is a big house with inhabitants (the widgets) living in various rooms (the layouts).
For this example, the layout we've just created 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 layout can contain only one widget. But, the trick is that, in Bogue, an element of type Layout.t
can also contain a list of layouts; in this case we often call it a "house", since it contains a number of "rooms". Let's do this.
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
do? 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.