* @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 #GtkCellArea is an abstract class for #GtkCellLayout widgets (also referred
+ * to as "layouting widgets") to interface with an arbitrary number of #GtkCellRenderers
+ * and interact with the user for a given #GtkTreeModel row.
*
- * 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.
+ * The cell area handles events, focus navigation, drawing and wraps geometrical
+ * size requests and allocations for a given row of data.
+ *
+ * Usually users dont have to interact with the #GtkCellArea directly unless they
+ * are implementing a cell layouting widget themselves.
*
* <refsect2 id="cell-area-geometry-management">
* <title>Requesting area sizes</title>
* 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
+ * When requesting the size of a cell area one needs to calculate
+ * the size for a handful of rows, this will be done differently by
+ * different layouting 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
+ * on the other hand might enforce that all areas received the same
+ * width and wrap the areas around, requesting height for more cell
* 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
+ * It's also important for areas to maintain some cell
+ * alignments with areas rendered for adjacent rows (cells can
+ * appear "columnized" inside an area even when the size of
+ * cells are different in each row). For this reason the #GtkCellArea
* uses a #GtkCellAreaContext object to store the alignments
- * and sizes along the way.
+ * and sizes along the way (as well as the overall largest minimum
+ * and natural size for all the rows which have been calculated
+ * with the said context).
+ *
+ * The #GtkCellAreaContext is an opaque object specific to the
+ * #GtkCellArea which created it (see gtk_cell_area_create_context()).
+ * The owning cell layouting widget can create as many contexts as
+ * it wishes to calculate sizes of rows which should receive the
+ * same size in at least one orientation (horizontally or vertically),
+ * however it's important that the same #GtkCellAreaContext which
+ * was used to request the sizes for a given #GtkTreeModel row be
+ * used when rendering or processing events for that row.
*
* In order to request the width of all the rows at the root level
* of a #GtkTreeModel one would do the following:
* 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>
+ * <title>A typical #GtkWidgetClass.get_preferred_width() for a layouting widget.</title>
* <programlisting>
* static void
* foo_get_preferred_width (GtkWidget *widget,
* 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
+ * widget with no 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>
* 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.
+ * an editable cell was clicked and needs to start editing. You can call
+ * gtk_cell_area_stop_editing() at any time to cancel any cell editing
+ * that is currently in progress.
*
* 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
* <example>
* <title>Implementing keyboard focus navigation when displaying rows from top to bottom.</title>
* <programlisting>
- * static void
+ * static gboolean
* foo_focus (GtkWidget *widget,
* GtkDirectionType direction)
* {
* }
* 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)
+ * 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
* {
* else
* {
* if (focus_row == last_row)
- * break;
+ * break;
* else
* {
* focus_row++;
* </example>
* </para>
* </refsect2>
+ * <refsect2 id="cell-properties">
+ * <title>Cell Properties</title>
+ * <para>
+ * The #GtkCellArea introduces <emphasis>cell properties</emphasis> for #GtkCellRenderers in very
+ * much the same way that #GtkContainer introduces <link linkend="child-properties">child properties</link>
+ * for #GtkWidgets. This provides some general interfaces for defining the relationship cell areas
+ * have with their cells. For instance in a #GtkCellAreaBox a cell might "expand" and recieve extra
+ * space when the area is allocated more than it's full natural request, or a cell might be configured
+ * to "align" with adjacent rows which were requested and rendered with the same #GtkCellAreaContext.
+ *
+ * Use gtk_cell_area_class_install_cell_property() to install cell properties
+ * for a cell area class and gtk_cell_area_class_find_cell_property() or
+ * gtk_cell_area_class_list_cell_properties() to get information about existing
+ * cell properties.
+ *
+ * To set the value of a cell property, use gtk_cell_area_cell_set_property(),
+ * gtk_cell_area_cell_set() or gtk_cell_area_cell_set_valist().
+ * To obtain the value of a cell property, use
+ * gtk_cell_area_cell_get_property(), gtk_cell_area_cell_get() or
+ * gtk_cell_area_cell_get_valist().
+ * </para>
+ * </refsect2>
*
*/
GdkEvent *event,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
+static void gtk_cell_area_real_render (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ cairo_t *cr,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
+ GtkCellRendererState flags,
+ gboolean paint_focus);
static void gtk_cell_area_real_apply_attributes (GtkCellArea *area,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkCellAreaContext *context,
GtkWidget *widget,
const GdkRectangle *cell_area,
- GtkCellRendererState flags);
+ GtkCellRendererState flags,
+ gboolean edit_only);
/* GtkCellLayoutIface */
static void gtk_cell_area_cell_layout_init (GtkCellLayoutIface *iface);
GtkCellRenderer *cell,
gint position);
static GList *gtk_cell_area_get_cells (GtkCellLayout *cell_layout);
+static GtkCellArea *gtk_cell_area_get_area (GtkCellLayout *cell_layout);
+/* GtkBuildableIface */
+static void gtk_cell_area_buildable_init (GtkBuildableIface *iface);
+static void gtk_cell_area_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data);
-/* Used in forall loop to check if a child renderer is present */
+/* Used in foreach loop to check if a child renderer is present */
typedef struct {
GtkCellRenderer *renderer;
gboolean has_renderer;
} HasRendererCheck;
+/* Used in foreach loop to get a cell's allocation */
+typedef struct {
+ GtkCellRenderer *renderer;
+ GdkRectangle allocation;
+} RendererAllocationData;
+
+/* Used in foreach loop to render cells */
+typedef struct {
+ GtkCellArea *area;
+ GtkWidget *widget;
+ cairo_t *cr;
+ GdkRectangle focus_rect;
+ GtkCellRendererState render_flags;
+ guint paint_focus : 1;
+ guint focus_all : 1;
+ guint first_focus : 1;
+} CellRenderData;
+
+/* Used in foreach loop to get a cell by position */
+typedef struct {
+ gint x;
+ gint y;
+ GtkCellRenderer *renderer;
+ GdkRectangle cell_area;
+} CellByPositionData;
+
/* Attribute/Cell metadata */
typedef struct {
const gchar *attribute;
static void gtk_cell_area_add_editable (GtkCellArea *area,
GtkCellRenderer *renderer,
GtkCellEditable *editable,
- GdkRectangle *cell_area);
+ const GdkRectangle *cell_area);
static void gtk_cell_area_remove_editable (GtkCellArea *area,
GtkCellRenderer *renderer,
GtkCellEditable *editable);
#define PARAM_SPEC_PARAM_ID(pspec) ((pspec)->param_id)
#define PARAM_SPEC_SET_PARAM_ID(pspec, id) ((pspec)->param_id = (id))
-
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkCellArea, gtk_cell_area, G_TYPE_INITIALLY_UNOWNED,
G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
- gtk_cell_area_cell_layout_init));
+ gtk_cell_area_cell_layout_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_cell_area_buildable_init))
static void
gtk_cell_area_init (GtkCellArea *area)
/* general */
class->add = NULL;
class->remove = NULL;
- class->forall = NULL;
+ class->foreach = NULL;
class->event = gtk_cell_area_real_event;
- class->render = NULL;
+ class->render = gtk_cell_area_real_render;
class->apply_attributes = gtk_cell_area_real_apply_attributes;
/* geometry */
* @is_expanded: whether the view is currently showing the children of this row
*
* This signal is emitted whenever applying attributes to @area from @model
+ *
+ * Since: 3.0
*/
cell_area_signals[SIGNAL_APPLY_ATTRIBUTES] =
g_signal_new (I_("apply-attributes"),
* @editable: the #GtkCellEditable widget to add
* @cell_area: the #GtkWidget relative #GdkRectangle coordinates
* where @editable should be added
- * @path: the #GtkTreePath string this edit was initiated for
+ * @path: the #GtkTreePath string this edit was initiated for
*
* Indicates that editing has started on @renderer and that @editable
* should be added to the owning cell layouting widget at @cell_area.
+ *
+ * Since: 3.0
*/
cell_area_signals[SIGNAL_ADD_EDITABLE] =
g_signal_new (I_("add-editable"),
*
* Indicates that editing finished on @renderer and that @editable
* should be removed from the owning cell layouting widget.
+ *
+ * Since: 3.0
*/
cell_area_signals[SIGNAL_REMOVE_EDITABLE] =
g_signal_new (I_("remove-editable"),
* currently focused renderer did not change, this is
* because focus may change to the same renderer in the
* same cell area for a different row of data.
+ *
+ * Since: 3.0
*/
cell_area_signals[SIGNAL_FOCUS_CHANGED] =
g_signal_new (I_("focus-changed"),
* GtkCellArea:focus-cell:
*
* The cell in the area that currently has focus
+ *
+ * Since: 3.0
*/
g_object_class_install_property (object_class,
PROP_FOCUS_CELL,
*
* This property is read-only and only changes as
* a result of a call gtk_cell_area_activate_cell().
+ *
+ * Since: 3.0
*/
g_object_class_install_property (object_class,
PROP_EDITED_CELL,
*
* This property is read-only and only changes as
* a result of a call gtk_cell_area_activate_cell().
+ *
+ * Since: 3.0
*/
g_object_class_install_property (object_class,
PROP_EDIT_WIDGET,
GtkCellRendererState flags)
{
GtkCellAreaPrivate *priv = area->priv;
+ gboolean retval = FALSE;
if (event->type == GDK_KEY_PRESS && (flags & GTK_CELL_RENDERER_FOCUSED) != 0)
{
if (priv->edited_cell && (key_event->keyval == GDK_KEY_Escape))
{
gtk_cell_area_stop_editing (area, TRUE);
- return TRUE;
+ retval = TRUE;
+ }
+ }
+ else if (event->type == GDK_BUTTON_PRESS)
+ {
+ GdkEventButton *button_event = (GdkEventButton *)event;
+
+ if (button_event->button == 1)
+ {
+ GtkCellRenderer *renderer = NULL;
+ GtkCellRenderer *focus_renderer;
+ GdkRectangle alloc_area;
+ gint event_x, event_y;
+
+ /* We may need some semantics to tell us the offset of the event
+ * window we are handling events for (i.e. GtkTreeView has a bin_window) */
+ event_x = button_event->x;
+ event_y = button_event->y;
+
+ /* Dont try to search for an event coordinate that is not in the area, that will
+ * trigger a runtime warning.
+ */
+ if (event_x >= cell_area->x && event_x <= cell_area->x + cell_area->width &&
+ event_y >= cell_area->y && event_y <= cell_area->y + cell_area->height)
+ renderer =
+ gtk_cell_area_get_cell_at_position (area, context, widget,
+ cell_area, event_x, event_y,
+ &alloc_area);
+
+ if (renderer)
+ {
+ focus_renderer = gtk_cell_area_get_focus_from_sibling (area, renderer);
+ if (!focus_renderer)
+ focus_renderer = renderer;
+
+ /* If we're already editing, cancel it and set focus */
+ if (gtk_cell_area_get_edited_cell (area))
+ {
+ /* XXX Was it really canceled in this case ? */
+ gtk_cell_area_stop_editing (area, TRUE);
+ gtk_cell_area_set_focus_cell (area, focus_renderer);
+ retval = TRUE;
+ }
+ else
+ {
+ /* If we are activating via a focus sibling,
+ * we need to fetch the right cell area for the real event renderer */
+ if (focus_renderer != renderer)
+ gtk_cell_area_get_cell_allocation (area, context, widget, focus_renderer,
+ cell_area, &alloc_area);
+
+ gtk_cell_area_set_focus_cell (area, focus_renderer);
+ retval = gtk_cell_area_activate_cell (area, widget, focus_renderer,
+ event, &alloc_area, flags);
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+static gboolean
+render_cell (GtkCellRenderer *renderer,
+ const GdkRectangle *cell_area,
+ const GdkRectangle *cell_background,
+ CellRenderData *data)
+{
+ GtkCellRenderer *focus_cell;
+ GtkCellRendererState flags;
+ GdkRectangle inner_area;
+
+ focus_cell = gtk_cell_area_get_focus_cell (data->area);
+ flags = data->render_flags;
+
+ gtk_cell_area_inner_cell_area (data->area, data->widget, cell_area, &inner_area);
+
+ if ((flags & GTK_CELL_RENDERER_FOCUSED) &&
+ (data->focus_all ||
+ (focus_cell &&
+ (renderer == focus_cell ||
+ gtk_cell_area_is_focus_sibling (data->area, focus_cell, renderer)))))
+ {
+ gint focus_line_width;
+ GdkRectangle cell_focus;
+
+ gtk_cell_renderer_get_aligned_area (renderer, data->widget, flags, &inner_area, &cell_focus);
+
+ gtk_widget_style_get (data->widget,
+ "focus-line-width", &focus_line_width,
+ NULL);
+
+ /* The focus rectangle is located around the aligned area of the cell */
+ cell_focus.x -= focus_line_width;
+ cell_focus.y -= focus_line_width;
+ cell_focus.width += 2 * focus_line_width;
+ cell_focus.height += 2 * focus_line_width;
+
+ if (data->first_focus)
+ {
+ data->first_focus = FALSE;
+ data->focus_rect = cell_focus;
+ }
+ else
+ {
+ gdk_rectangle_union (&data->focus_rect, &cell_focus, &data->focus_rect);
}
}
+ else
+ flags &= ~GTK_CELL_RENDERER_FOCUSED;
+
+ gtk_cell_renderer_render (renderer, data->cr, data->widget,
+ cell_background, &inner_area, flags);
return FALSE;
}
+static void
+gtk_cell_area_real_render (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ cairo_t *cr,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
+ GtkCellRendererState flags,
+ gboolean paint_focus)
+{
+ CellRenderData render_data =
+ {
+ area,
+ widget,
+ cr,
+ { 0, },
+ flags,
+ paint_focus,
+ FALSE, TRUE
+ };
+
+ /* Make sure we dont paint a focus rectangle while there
+ * is an editable widget in play
+ */
+ if (gtk_cell_area_get_edited_cell (area))
+ render_data.paint_focus = FALSE;
+
+ /* If no cell can activate but the caller wants focus painted,
+ * then we paint focus around all cells */
+ if ((flags & GTK_CELL_RENDERER_FOCUSED) != 0 && paint_focus &&
+ !gtk_cell_area_is_activatable (area))
+ render_data.focus_all = TRUE;
+
+ gtk_cell_area_foreach_alloc (area, context, widget, cell_area, background_area,
+ (GtkCellAllocCallback)render_cell, &render_data);
+
+ if (render_data.paint_focus &&
+ render_data.focus_rect.width != 0 &&
+ render_data.focus_rect.height != 0)
+ {
+ GtkStateType renderer_state =
+ flags & GTK_CELL_RENDERER_SELECTED ? GTK_STATE_SELECTED :
+ (flags & GTK_CELL_RENDERER_PRELIT ? GTK_STATE_PRELIGHT :
+ (flags & GTK_CELL_RENDERER_INSENSITIVE ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL));
+
+ gtk_paint_focus (gtk_widget_get_style (widget), cr,
+ renderer_state, widget,
+ gtk_cell_area_get_style_detail (area),
+ render_data.focus_rect.x, render_data.focus_rect.y,
+ render_data.focus_rect.width, render_data.focus_rect.height);
+ }
+}
+
static void
apply_cell_attributes (GtkCellRenderer *renderer,
CellInfo *info,
GTK_CELL_AREA_GET_CLASS (area)->get_preferred_width (area, context, widget, minimum_width, natural_width);
}
-static void
+static gboolean
get_is_activatable (GtkCellRenderer *renderer,
gboolean *activatable)
{
if (gtk_cell_renderer_is_activatable (renderer))
*activatable = TRUE;
+
+ return *activatable;
}
static gboolean
* Subclasses can override this in the case that they are also
* rendering widgets as well as renderers.
*/
- gtk_cell_area_forall (area, (GtkCellCallback)get_is_activatable, &activatable);
+ gtk_cell_area_foreach (area, (GtkCellCallback)get_is_activatable, &activatable);
return activatable;
}
GtkCellAreaContext *context,
GtkWidget *widget,
const GdkRectangle *cell_area,
- GtkCellRendererState flags)
+ GtkCellRendererState flags,
+ gboolean edit_only)
{
GtkCellAreaPrivate *priv = area->priv;
- GdkRectangle background_area;
+ GdkRectangle renderer_area;
GtkCellRenderer *activate_cell = NULL;
+ GtkCellRendererMode mode;
if (priv->focus_cell)
- activate_cell = priv->focus_cell;
+ {
+ g_object_get (priv->focus_cell, "mode", &mode, NULL);
+
+ if (gtk_cell_renderer_get_visible (priv->focus_cell) &&
+ (edit_only ? mode == GTK_CELL_RENDERER_MODE_EDITABLE :
+ mode != GTK_CELL_RENDERER_MODE_INERT))
+ activate_cell = priv->focus_cell;
+ }
else
{
GList *cells, *l;
{
GtkCellRenderer *renderer = l->data;
- if (gtk_cell_renderer_is_activatable (renderer))
+ g_object_get (renderer, "mode", &mode, NULL);
+
+ if (gtk_cell_renderer_get_visible (renderer) &&
+ (edit_only ? mode == GTK_CELL_RENDERER_MODE_EDITABLE :
+ mode != GTK_CELL_RENDERER_MODE_INERT))
activate_cell = renderer;
}
g_list_free (cells);
}
-
if (activate_cell)
{
/* Get the allocation of the focused cell.
*/
gtk_cell_area_get_cell_allocation (area, context, widget, activate_cell,
- cell_area, &background_area);
+ cell_area, &renderer_area);
/* Activate or Edit the cell
*
* the event argument anyway, worst case is we can synthesize one.
*/
if (gtk_cell_area_activate_cell (area, widget, activate_cell, NULL,
- &background_area, flags))
+ &renderer_area, flags))
return TRUE;
}
iface->clear_attributes = gtk_cell_area_clear_attributes;
iface->reorder = gtk_cell_area_reorder;
iface->get_cells = gtk_cell_area_get_cells;
+ iface->get_area = gtk_cell_area_get_area;
}
static void
g_type_name (G_TYPE_FROM_INSTANCE (cell_layout)));
}
-static void
+static gboolean
accum_cells (GtkCellRenderer *renderer,
GList **accum)
{
*accum = g_list_prepend (*accum, renderer);
+
+ return FALSE;
}
static GList *
{
GList *cells = NULL;
- gtk_cell_area_forall (GTK_CELL_AREA (cell_layout),
- (GtkCellCallback)accum_cells,
- &cells);
+ gtk_cell_area_foreach (GTK_CELL_AREA (cell_layout),
+ (GtkCellCallback)accum_cells,
+ &cells);
return g_list_reverse (cells);
}
+static GtkCellArea *
+gtk_cell_area_get_area (GtkCellLayout *cell_layout)
+{
+ return GTK_CELL_AREA (cell_layout);
+}
+
+/*************************************************************
+ * GtkBuildableIface *
+ *************************************************************/
+static void
+gtk_cell_area_buildable_init (GtkBuildableIface *iface)
+{
+ iface->add_child = _gtk_cell_layout_buildable_add_child;
+ iface->custom_tag_start = _gtk_cell_layout_buildable_custom_tag_start;
+ iface->custom_tag_end = gtk_cell_area_buildable_custom_tag_end;
+}
+
+static void
+gtk_cell_area_buildable_custom_tag_end (GtkBuildable *buildable,
+ GtkBuilder *builder,
+ GObject *child,
+ const gchar *tagname,
+ gpointer *data)
+{
+ /* Just ignore the boolean return from here */
+ _gtk_cell_layout_buildable_custom_tag_end (buildable, builder, child, tagname, data);
+}
/*************************************************************
* API *
* @renderer: the #GtkCellRenderer to add to @area
*
* Adds @renderer to @area with the default child cell properties.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_add (GtkCellArea *area,
/**
* gtk_cell_area_remove:
* @area: a #GtkCellArea
- * @renderer: the #GtkCellRenderer to add to @area
+ * @renderer: the #GtkCellRenderer to remove from @area
*
* Removes @renderer from @area.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_remove (GtkCellArea *area,
g_type_name (G_TYPE_FROM_INSTANCE (area)));
}
-static void
+static gboolean
get_has_renderer (GtkCellRenderer *renderer,
HasRendererCheck *check)
{
if (renderer == check->renderer)
check->has_renderer = TRUE;
+
+ return check->has_renderer;
}
/**
*
* Checks if @area contains @renderer.
*
- * Returns: %TRUE if @renderer is in the @area.
+ * Return value: %TRUE if @renderer is in the @area.
+ *
+ * Since: 3.0
*/
gboolean
gtk_cell_area_has_renderer (GtkCellArea *area,
g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
g_return_val_if_fail (GTK_IS_CELL_RENDERER (renderer), FALSE);
- gtk_cell_area_forall (area, (GtkCellCallback)get_has_renderer, &check);
+ gtk_cell_area_foreach (area, (GtkCellCallback)get_has_renderer, &check);
return check.has_renderer;
}
/**
- * gtk_cell_area_forall:
+ * gtk_cell_area_foreach:
* @area: a #GtkCellArea
* @callback: the #GtkCellCallback to call
* @callback_data: user provided data pointer
*
* Calls @callback for every #GtkCellRenderer in @area.
+ *
+ * Since: 3.0
*/
void
-gtk_cell_area_forall (GtkCellArea *area,
- GtkCellCallback callback,
- gpointer callback_data)
+gtk_cell_area_foreach (GtkCellArea *area,
+ GtkCellCallback callback,
+ gpointer callback_data)
{
GtkCellAreaClass *class;
class = GTK_CELL_AREA_GET_CLASS (area);
- if (class->forall)
- class->forall (area, callback, callback_data);
+ if (class->foreach)
+ class->foreach (area, callback, callback_data);
else
- g_warning ("GtkCellAreaClass::forall not implemented for `%s'",
+ g_warning ("GtkCellAreaClass::foreach not implemented for `%s'",
g_type_name (G_TYPE_FROM_INSTANCE (area)));
}
/**
- * gtk_cell_area_get_cell_allocation:
+ * gtk_cell_area_foreach_alloc:
* @area: a #GtkCellArea
- * @context: the #GtkCellAreaContext used to hold sizes for @area.
- * @widget: the #GtkWidget that @area is rendering on
- * @renderer: the #GtkCellRenderer to get the allocation for
- * @cell_area: the whole allocated area for @area in @widget
- * for this row
- * @allocation: where to store the allocation for @renderer
+ * @context: the #GtkCellAreaContext for this row of data.
+ * @widget: the #GtkWidget that @area is rendering to
+ * @cell_area: the @widget relative coordinates and size for @area
+ * @background_area: the @widget relative coordinates of the background area
+ * @callback: the #GtkCellAllocCallback to call
+ * @callback_data: user provided data pointer
*
- * Derives the allocation of @renderer inside @area if @area
- * were to be renderered in @cell_area.
+ * Calls @callback for every #GtkCellRenderer in @area with the
+ * allocated rectangle inside @cell_area.
+ *
+ * Since: 3.0
*/
void
-gtk_cell_area_get_cell_allocation (GtkCellArea *area,
- GtkCellAreaContext *context,
- GtkWidget *widget,
- GtkCellRenderer *renderer,
- const GdkRectangle *cell_area,
- GdkRectangle *allocation)
+gtk_cell_area_foreach_alloc (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ const GdkRectangle *cell_area,
+ const GdkRectangle *background_area,
+ GtkCellAllocCallback callback,
+ gpointer callback_data)
{
GtkCellAreaClass *class;
g_return_if_fail (GTK_IS_CELL_AREA (area));
g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
g_return_if_fail (GTK_IS_WIDGET (widget));
- g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
g_return_if_fail (cell_area != NULL);
- g_return_if_fail (allocation != NULL);
+ g_return_if_fail (callback != NULL);
class = GTK_CELL_AREA_GET_CLASS (area);
- if (class->get_cell_allocation)
- class->get_cell_allocation (area, context, widget, renderer, cell_area, allocation);
+ if (class->foreach_alloc)
+ class->foreach_alloc (area, context, widget, cell_area, background_area, callback, callback_data);
else
- g_warning ("GtkCellAreaClass::get_cell_allocation not implemented for `%s'",
+ g_warning ("GtkCellAreaClass::foreach_alloc not implemented for `%s'",
g_type_name (G_TYPE_FROM_INSTANCE (area)));
}
*
* Delegates event handling to a #GtkCellArea.
*
- * Returns: %TRUE if the event was handled by @area.
+ * Return value: %TRUE if the event was handled by @area.
+ *
+ * Since: 3.0
*/
gint
gtk_cell_area_event (GtkCellArea *area,
*
* Renders @area's cells according to @area's layout onto @widget at
* the given coordinates.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_render (GtkCellArea *area,
*
* Sets the detail string used in any gtk_paint_*() functions
* used by @area.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_set_style_detail (GtkCellArea *area,
* Gets the detail string used in any gtk_paint_*() functions
* used by @area.
*
- * Returns: the detail string.
+ * Return value: the detail string, the string belongs to the area and should not be freed.
+ *
+ * Since: 3.0
*/
G_CONST_RETURN gchar *
gtk_cell_area_get_style_detail (GtkCellArea *area)
return priv->style_detail;
}
+static gboolean
+get_cell_allocation (GtkCellRenderer *renderer,
+ const GdkRectangle *cell_area,
+ const GdkRectangle *cell_background,
+ RendererAllocationData *data)
+{
+ if (data->renderer == renderer)
+ data->allocation = *cell_area;
+
+ return (data->renderer == renderer);
+}
+
+/**
+ * gtk_cell_area_get_cell_allocation:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext used to hold sizes for @area.
+ * @widget: the #GtkWidget that @area is rendering on
+ * @renderer: the #GtkCellRenderer to get the allocation for
+ * @cell_area: the whole allocated area for @area in @widget
+ * for this row
+ * @allocation: (out): where to store the allocation for @renderer
+ *
+ * Derives the allocation of @renderer inside @area if @area
+ * were to be renderered in @cell_area.
+ *
+ * Since: 3.0
+ */
+void
+gtk_cell_area_get_cell_allocation (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ GtkCellRenderer *renderer,
+ const GdkRectangle *cell_area,
+ GdkRectangle *allocation)
+{
+ RendererAllocationData data = { renderer, { 0, } };
+
+ g_return_if_fail (GTK_IS_CELL_AREA (area));
+ g_return_if_fail (GTK_IS_CELL_AREA_CONTEXT (context));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (GTK_IS_CELL_RENDERER (renderer));
+ g_return_if_fail (cell_area != NULL);
+ g_return_if_fail (allocation != NULL);
+
+ gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area,
+ (GtkCellAllocCallback)get_cell_allocation, &data);
+
+ *allocation = data.allocation;
+}
+
+static gboolean
+get_cell_by_position (GtkCellRenderer *renderer,
+ const GdkRectangle *cell_area,
+ const GdkRectangle *cell_background,
+ CellByPositionData *data)
+{
+ if (data->x >= cell_area->x && data->x < cell_area->x + cell_area->width &&
+ data->y >= cell_area->y && data->y < cell_area->y + cell_area->height)
+ {
+ data->renderer = renderer;
+ data->cell_area = *cell_area;
+ }
+
+ return (data->renderer != NULL);
+}
+
+/**
+ * gtk_cell_area_get_cell_at_position:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext used to hold sizes for @area.
+ * @widget: the #GtkWidget that @area is rendering on
+ * @cell_area: the whole allocated area for @area in @widget
+ * for this row
+ * @x: the x position
+ * @y: the y position
+ * @alloc_area: (out) (allow-none): where to store the inner allocated area of the
+ * returned cell renderer, or %NULL.
+ *
+ * Gets the #GtkCellRenderer at @x and @y coordinates inside @area and optionally
+ * returns the full cell allocation for it inside @cell_area.
+ *
+ * Return value: the #GtkCellRenderer at @x and @y.
+ *
+ * Since: 3.0
+ */
+GtkCellRenderer *
+gtk_cell_area_get_cell_at_position (GtkCellArea *area,
+ GtkCellAreaContext *context,
+ GtkWidget *widget,
+ const GdkRectangle *cell_area,
+ gint x,
+ gint y,
+ GdkRectangle *alloc_area)
+{
+ CellByPositionData data = { x, y, NULL, { 0, } };
+
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
+ g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+ g_return_val_if_fail (cell_area != NULL, NULL);
+ g_return_val_if_fail (x >= cell_area->x && x <= cell_area->x + cell_area->width, NULL);
+ g_return_val_if_fail (y >= cell_area->y && y <= cell_area->y + cell_area->height, NULL);
+
+ gtk_cell_area_foreach_alloc (area, context, widget, cell_area, cell_area,
+ (GtkCellAllocCallback)get_cell_by_position, &data);
+
+ if (alloc_area)
+ *alloc_area = data.cell_area;
+
+ return data.renderer;
+}
+
/*************************************************************
* API: Geometry *
*************************************************************/
* one should render and handle events with the same #GtkCellAreaContext
* which was used to request the size of those rows of data).
*
- * Returns: a newly created #GtkCellAreaContext which can be used with @area.
+ * Return value: (transfer full): a newly created #GtkCellAreaContext which can be used with @area.
+ *
+ * Since: 3.0
*/
GtkCellAreaContext *
gtk_cell_area_create_context (GtkCellArea *area)
return NULL;
}
+/**
+ * gtk_cell_area_copy_context:
+ * @area: a #GtkCellArea
+ * @context: the #GtkCellAreaContext to copy
+ *
+ * This is sometimes needed for cases where rows need to share
+ * alignments in one orientation but may be separately grouped
+ * in the opposing orientation.
+ *
+ * For instance, #GtkIconView creates all icons (rows) to have
+ * the same width and the cells theirin to have the same
+ * horizontal alignments. However each row of icons may have
+ * a separate collective height. #GtkIconView uses this to
+ * request the heights of each row based on a context which
+ * was already used to request all the row widths that are
+ * to be displayed.
+ *
+ * Return value: (transfer full): a newly created #GtkCellAreaContext copy of @context.
+ *
+ * Since: 3.0
+ */
+GtkCellAreaContext *
+gtk_cell_area_copy_context (GtkCellArea *area,
+ GtkCellAreaContext *context)
+{
+ GtkCellAreaClass *class;
+
+ g_return_val_if_fail (GTK_IS_CELL_AREA (area), NULL);
+ g_return_val_if_fail (GTK_IS_CELL_AREA_CONTEXT (context), NULL);
+
+ class = GTK_CELL_AREA_GET_CLASS (area);
+
+ if (class->copy_context)
+ return class->copy_context (area, context);
+
+ g_warning ("GtkCellAreaClass::copy_context not implemented for `%s'",
+ g_type_name (G_TYPE_FROM_INSTANCE (area)));
+
+ return NULL;
+}
/**
* gtk_cell_area_get_request_mode:
* Gets whether the area prefers a height-for-width layout
* or a width-for-height layout.
*
- * Returns: The #GtkSizeRequestMode preferred by @area.
+ * Return value: The #GtkSizeRequestMode preferred by @area.
*
* Since: 3.0
*/
* consult gtk_cell_area_context_get_preferred_width() after a series of
* requests.
*
- *
* Since: 3.0
*/
void
*
* Connects an @attribute to apply values from @column for the
* #GtkTreeModel in use.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_attribute_connect (GtkCellArea *area,
* Disconnects @attribute for the @renderer in @area so that
* attribute will no longer be updated with values from the
* model.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_attribute_disconnect (GtkCellArea *area,
/**
* gtk_cell_area_apply_attributes
* @area: a #GtkCellArea
- * @tree_model: a #GtkTreeModel to pull values from
+ * @tree_model: the #GtkTreeModel to pull values from
* @iter: the #GtkTreeIter in @tree_model to apply values for
* @is_expander: whether @iter has children
* @is_expanded: whether @iter is expanded in the view and
*
* Applies any connected attributes to the renderers in
* @area by pulling the values from @tree_model.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_apply_attributes (GtkCellArea *area,
* gtk_cell_area_apply_attributes() is called and can be
* used to interact with renderers from #GtkCellArea
* subclasses.
+ *
+ * Return value: The current #GtkTreePath string for the current
+ * attributes applied to @area. This string belongs to the area and
+ * should not be freed.
+ *
+ * Since: 3.0
*/
-const gchar *
+G_CONST_RETURN gchar *
gtk_cell_area_get_current_path_string (GtkCellArea *area)
{
GtkCellAreaPrivate *priv;
* @pspec: the #GParamSpec for the property
*
* Installs a cell property on a cell area class.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_class_install_cell_property (GtkCellAreaClass *aclass,
* gtk_cell_area_class_find_cell_property:
* @aclass: a #GtkCellAreaClass
* @property_name: the name of the child property to find
- * @returns: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
- * child property with that name.
*
* Finds a cell property of a cell area class by name.
+ *
+ * Return value: (allow-none): the #GParamSpec of the child property or %NULL if @aclass has no
+ * child property with that name.
+ *
+ * Since: 3.0
*/
GParamSpec*
gtk_cell_area_class_find_cell_property (GtkCellAreaClass *aclass,
* gtk_cell_area_class_list_cell_properties:
* @aclass: a #GtkCellAreaClass
* @n_properties: location to return the number of cell properties found
- * @returns: a newly allocated %NULL-terminated array of #GParamSpec*.
- * The array must be freed with g_free().
*
* Returns all cell properties of a cell area class.
+ *
+ * Return value: a newly allocated %NULL-terminated array of #GParamSpec*.
+ * The array must be freed with g_free().
+ *
+ * Since: 3.0
*/
GParamSpec**
gtk_cell_area_class_list_cell_properties (GtkCellAreaClass *aclass,
*
* Adds @renderer to @area, setting cell properties at the same time.
* See gtk_cell_area_add() and gtk_cell_area_child_set() for more details.
- **/
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_add_with_properties (GtkCellArea *area,
GtkCellRenderer *renderer,
* with @first_prop_name
*
* Sets one or more cell properties for @cell in @area.
- **/
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_cell_set (GtkCellArea *area,
GtkCellRenderer *renderer,
* optionally by more name/return location pairs, followed by %NULL
*
* Gets the values of one or more cell properties for @renderer in @area.
- **/
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_cell_get (GtkCellArea *area,
GtkCellRenderer *renderer,
* with @first_prop_name
*
* Sets one or more cell properties for @renderer in @area.
- **/
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_cell_set_valist (GtkCellArea *area,
GtkCellRenderer *renderer,
* optionally by more name/return location pairs, followed by %NULL
*
* Gets the values of one or more cell properties for @renderer in @area.
- **/
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_cell_get_valist (GtkCellArea *area,
GtkCellRenderer *renderer,
* @value: the value to set the cell property to
*
* Sets a cell property for @renderer in @area.
- **/
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_cell_set_property (GtkCellArea *area,
GtkCellRenderer *renderer,
* @value: a location to return the value
*
* Gets the value of a cell property for @renderer in @area.
- **/
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_cell_get_property (GtkCellArea *area,
GtkCellRenderer *renderer,
* Returns whether the area can do anything when activated,
* after applying new attributes to @area.
*
- * Returns: whether @area can do anything when activated.
+ * Return value: whether @area can do anything when activated.
+ *
+ * Since: 3.0
*/
gboolean
gtk_cell_area_is_activatable (GtkCellArea *area)
* method to receive and navigate focus in it's own way particular
* to how it lays out cells.
*
- * Returns: %TRUE if focus remains inside @area as a result of this call.
+ * Return value: %TRUE if focus remains inside @area as a result of this call.
+ *
+ * Since: 3.0
*/
gboolean
gtk_cell_area_focus (GtkCellArea *area,
* @widget: the #GtkWidget that @area is rendering on
* @cell_area: the size and location of @area relative to @widget's allocation
* @flags: the #GtkCellRendererState flags for @area for this row of data.
+ * @edit_only: if %TRUE then only cell renderers that are %GTK_CELL_RENDERER_MODE_EDITABLE
+ * will be activated.
*
* Activates @area, usually by activating the currently focused
* cell, however some subclasses which embed widgets in the area
* can also activate a widget if it currently has the focus.
*
- * Returns: Whether @area was successfully activated.
+ * Return value: Whether @area was successfully activated.
+ *
+ * Since: 3.0
*/
gboolean
gtk_cell_area_activate (GtkCellArea *area,
GtkCellAreaContext *context,
GtkWidget *widget,
const GdkRectangle *cell_area,
- GtkCellRendererState flags)
+ GtkCellRendererState flags,
+ gboolean edit_only)
{
g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
- return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags);
+ return GTK_CELL_AREA_GET_CLASS (area)->activate (area, context, widget, cell_area, flags, edit_only);
}
* is called. It's also up to the #GtkCellArea implementation
* to update the focused cell when receiving events from
* gtk_cell_area_event() appropriately.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_set_focus_cell (GtkCellArea *area,
*
* Retrieves the currently focused cell for @area
*
- * Returns: the currently focused cell in @area.
+ * Return value: the currently focused cell in @area.
+ *
+ * Since: 3.0
*/
GtkCellRenderer *
gtk_cell_area_get_focus_cell (GtkCellArea *area)
*
* Events handled by focus siblings can also activate the given
* focusable @renderer.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_add_focus_sibling (GtkCellArea *area,
*
* Removes @sibling from @renderer's focus sibling list
* (see gtk_cell_area_add_focus_sibling()).
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_remove_focus_sibling (GtkCellArea *area,
*
* Returns %TRUE if @sibling is one of @renderer's focus siblings
* (see gtk_cell_area_add_focus_sibling()).
+ *
+ * Since: 3.0
*/
gboolean
gtk_cell_area_is_focus_sibling (GtkCellArea *area,
*
* Gets the focus sibling cell renderers for @renderer.
*
- * Returns: A #GList of #GtkCellRenderers. The returned list is internal and should not be freed.
+ * Return value: (element-type GtkCellRenderer) (transfer none): A #GList of #GtkCellRenderers.
+ * The returned list is internal and should not be freed.
+ *
+ * Since: 3.0
*/
const GList *
gtk_cell_area_get_focus_siblings (GtkCellArea *area,
* then chose to activate the focus cell for which the event
* cell may have been a sibling.
*
- * Returns: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
+ * Return value: the #GtkCellRenderer for which @renderer is a sibling, or %NULL.
+ *
+ * Since: 3.0
*/
GtkCellRenderer *
gtk_cell_area_get_focus_from_sibling (GtkCellArea *area,
gtk_cell_area_add_editable (GtkCellArea *area,
GtkCellRenderer *renderer,
GtkCellEditable *editable,
- GdkRectangle *cell_area)
+ const GdkRectangle *cell_area)
{
g_signal_emit (area, cell_area_signals[SIGNAL_ADD_EDITABLE], 0,
renderer, editable, cell_area, area->priv->current_path);
* Gets the #GtkCellRenderer in @area that is currently
* being edited.
*
- * Returns: The currently edited #GtkCellRenderer
+ * Return value: The currently edited #GtkCellRenderer
+ *
+ * Since: 3.0
*/
GtkCellRenderer *
gtk_cell_area_get_edited_cell (GtkCellArea *area)
* Gets the #GtkCellEditable widget currently used
* to edit the currently edited cell.
*
- * Returns: The currently active #GtkCellEditable widget
+ * Return value: The currently active #GtkCellEditable widget
+ *
+ * Since: 3.0
*/
GtkCellEditable *
gtk_cell_area_get_edit_widget (GtkCellArea *area)
* for keyboard events for free in it's own GtkCellArea->activate()
* implementation.
*
- * Returns: whether cell activation was successful
+ * Return value: whether cell activation was successful
+ *
+ * Since: 3.0
*/
gboolean
gtk_cell_area_activate_cell (GtkCellArea *area,
GtkCellRendererState flags)
{
GtkCellRendererMode mode;
- GdkRectangle inner_area;
GtkCellAreaPrivate *priv;
g_return_val_if_fail (GTK_IS_CELL_AREA (area), FALSE);
priv = area->priv;
- /* Remove margins from the background area to produce the cell area.
- *
- * XXX Maybe have to do some rtl mode treatment here...
- */
- gtk_cell_area_inner_cell_area (area, widget, cell_area, &inner_area);
-
g_object_get (renderer, "mode", &mode, NULL);
if (mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE)
event, widget,
priv->current_path,
cell_area,
- &inner_area,
+ cell_area,
flags))
return TRUE;
}
event, widget,
priv->current_path,
cell_area,
- &inner_area,
+ cell_area,
flags);
if (editable_widget != NULL)
/* Signal that editing started so that callers can get
* a handle on the editable_widget */
- gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, &inner_area);
+ gtk_cell_area_add_editable (area, priv->focus_cell, editable_widget, cell_area);
/* If the signal was successfully handled start the editing */
if (gtk_widget_get_parent (GTK_WIDGET (editable_widget)))
*
* If @canceled is %TRUE, the cell renderer will emit
* the ::editing-canceled signal.
+ *
+ * Since: 3.0
*/
void
gtk_cell_area_stop_editing (GtkCellArea *area,
* API: Convenience for area implementations *
*************************************************************/
+/**
+ * gtk_cell_area_inner_cell_area:
+ * @area: a #GtkCellArea
+ * @widget: the #GtkWidget that @area is rendering onto
+ * @cell_area: the @widget relative coordinates where one of @area's cells
+ * is to be placed
+ * @inner_area: (out): the return location for the inner cell area
+ *
+ * This is a convenience function for #GtkCellArea implementations
+ * to get the inner area where a given #GtkCellRenderer will be
+ * rendered. It removes any padding previously added by gtk_cell_area_request_renderer().
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_inner_cell_area (GtkCellArea *area,
GtkWidget *widget,
inner_area->height -= focus_line_width * 2;
}
+/**
+ * gtk_cell_area_request_renderer:
+ * @area: a #GtkCellArea
+ * @renderer: the #GtkCellRenderer to request size for
+ * @orientation: the #GtkOrientation in which to request size
+ * @widget: the #GtkWidget that @area is rendering onto
+ * @for_size: the allocation contextual size to request for, or -1 if
+ * the base request for the orientation is to be returned.
+ * @minimum_size: (out) (allow-none): location to store the minimum size, or %NULL
+ * @natural_size: (out) (allow-none): location to store the natural size, or %NULL
+ *
+ * This is a convenience function for #GtkCellArea implementations
+ * to request size for cell renderers. It's important to use this
+ * function to request size and then use gtk_cell_area_inner_cell_area()
+ * at render and event time since this function will add padding
+ * around the cell for focus painting.
+ *
+ * Since: 3.0
+ */
void
gtk_cell_area_request_renderer (GtkCellArea *area,
GtkCellRenderer *renderer,