<?xml version="1.0"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN"
               "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [
]>
<chapter id="gtk-migrating-GtkGrid">

  <title>Migrating from other containers to GtkGrid</title>

  <para>
    #GtkGrid is an attempt to write a comprehensive, legacy-free,
    box-layout container that is flexible enough to replace #GtkBox,
    #GtkTable and the like.
  </para>

  <para>
    The layout model of GtkGrid is to arrange its children in rows and
    columns. This is done by assigning positions on a two-dimentions
    grid that stretches arbitrarily far in all directions.
    Children can span multiple rows or columns, too.
 </para>

  <section>

    <title>GtkBox versus GtkGrid: packing</title>

    <para>
      GtkBox works by arranging child widgets in a single line, either
      horizontally or vertically. It allows packing children from the
      beginning or end, using gtk_box_pack_start() and gtk_box_pack_end().
    </para>

    <inlinegraphic fileref="box-packing.png" format="PNG"></inlinegraphic>

  <example>
    <title>A simple box</title>
    <programlisting>
  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);

  gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("One"), FALSE, FALSE, 0);
  gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("Two"), FALSE, FALSE, 0);
    </programlisting>
    <para>This can be done with #GtkGrid as follows:</para>
    <programlisting>
  grid = gtk_grid_new ();

  child1 = gtk_label_new ("One");
  gtk_grid_attach (GTK_GRID (grid), child1, 0, 0, 1, 1);
  child2 = gtk_label_new ("Two");
  gtk_grid_attach_next_to (GTK_GRID (grid), child2, child1, GTK_POS_RIGHT, 1, 1);
    </programlisting>
    <para>
      And similarly for gtk_box_pack_end(). In that case, you
      would use #GTK_POS_LEFT to place the grid children from
      left to right.
    </para>
    <para>
      If you only need to pack children from the start, using
      gtk_container_add() is an even simpler alternative. GtkGrid
      places children added with gtk_container_add() in a single
      row or column according to its #GtkOrientable:orientation.
    </para>
  </example>

    <para>
      One difference to keep in mind is that the gtk_box_pack_start/pack_end
      functions allow you to place an arbitrary number of children from
      either end without ever 'colliding in the middle'. With GtkGrid, you
      have to leave enough space between the two ends, if you want to combine
      packing from both ends towards the middle. In practice, this should be
      easy to avoid; and GtkGrid simply ignores entirely empty rows or
      columns for layout and spacing.
    </para>
    <para>
      On the other hand, GtkGrid is more flexible in that its grid extends
      indefinitively in both directions &mdash; there is no problem with
      using negative numbers for the grid positions. So, if you discover
      that you need to place a widget before your existing arrangement,
      you always can.
    </para>
  </section>

  <section>
    <title>GtkBox versus GtkGrid: sizing</title>

    <para>
      When adding a child to a GtkBox, there are two hard-to-remember
      parameters (child properties, more exactly) named expand and fill
      that determine how the child size behaves in the main direction
      of the box. If expand is set, the box allows the position occupied
      by the child to grow when extra space is available. If fill is
      also set, the extra space is allocated to the child widget itself.
      Otherwise it is left 'free'.
      There is no control about the 'minor' direction; children
      are always given the full size in the minor direction.
    </para>

    <inlinegraphic fileref="box-expand.png" format="PNG"></inlinegraphic>

    <para>
      GtkGrid does not have any custom child properties for controlling
      size allocation to children. Instead, it fully supports the newly
      introduced #GtkWidget:hexpand, #GtkWidget:vexpand, #GtkWidget:halign
      and #GtkWidget:valign properties.
    </para>
    <para>
      The #GtkWidget:hexpand and #GtkWidget:vexpand properties operate
      in a similar way to the expand child properties of #GtkBox. As soon
      as a column contains a hexpanding child, GtkGrid allows the column
      to grow when extra space is available (similar for rows and vexpand).
      In contrast to GtkBox, all the extra space is always allocated
      to the child widget, there are no 'free' areas.
    </para>
    <para>
      To replace the functionality of the fill child properties, you can
      set the #GtkWidget:halign and #GtkWidget:valign properties. An
      align value of #GTK_ALIGN_FILL has the same effect as setting fill
      to %TRUE, a value of #GTK_ALIGN_CENTER has the same effect as setting
      fill to %FALSE. The image below shows the effect of various combinations
      of halign and valign.
    </para>

    <inlinegraphic fileref="widget-hvalign.png" format="PNG"></inlinegraphic>

    <example>
      <title>Expansion and alignment</title>
      <programlisting>
  box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);

  gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("One"), TRUE, FALSE, 0);
  gtk_box_pack_start (GTK_BOX (box), gtk_label_new ("Two"), TRUE, TRUE, 0);
      </programlisting>
    <para>This can be done with #GtkGrid as follows:</para>
    <programlisting>
  grid = gtk_grid_new ();

  child1 = gtk_label_new ("One");
  gtk_widget_set_hexpand (child1, TRUE);
  gtk_widget_set_halign (child1, GTK_ALIGN_CENTER);
  gtk_grid_attach (GTK_GRID (grid), child1, 0, 0, 1, 1);
  child2 = gtk_label_new ("Two");
  gtk_widget_set_hexpand (child2, TRUE);
  gtk_widget_set_halign (child1, GTK_ALIGN_FILL);
  gtk_grid_attach_next_to (GTK_GRID (grid), child2, child1, GTK_POS_RIGHT, 1, 1);
      </programlisting>
    </example>
    <para>
      One difference between the new GtkWidget expand properties and
      the GtkBox child property of the same name is that widget expandability
      is 'inherited' from children. What this means is that a container
      will become itself expanding as soon as it has
      an expanding child. This is typically what you want, it lets
      you e.g. mark the content pane of your application window as
      expanding, and all the intermediate containers between the
      content pane and the toplevel window will automatically do
      the right thing. This automatism can be overridden at any
      point by setting the expand flags on a container explicitly.
    </para>
    <para>
      Another difference between GtkBox and GtkGrid with respect to
      expandability is when there are no expanding children at all.
      In this case, GtkBox will forcibly expand all children whereas
      GtkGrid will not. In practice, the effect of this is typically
      that a grid will 'stick to the corner' when the toplevel
      containing it is grown, instead of spreading out its children
      over the entire area. The problem can be fixed by setting some
      or all of the children to expand.
    </para>

    <para>
      When you set the #GtkBox:homogeneous property on a GtkBox,
      it reserves the same space for all its children. GtkGrid does
      this in a very similar way, with #GtkGrid:row-homogeneous and
      #GtkGrid:column-homogeneous properties which control whether
      all rows have the same height and whether all columns have
      the same width.
    </para>
  </section>

  <section>
    <title>GtkBox versus GtkGrid: spacing</title>

    <para>
      With GtkBox, you have to specify the #GtkBox:spacing when
      you construct it. This property specifies the space that
      separates the children from each other. Additionally, you
      can specify extra space to put around each child individually,
      using the #GtkBox padding child property.
    </para>

    <para>
      GtkGrid is very similar when it comes to spacing between the
      children, except that it has two separate properties,
      #GtkGrid:row-spacing and #GtkGrid:column-spacing, for the
      space to leave between rows and columns. Note that row-spacing
      is the space <emphasis>between</emphasis> rows, not inside
      a row. So, if you doing a horizontal layout, you need to set
      #GtkGrid:column-spacing.
    </para>
    <para>
      GtkGrid doesn't have any custom child properties to specify
      per-child padding; instead you can use the #GtkWidget:margin
      property. You can also set different padding on each side with
      the  #GtkWidget:margin-left, #GtkWidget:margin-right,
      #GtkWidget:margin-top and #GtkWidget:margin-bottom properties.
    </para>

    <example>
      <title>Spacing in boxes</title>

      <programlisting>
         box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
         gtk_box_pack_start (GTK_BOX (box), child, FALSE, FALSE, 12);
      </programlisting>
      <para>This can be done with #GtkGrid as follows:</para>
      <programlisting>
         grid = gtk_grid_new ();
         gtk_grid_set_row_spacing (GTK_GRID (grid), 6);
         g_object_set (child, "margin", 12, NULL);
         gtk_grid_attach (GTK_GRID (box), child, 0, 0, 1, 1);
      </programlisting>
    </example>
  </section>

<!--
  <section>
    <title>GtkTable versus GtkGrid</title>
    cover here: spanning, attachment points, grid size, attach options vs expand/align

  </section>
-->
</chapter>
