Box Packing

The program we are to see implements a panel containing ten buttons labeled with digits from 0 to 9, inclusive. If a button is clicked, then the digit appearing in its label is printed out (onto the stdout channel). In terms of the layout of buttons, there four rows in the panel; the first three rows contain three buttons each and the last row contains only one button; the buttons are labeled with 1, 2, 3, 4, 5, 6, 7, 8, 9, and 0 when enumerated in row-major mode.

The following function button_create creates a button with a given label:

fun
button_create
(
  msg: SHR(string)
) : GtkButton1 = let
//
val res =
gtk_button_new_with_label ((gstring)msg)
//
fun f
(
  button: !GtkButton1, udata: gpointer
) : void = println! ($UN.cast{string}(udata))
//
val ((*void*)) = assertloc (ptrcast (res) > 0)
//
val id =
g_signal_connect
(
  res, (gsignal)"clicked", G_CALLBACK(f), $UN.cast{gpointer}(msg)
) (* end of [val] *)
//
in
  res
end // end of [button_create]

When clicked, the created button prints out the string contained in its label onto the stdout channel.

The following function row_create creates a horizontal box (H-box) of buttons:

fun row_create
(
  xs: list0(string)
) : GtkBox1 = let
//
fun loop
(
  box: !GtkBox1, xs: list0(string)
) : void =
  case+ xs of
  | nil0 () => ()
  | cons0 (x, xs) => let
      val btn = button_create (x)
      val () = gtk_box_pack_start (box, btn, GTRUE, GTRUE, (guint)0)
      val () = gtk_widget_show_unref (btn)
    in
      loop (box, xs)
    end // end of [cons0]
//
val hbox =
gtk_box_new
(
  GTK_ORIENTATION_HORIZONTAL, (gint)0
) (* end of [val] *)
val () = assertloc (ptrcast(hbox) > 0)
//
val () = loop (hbox, xs)
//
in
  hbox
end // end of [row_create]

Each button in the created H-box is created by calling button_create on the corresponding string in the given argument of row_create, which is a list of strings. Note that the function gtk_box_pack_start packs a given widget into an H-box at the leftmost available position. There is another function gtk_box_pack_end that packs a given widget into an H-box at the rightmost available position. These two functions can also be called to pack widgets into vertical boxes.

The following function thePanel_create creates a panel of ten buttons that are labeled with digits:

fun
thePanel_create (): GtkBox1 = let
//
val vbox =
gtk_box_new
(
  GTK_ORIENTATION_VERTICAL, (gint)0
) (* end of [val] *)
val () = assertloc (ptrcast(vbox) > 0)
//
val row0 = row_create (row0)
val () = gtk_box_pack_start (vbox, row0, GTRUE, GTRUE, (guint)0)
val () = gtk_widget_show_unref (row0)
//
val row1 = row_create (row1)
val () = gtk_box_pack_start (vbox, row1, GTRUE, GTRUE, (guint)0)
val () = gtk_widget_show_unref (row1)
//
val row2 = row_create (row2)
val () = gtk_box_pack_start (vbox, row2, GTRUE, GTRUE, (guint)0)
val () = gtk_widget_show_unref (row2)
//
val row3 = row_create (row3)
val () = gtk_box_pack_start (vbox, row3, GTRUE, GTRUE, (guint)0)
val () = gtk_widget_show_unref (row3)
//
in
  vbox
end // end of [thePanel_create]

where the values row0, row1, and row2 have the following bindings when thePanel_create is called:

val row0 =
g0ofg1 ($list{string}("1", "2", "3"))
//
val row1 =
g0ofg1 ($list{string}("4", "5", "6"))
//
val row2 =
g0ofg1 ($list{string}("7", "8", "9"))
//
val row3 = g0ofg1 ($list{string}("0"))

The function thePanel_create returns a vertical box (V-box). In its body, the function gtk_box_pack_start is called to pack four H-boxes into the returned V-box. When called to pack a widget into a V-box, gtk_box_pack_start chooses the topmost available position for the widget.

The entirety of the presented code can be found in chap_boxpack.dats, and there is a Makefile available for compiling the file.