[gtk+] Enhanced GtkWidget documentation with regards to height-for-width geometry management.



commit 86b3c1b65e6fefc6f686279b1bc15b10895b61fe
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date:   Thu Oct 21 22:53:06 2010 +0900

    Enhanced GtkWidget documentation with regards to height-for-width geometry management.

 gtk/gtkwidget.c |  229 +++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 173 insertions(+), 56 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 49420c9..a681dd3 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -72,73 +72,190 @@
  * <refsect2 id="geometry-management">
  * <title>Height-for-width Geometry Management</title>
  * <para>
- * GTK+ uses a height-for-width (and width-for-height) geometry management system. 
- * Height-for-width means that a widget can change how much vertical space it needs, 
- * depending on the amount of horizontal space that it is given (and similar for 
- * width-for-height). The most common example is a label that reflows to fill up the 
- * available width, wraps to fewer lines, and therefore needs less height.
- *
- * GTK+'s traditional two-pass <link linkend="size-allocation">size-allocation</link>
- * algorithm does not allow this flexibility. #GtkWidget provides a default
- * implementation of the height-for-width methods for existing widgets,
- * which always requests the same height, regardless of the available width.
- *
- * Some important things to keep in mind when implementing
- * height-for-width and when using it in container
- * implementations.
- *
- * The geometry management system will query a logical hierarchy in
+ * GTK+ uses a height-for-width (and width-for-height) geometry management
+ * system Height-for-width means that a widget can change how much 
+ * vertical space it needs, depending on the amount of horizontal space 
+ * that it is given (and similar for width-for-height). The most common 
+ * example is a label that reflows to fill up the available width, wraps 
+ * to fewer lines, and therefore needs less height.
+ *
+ * Height-for-width geometry management is implemented in GTK+ by way 
+ * of five virtual methods:
+ * <variablelist>
+ *    <varlistentry>
+ *       <term>#GtkWidgetClass.get_request_mode()</term>
+ *       <listitem>
+ *          This allows a widget to tell it's parent container whether
+ *          it preferrs to be allocated in %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH
+ *          or %GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT mode.
+ *
+ *          %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH means the widget preferrs to
+ *          have #GtkWidgetClass.get_preferred_width() called and then
+ *          #GtkWidgetClass.get_preferred_height_for_width() and is the 
+ *          default return for unimplemented cases.
+ *
+ *          However it's important to note (as described below) that any
+ *          widget which trades height-for-width must respond properly to 
+ *          both #GtkSizeRequestModes since it might be queried in either
+ *          orientation by it's parent container.
+ *       </listitem>
+ *    </varlistentry>
+ *    <varlistentry>
+ *       <term>#GtkWidgetClass.get_preferred_width()</term>
+ *       <listitem>
+ *          This is called by containers to obtain the minimum and
+ *          natural width of a widget. A widget will never be allocated
+ *          a width less than it's minimum and will only ever be allocated
+ *          a width greater than the natural width once all of the said
+ *          widget's siblings have received their natural widths.
+ *
+ *          Furthermore a widget will only ever be allocated a width greater
+ *          than it's natural width if it was configured to receive extra
+ *          expand space from it's parent container.
+ *       </listitem>
+ *    </varlistentry>
+ *    <varlistentry>
+ *       <term>#GtkWidgetClass.get_preferred_height()</term>
+ *       <listitem>
+ *          This is called by containers to obtain the minimum and
+ *          natural height of a widget.
+ *
+ *          A widget that does not actually trade any height for width
+ *          or width for height only has to implement these two virtual 
+ *          methods (#GtkWidgetClass.get_preferred_width() and
+ *          #GtkWidgetClass.get_preferred_height()).
+ *       </listitem>
+ *    </varlistentry>
+ *    <varlistentry>
+ *       <term>#GtkWidgetClass.get_preferred_height_for_width()</term>
+ *       <listitem>
+ *          This is similar to #GtkWidgetClass.get_preferred_height() except
+ *          that it is passed a contextual width to request height for. By
+ *          implementing this virtual method it is possible for a #GtkLabel
+ *          to tell it's parent how much height would be required if the
+ *          label were to be allocated a said width.
+ *       </listitem>
+ *    </varlistentry>
+ *    <varlistentry>
+ *       <term>#GtkWidgetClass.get_preferred_width_for_height()</term>
+ *       <listitem>
+ *          This is analogous to #GtkWidgetClass.get_preferred_height_for_width() 
+ *          except that it operates in the oposite orientation. It's rare that
+ *          a widget actually does %GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT requests
+ *          but can happen when for example; a widget or container gets additional
+ *          columns to compensate for a smaller allocated height.
+ *       </listitem>
+ *    </varlistentry>
+ * </variablelist>
+ *
+ * There are some important things to keep in mind when implementing
+ * height-for-width and when using it in container implementations.
+ *
+ * The geometry management system will query a widget hierarchy in
  * only one orientation at a time. When widgets are initially queried
- * for their minimum sizes it is generally done in a dual pass
- * in the direction chosen by the toplevel.
- *
- * For instance when queried in the normal height-for-width mode:
- * First the default minimum and natural width for each widget
- * in the interface will computed and collectively returned to
- * the toplevel by way of gtk_widget_get_preferred_width().
- * Next, the toplevel will use the minimum width to query for the
- * minimum height contextual to that width using
- * gtk_widget_get_preferred_height_for_width(), which will also
- * be a highly recursive operation. This minimum-for-minimum size can
- * be used to set the minimum size constraint on the toplevel.
- *
- * When allocating, each container can use the minimum and natural
- * sizes reported by their children to allocate natural sizes and
- * expose as much content as possible with the given allocation.
- *
- * That means that the request operation at allocation time will
- * usually fire again in contexts of different allocated sizes than
- * the ones originally queried for. #GtkWidget caches a
- * small number of results to avoid re-querying for the same
- * allocated size in one allocation cycle.
- *
- * A widget that does not actually do height-for-width
- * or width-for-height size negotiations only has to implement
- * #GtkWidgetClass.get_preferred_width() and
- * #GtkWidgetClass.get_preferred_height().
+ * for their minimum sizes it is generally done in two initial passes
+ * in the #GtkSizeRequestMode chosen by the toplevel.
+ *
+ * For example, when queried in the normal 
+ * %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH mode:
+ * First, the default minimum and natural width for each widget
+ * in the interface will be computed using gtk_width_get_preferred_width(). 
+ * Because the preferred widths for each container depends on the preferred 
+ * widths of thier children, this information propagates up the hierarchy, 
+ * and finally a minimum and natural width is determined for the entire
+ * toplevel. Next, the toplevel will use the minimum width to query for the 
+ * minimum height contextual to that width using 
+ * gtk_widget_get_preferred_height_for_width(), which will also be a highly 
+ * recursive operation. The minimum height for the minimum width is normally 
+ * used to set the minimum size constraint on the toplevel 
+ * (unless gtk_window_set_geometry_hints() is explicitly used instead).
+ *
+ * After the toplevel window has initially requested it's size in both 
+ * dimensions it can go on to allocate itself a reasonable size (or a size 
+ * previously specified with gtk_window_set_default_size()). During the 
+ * recursive allocation process it's important to note that request cycles 
+ * will be recursively executed while container widgets allocate their children. 
+ * Each container widget, once allocated a size will go on to first share the 
+ * space in one orientation among its children and then request each child's 
+ * height for their target allocated width or width for allocated height 
+ * depending. In this way a #GtkWidget will typically be requested its size
+ * a number of times before actually being allocated a size, the size a 
+ * widget is finally allocated can of course differ from the size it 
+ * requested. For this reason; #GtkWidget caches a  small number of results 
+ * to avoid re-querying for the same sizes in one allocation cycle.
+ *
+ * See <link linkend="container-geometry-management">GtkContainer's 
+ * geometry management section</link>
+ * to learn more about how height-for-width allocations are performed 
+ * by container widgets.
  *
  * If a widget does move content around to smartly use up the
- * allocated size, then it must support the request properly in
- * both orientations; even if the request only makes sense in
- * one orientation.
+ * allocated size, then it must support the request in both
+ * #GtkSizeRequestModes even if the widget in question only 
+ * trades sizes in a single orientation.
  *
  * For instance, a #GtkLabel that does height-for-width word wrapping
- * will not expect to have #GtkWidgetClass.get_preferred_height() called because that
- * call is specific to a width-for-height request. In this case the
- * label must return the heights contextual to its minimum possible
- * width. By following this rule any widget that handles height-for-width
- * or width-for-height requests will always be allocated at least
- * enough space to fit its own content.
+ * will not expect to have #GtkWidgetClass.get_preferred_height() called 
+ * because that call is specific to a width-for-height request. In this 
+ * case the label must return the heights required for it's own minimum 
+ * possible width. By following this rule any widget that handles 
+ * height-for-width or width-for-height requests will always be allocated 
+ * at least enough space to fit its own content.
+ *
+ * Here are some examples of how a %GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH widget
+ * generally deals with width-for-height requests, for #GtkWidgetClass.get_preferred_height()
+ * it will do:
+ * <programlisting><![CDATA[
+ * static void
+ * foo_widget_get_preferred_height (GtkWidget *widget, gint *min_height, gint *nat_height)
+ * {
+ *    if (i_am_in_height_for_width_mode)
+ *      {
+ *        gint min_width;
+ *
+ *        GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, &min_width, NULL);
+ *        GTK_WIDGET_GET_CLASS (widget)->get_preferred_height_for_width (widget, min_width, 
+ *                                                                      min_height, nat_height);
+ *      }
+ *    else
+ *      {
+ *         ... some widgets do both, for instance if a GtkLabel is rotated to 90 degrees
+ *         it will return the minimum and natural height for the rotated label here.
+ *      }
+ * }
+ * ]]></programlisting>
+ * 
+ * And in #GtkWidgetClass.get_preferred_width_for_height() it will simply return
+ * the minimum and natural width:
+ *
+ * <programlisting><![CDATA[
+ * static void
+ * foo_widget_get_preferred_width_for_height (GtkWidget *widget, gint for_height, 
+ *                                            gint *min_width, gint *nat_width)
+ * {
+ *    if (i_am_in_height_for_width_mode)
+ *      {
+ *        GTK_WIDGET_GET_CLASS (widget)->get_preferred_width (widget, min_width, nat_width);
+ *      }
+ *    else
+ *      {
+ *         ... again if a widget is sometimes operating in width-for-height mode
+ *         (like a rotated GtkLabel) it can go ahead and do it's real width for
+ *         height calculation here.
+ *      }
+ * }
+ * ]]></programlisting>
  *
  * Often a widget needs to get its own request during size request or
  * allocation, for example when computing height it may need to also
- * compute width, or when deciding how to use an allocation the widget may
- * need to know its natural size. In these cases, the widget should be
- * careful to call its virtual methods directly, like this:
+ * compute width, or when deciding how to use an allocation the widget 
+ * may need to know its natural size. In these cases, the widget should 
+ * be careful to call its virtual methods directly, like this:
  * <example>
  *   <title>Widget calling its own size request method.</title>
  *   <programlisting>
- * GTK_WIDGET_GET_CLASS(widget)-&gt;get_preferred_width (widget), &min, &natural);
+ * GTK_WIDGET_GET_CLASS(widget)-&gt;get_preferred_width (widget), 
+ *                                  &min, &natural);
  *   </programlisting>
  * </example>
  *



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]