[gtk+/treeview-refactor] Added initial detailed docs for GtkCellArea.
- From: Tristan Van Berkom <tvb src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/treeview-refactor] Added initial detailed docs for GtkCellArea.
- Date: Mon, 29 Nov 2010 05:25:58 +0000 (UTC)
commit 9ee908140589968c069b75aa37fb0d3ef3fb954f
Author: Tristan Van Berkom <tristan van berkom gmail com>
Date: Mon Nov 29 10:54:07 2010 +0900
Added initial detailed docs for GtkCellArea.
gtk/gtkcellarea.c | 307 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 305 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c
index e68fb65..f170786 100644
--- a/gtk/gtkcellarea.c
+++ b/gtk/gtkcellarea.c
@@ -21,6 +21,289 @@
* Boston, MA 02111-1307, USA.
*/
+/**
+ * SECTION:gtkcellarea
+ * @Short_Description: An abstract class for laying out #GtkCellRenderers
+ * @Title: GtkCellArea
+ *
+ * The #GtkCellArea is an abstract class for laying out #GtkCellRenderers
+ * onto a given area of a #GtkWidget.
+ *
+ * The work of rendering #GtkCellRenderers can be very complicated; it involves
+ * requesting size for cells, driving keyboard focus from cell to cell, rendering
+ * the actual cells, painting the focus onto the currently focused cell and finally
+ * activating cells which are %GTK_CELL_RENDERER_MODE_ACTIVATABLE and editing cells
+ * which are %GTK_CELL_RENDERER_MODE_EDITABLE. The work is even more complex since
+ * a cell renderer as opposed to a widget, is used to interact with an arbitrary
+ * number of #GtkTreeModel rows instead of always displaying the same data.
+ *
+ * <refsect2 id="cell-area-geometry-management">
+ * <title>Requesting area sizes</title>
+ * <para>
+ * As outlined in <link linkend="geometry-management">GtkWidget's
+ * geometry management section</link>, GTK+ uses a height-for-width
+ * geometry managemen system to compute the sizes of widgets and user
+ * interfaces. #GtkCellArea uses the same semantics to calculate the
+ * size of an area for an arbitrary number of #GtkTreeModel rows.
+ *
+ * When requesting the size of a #GtkCellArea one needs to calculate
+ * the size of a handful of rows, this will be done differently by
+ * different #GtkCellLayout widgets. For instance a #GtkTreeViewColumn
+ * always lines up the areas from top to bottom while a #GtkIconView
+ * on the other hand might enforce that areas maintain a fixed width
+ * and then wrap the area around, thus requesting height for more
+ * areas when allocated less width.
+ *
+ * It's also important for #GtkCellAreas to maintain some cell
+ * alignments with areas rendered for different rows so that
+ * a handful of rendered rows can allocate the same size for
+ * a said cell across rows (and also to make sure to request
+ * an appropriate size for the largest row after requesting
+ * a hand full of rows). For this reason the #GtkCellArea
+ * uses a #GtkCellAreaContext object to store the alignments
+ * and sizes along the way.
+ *
+ * In order to request the width of all the rows at the root level
+ * of a #GtkTreeModel one would do the following:
+ * <example>
+ * <title>Requesting the width of a hand full of GtkTreeModel rows.</title>
+ * <programlisting>
+ * GtkTreeIter iter;
+ * gint minimum_width;
+ * gint natural_width;
+ *
+ * valid = gtk_tree_model_get_iter_first (model, &iter);
+ * while (valid)
+ * {
+ * gtk_cell_area_apply_attributes (area, model, &iter, FALSE, FALSE);
+ * gtk_cell_area_get_preferred_width (area, context, widget, NULL, NULL);
+ *
+ * valid = gtk_tree_model_iter_next (model, &iter);
+ * }
+ * gtk_cell_area_context_get_preferred_width (context, &minimum_width, &natural_width);
+ * </programlisting>
+ * </example>
+ * Note that in this example it's not important to observe the returned minimum and
+ * natural width of the area for each row unless the cell layouting object is actually
+ * interested in the widths of individual rows. The overall width is however stored
+ * in the accompanying #GtkCellAreaContext object and can be consulted at any time.
+ *
+ * This can be useful since #GtkCellLayout widgets usually have to support requesting
+ * and rendering rows in treemodels with an exceedingly large amount of rows. The
+ * #GtkCellLayout widget in that case would calculate the required width of the rows
+ * in an idle or timeout source (see g_timeout_add()) and when the widget is requested
+ * its actual width in #GtkWidgetClass.get_preferred_width() it can simply consult the
+ * width accumulated so far in the #GtkCellAreaContext object.
+ *
+ * A simple example where rows are rendered from top to bottom and take up the full
+ * width of the layouting widget would look like:
+ * <example>
+ * <title>Requesting the width of a hand full of GtkTreeModel rows.</title>
+ * <programlisting>
+ * static void
+ * foo_get_preferred_width (GtkWidget *widget,
+ * gint *minimum_size,
+ * gint *natural_size)
+ * {
+ * Foo *foo = FOO (widget);
+ * FooPrivate *priv = foo->priv;
+ *
+ * foo_ensure_at_least_one_handfull_of_rows_have_been_requested (foo);
+ *
+ * gtk_cell_area_context_get_preferred_width (priv->context, minimum_size, natural_size);
+ * }
+ * </programlisting>
+ * </example>
+ *
+ * In the above example the Foo widget has to make sure that some row sizes have
+ * been calculated (the amount of rows that Foo judged was appropriate to request
+ * space for in a single timeout iteration) before simply returning the amount
+ * of space required by the area via the #GtkCellAreaContext.
+ *
+ * Requesting the height for width (or width for height) of an area is a similar
+ * task except in this case the #GtkCellAreaContext does not store the data (actually
+ * it does not know how much space the layouting widget plans to allocate it for
+ * every row, it's up to the layouting widget to render each row of data with
+ * the appropriate height and width which was requested by the #GtkCellArea).
+ *
+ * In order to request the height for width of all the rows at the root level
+ * of a #GtkTreeModel one would do the following:
+ * <example>
+ * <title>Requesting the height for width of a hand full of GtkTreeModel rows.</title>
+ * <programlisting>
+ * GtkTreeIter iter;
+ * gint minimum_height;
+ * gint natural_height;
+ * gint full_minimum_height = 0;
+ * gint full_natural_height = 0;
+ *
+ * valid = gtk_tree_model_get_iter_first (model, &iter);
+ * while (valid)
+ * {
+ * gtk_cell_area_apply_attributes (area, model, &iter, FALSE, FALSE);
+ * gtk_cell_area_get_preferred_height_for_width (area, context, widget,
+ * width, &minimum_height, &natural_height);
+ *
+ * if (width_is_for_allocation)
+ * cache_row_height (&iter, minimum_height, natural_height);
+ *
+ * full_minimum_height += minimum_height;
+ * full_natural_height += natural_height;
+ *
+ * valid = gtk_tree_model_iter_next (model, &iter);
+ * }
+ * </programlisting>
+ * </example>
+ *
+ * Note that in the above example we would need to cache the heights returned for each
+ * treemodel row so that we would know what sizes to render the areas for each row. However
+ * we would only want to really cache the heights if the request is intended for the
+ * layouting widgets real allocation.
+ *
+ * In some cases the layouting widget is requested the height for an arbitrary for_width,
+ * this is a special case for layouting widgets who need to request size for tens of thousands
+ * of treemodel rows. For this case it's only important that the layouting widget calculate
+ * one reasonably sized chunk of rows and return that height synchronously. The reasoning here
+ * is that any layouting widget is at least capable of synchronously calculating enough
+ * height to fill the screen height (or scrolled window height) in response to a single call to
+ * #GtkWidgetClass.get_preferred_height_for_width(). Returning a perfect height for width that
+ * is larger than the screen area is inconsequential since after the layouting receives an
+ * allocation from a scrolled window it simply continues to drive the the scrollbar
+ * values while more and mode height is required for the row heights that are calculated
+ * in the background.
+ * </para>
+ * </refsect2>
+ * <refsect2 id="cell-area-rendering">
+ * <title>Rendering Areas</title>
+ * <para>
+ * Once area sizes have been aquired at least for the rows in the visible area of the
+ * layouting widget they can be rendered at #GtkWidgetClass.draw() time.
+ *
+ * A crued example of how to render all the rows at the root level runs as follows:
+ * <example>
+ * <title>Requesting the width of a hand full of GtkTreeModel rows.</title>
+ * <programlisting>
+ * GtkAllocation allocation;
+ * GdkRectangle cell_area = { 0, };
+ * GtkTreeIter iter;
+ * gint minimum_width;
+ * gint natural_width;
+ *
+ * gtk_widget_get_allocation (widget, &allocation);
+ * cell_area.width = allocation.width;
+ *
+ * valid = gtk_tree_model_get_iter_first (model, &iter);
+ * while (valid)
+ * {
+ * cell_area.height = get_cached_height_for_row (&iter);
+ *
+ * gtk_cell_area_apply_attributes (area, model, &iter, FALSE, FALSE);
+ * gtk_cell_area_render (area, context, widget, cr,
+ * &cell_area, &cell_area, state_flags, FALSE);
+ *
+ * cell_area.y += cell_area.height;
+ *
+ * valid = gtk_tree_model_iter_next (model, &iter);
+ * }
+ * </programlisting>
+ * </example>
+ * Note that the cached height in this example really depends on how the layouting
+ * widget works. The layouting widget might decide to give every row it's minimum
+ * or natural height or if the model content is expected to fit inside the layouting
+ * widget with not scrolled window it would make sense to calculate the allocation
+ * for each row at #GtkWidget.size_allocate() time using gtk_distribute_natural_allocation().
+ * </para>
+ * </refsect2>
+ * <refsect2 id="cell-area-events-and-focus">
+ * <title>Handling Events and Driving Keyboard Focus</title>
+ * <para>
+ * Passing events to the area is as simple as handling events on any normal
+ * widget and then passing them to the gtk_cell_area_event() api as they come
+ * in. Usually #GtkCellArea is only interested in button events, however some
+ * customized derived areas can be implemented who are interested in handling
+ * other events. Handling an event can trigger the #GtkCellArea::focus-changed
+ * signal to fire as well as #GtkCellArea::add-editable in the case that
+ * an editable cell was clicked and needs to start editing.
+ *
+ * The #GtkCellArea drives keyboard focus from cell to cell in a way similar
+ * to #GtkWidget. For layouting widgets that support giving focus to cells it's
+ * important to remember to pass %GTK_CELL_RENDERER_FOCUSED to the area functions
+ * for the row that has focus and to tell the area to paint the focus at render
+ * time.
+ *
+ * Layouting widgets that accept focus on cells should implement the #GtkWidgetClass.focus()
+ * virtual method. The layouting widget is always responsible for knowing where
+ * #GtkTreeModel rows are rendered inside the widget, so at #GtkWidgetClass.focus() time
+ * the layouting widget should use the #GtkCellArea methods to navigate focus inside the
+ * area and then observe the GtkDirectionType to pass the focus to adjacent rows and
+ * areas.
+ *
+ * A basic example of how the #GtkWidgetClass.focus() virtual method should be implemented:
+ * <example>
+ * <title>Implementing keyboard focus navigation when displaying rows from top to bottom.</title>
+ * <programlisting>
+ * static void
+ * foo_focus (GtkWidget *widget,
+ * GtkDirectionType direction)
+ * {
+ * Foo *foo = FOO (widget);
+ * FooPrivate *priv = foo->priv;
+ * gint focus_row;
+ * gboolean have_focus = FALSE;
+ *
+ * focus_row = priv->focus_row;
+ *
+ * if (!gtk_widget_has_focus (widget))
+ * gtk_widget_grab_focus (widget);
+ *
+ * valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, priv->focus_row);
+ * while (valid)
+ * {
+ * gtk_cell_area_apply_attributes (priv->area, priv->model, &iter, FALSE, FALSE);
+ *
+ * if (gtk_cell_area_focus (priv->area, direction))
+ * {
+ * priv->focus_row = focus_row;
+ * have_focus = TRUE;
+ * break;
+ * }
+ * else
+ * {
+ * if (direction == GTK_DIR_RIGHT ||
+ * direction == GTK_DIR_LEFT)
+ * break;
+ * else if (direction == GTK_DIR_UP ||
+ * direction == GTK_DIR_TAB_BACKWARD)
+ * {
+ * if (focus_row == 0)
+ * break;
+ * else
+ * {
+ * focus_row--;
+ * valid = gtk_tree_model_iter_nth_child (priv->model, &iter, NULL, focus_row);
+ * }
+ * }
+ * else
+ * {
+ * if (focus_row == last_row)
+ * break;
+ * else
+ * {
+ * focus_row++;
+ * valid = gtk_tree_model_iter_next (priv->model, &iter);
+ * }
+ * }
+ * }
+ * }
+ * return have_focus;
+ * }
+ * </programlisting>
+ * </example>
+ * </para>
+ * </refsect2>
+ *
+ */
+
#include "config.h"
#include <stdarg.h>
@@ -275,7 +558,6 @@ gtk_cell_area_class_init (GtkCellAreaClass *class)
class->activate = gtk_cell_area_real_activate;
/* Signals */
-
/**
* GtkCellArea::apply-attributes:
* @area: the #GtkCellArea to apply the attributes to
@@ -372,6 +654,11 @@ gtk_cell_area_class_init (GtkCellAreaClass *class)
G_TYPE_STRING);
/* Properties */
+ /**
+ * GtkCellArea:focus-cell:
+ *
+ * The cell in the area that currently has focus
+ */
g_object_class_install_property (object_class,
PROP_FOCUS_CELL,
g_param_spec_object
@@ -381,6 +668,14 @@ gtk_cell_area_class_init (GtkCellAreaClass *class)
GTK_TYPE_CELL_RENDERER,
GTK_PARAM_READWRITE));
+ /**
+ * GtkCellArea:edited-cell:
+ *
+ * The cell in the area that is currently edited
+ *
+ * This property is read-only and only changes as
+ * a result of a call gtk_cell_area_activate_cell().
+ */
g_object_class_install_property (object_class,
PROP_EDITED_CELL,
g_param_spec_object
@@ -390,6 +685,14 @@ gtk_cell_area_class_init (GtkCellAreaClass *class)
GTK_TYPE_CELL_RENDERER,
G_PARAM_READABLE));
+ /**
+ * GtkCellArea:edit-widget:
+ *
+ * The widget currently editing the edited cell
+ *
+ * This property is read-only and only changes as
+ * a result of a call gtk_cell_area_activate_cell().
+ */
g_object_class_install_property (object_class,
PROP_EDIT_WIDGET,
g_param_spec_object
@@ -989,7 +1292,7 @@ gtk_cell_area_has_renderer (GtkCellArea *area,
}
/**
- * gtk_cell_area_forall
+ * gtk_cell_area_forall:
* @area: a #GtkCellArea
* @callback: the #GtkCellCallback to call
* @callback_data: user provided data pointer
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]