* Boston, MA 02111-1307, USA.
*/
-#include <config.h>
-#include <string.h>
+#include "config.h"
+
#include "gtktreeviewcolumn.h"
+
+#include <string.h>
+
#include "gtktreeview.h"
#include "gtktreeprivate.h"
#include "gtkcelllayout.h"
#include "gtkarrow.h"
#include "gtkprivate.h"
#include "gtkintl.h"
-#include "gtkalias.h"
+
+
+/**
+ * SECTION:gtktreeviewcolumn
+ * @Short_description: A visible column in a GtkTreeView widget
+ * @Title: GtkTreeViewColumn
+ * @See_also: #GtkTreeView, #GtkTreeSelection, #GtkTreeDnd, #GtkTreeMode, #GtkTreeSortable,
+ * #GtkTreeModelSort, #GtkListStore, #GtkTreeStore, #GtkCellRenderer, #GtkCellEditable,
+ * #GtkCellRendererPixbuf, #GtkCellRendererText, #GtkCellRendererToggle
+ *
+ * The GtkTreeViewColumn object represents a visible column in a #GtkTreeView widget.
+ * It allows to set properties of the column header, and functions as a holding pen for
+ * the cell renderers which determine how the data in the column is displayed.
+ *
+ * Please refer to the <link linkend="TreeWidget">tree widget conceptual overview</link>
+ * for an overview of all the objects and data types related to the tree widget and how
+ * they work together.
+ */
+
enum
{
PROP_ALIGNMENT,
PROP_REORDERABLE,
PROP_SORT_INDICATOR,
- PROP_SORT_ORDER
+ PROP_SORT_ORDER,
+ PROP_SORT_COLUMN_ID
};
enum
GSList *attributes;
GtkTreeCellDataFunc func;
gpointer func_data;
- GtkDestroyNotify destroy;
+ GDestroyNotify destroy;
gint requested_width;
gint real_width;
guint expand : 1;
};
/* Type methods */
-static void gtk_tree_view_column_init (GtkTreeViewColumn *tree_column);
-static void gtk_tree_view_column_class_init (GtkTreeViewColumnClass *klass);
static void gtk_tree_view_column_cell_layout_init (GtkCellLayoutIface *iface);
/* GObject methods */
static void gtk_tree_view_column_cell_layout_reorder (GtkCellLayout *cell_layout,
GtkCellRenderer *cell,
gint position);
+static GList *gtk_tree_view_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
/* Button handling code */
static void gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column);
GList *current);
static void gtk_tree_view_column_clear_attributes_by_info (GtkTreeViewColumn *tree_column,
GtkTreeViewColumnCellInfo *info);
+/* GtkBuildable implementation */
+static void gtk_tree_view_column_buildable_init (GtkBuildableIface *iface);
-static GtkObjectClass *parent_class = NULL;
static guint tree_column_signals[LAST_SIGNAL] = { 0 };
+G_DEFINE_TYPE_WITH_CODE (GtkTreeViewColumn, gtk_tree_view_column, G_TYPE_INITIALLY_UNOWNED,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
+ gtk_tree_view_column_cell_layout_init)
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
+ gtk_tree_view_column_buildable_init))
-GType
-gtk_tree_view_column_get_type (void)
-{
- static GType tree_column_type = 0;
-
- if (!tree_column_type)
- {
- static const GTypeInfo tree_column_info =
- {
- sizeof (GtkTreeViewColumnClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_tree_view_column_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkTreeViewColumn),
- 0,
- (GInstanceInitFunc) gtk_tree_view_column_init
- };
-
- static const GInterfaceInfo cell_layout_info =
- {
- (GInterfaceInitFunc) gtk_tree_view_column_cell_layout_init,
- NULL,
- NULL
- };
-
- tree_column_type =
- g_type_register_static (GTK_TYPE_OBJECT, "GtkTreeViewColumn",
- &tree_column_info, 0);
-
- g_type_add_interface_static (tree_column_type,
- GTK_TYPE_CELL_LAYOUT,
- &cell_layout_info);
- }
-
- return tree_column_type;
-}
static void
gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
object_class = (GObjectClass*) class;
- parent_class = g_type_class_peek_parent (class);
-
class->clicked = NULL;
object_class->finalize = gtk_tree_view_column_finalize;
object_class->get_property = gtk_tree_view_column_get_property;
tree_column_signals[CLICKED] =
- g_signal_new ("clicked",
+ g_signal_new (I_("clicked"),
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GtkTreeViewColumnClass, clicked),
GTK_TYPE_SORT_TYPE,
GTK_SORT_ASCENDING,
GTK_PARAM_READWRITE));
-
+
+ /**
+ * GtkTreeViewColumn:sort-column-id:
+ *
+ * Logical sort column ID this column sorts on when selected for sorting. Setting the sort column ID makes the column header
+ * clickable. Set to %-1 to make the column unsortable.
+ *
+ * Since: 2.18
+ **/
+ g_object_class_install_property (object_class,
+ PROP_SORT_COLUMN_ID,
+ g_param_spec_int ("sort-column-id",
+ P_("Sort column ID"),
+ P_("Logical sort column ID this column sorts on when selected for sorting"),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
+}
+
+static void
+gtk_tree_view_column_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_layout_buildable_custom_tag_end;
}
static void
iface->set_cell_data_func = gtk_tree_view_column_cell_layout_set_cell_data_func;
iface->clear_attributes = gtk_tree_view_column_cell_layout_clear_attributes;
iface->reorder = gtk_tree_view_column_cell_layout_reorder;
+ iface->get_cells = gtk_tree_view_column_cell_layout_get_cells;
}
static void
if (info->destroy)
{
- GtkDestroyNotify d = info->destroy;
+ GDestroyNotify d = info->destroy;
info->destroy = NULL;
d (info->func_data);
if (tree_column->child)
g_object_unref (tree_column->child);
- G_OBJECT_CLASS (parent_class)->finalize (object);
+ G_OBJECT_CLASS (gtk_tree_view_column_parent_class)->finalize (object);
}
static void
g_value_get_enum (value));
break;
+ case PROP_SORT_COLUMN_ID:
+ gtk_tree_view_column_set_sort_column_id (tree_column,
+ g_value_get_int (value));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
gtk_tree_view_column_get_sort_order (tree_column));
break;
+ case PROP_SORT_COLUMN_ID:
+ g_value_set_int (value,
+ gtk_tree_view_column_get_sort_column_id (tree_column));
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
column = GTK_TREE_VIEW_COLUMN (cell_layout);
g_return_if_fail (! gtk_tree_view_column_get_cell_info (column, cell));
- g_object_ref (cell);
- gtk_object_sink (GTK_OBJECT (cell));
+ g_object_ref_sink (cell);
cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
cell_info->cell = cell;
column = GTK_TREE_VIEW_COLUMN (cell_layout);
g_return_if_fail (! gtk_tree_view_column_get_cell_info (column, cell));
- g_object_ref (cell);
- gtk_object_sink (GTK_OBJECT (cell));
+ g_object_ref_sink (cell);
cell_info = g_new0 (GtkTreeViewColumnCellInfo, 1);
cell_info->cell = cell;
g_return_if_fail (link != NULL);
- column->cell_list = g_list_remove_link (column->cell_list, link);
+ column->cell_list = g_list_delete_link (column->cell_list, link);
column->cell_list = g_list_insert (column->cell_list, info, position);
- gtk_widget_queue_draw (column->tree_view);
+ if (column->tree_view)
+ gtk_widget_queue_draw (column->tree_view);
}
static void
gtk_widget_show (child);
}
- g_signal_connect (child, "mnemonic_activate",
+ g_signal_connect (child, "mnemonic-activate",
G_CALLBACK (gtk_tree_view_column_mnemonic_activate),
tree_column);
static void
gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
{
+ gint sort_column_id = -1;
GtkWidget *hbox;
GtkWidget *alignment;
GtkWidget *arrow;
GtkWidget *current_child;
+ GtkArrowType arrow_type = GTK_ARROW_NONE;
+ GtkTreeModel *model;
+
+ if (tree_column->tree_view)
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
+ else
+ model = NULL;
/* Create a button if necessary */
if (tree_column->visible &&
tree_column->button == NULL &&
tree_column->tree_view &&
- GTK_WIDGET_REALIZED (tree_column->tree_view))
+ gtk_widget_get_realized (tree_column->tree_view))
gtk_tree_view_column_create_button (tree_column);
if (! tree_column->button)
return;
- hbox = GTK_BIN (tree_column->button)->child;
+ hbox = gtk_bin_get_child (GTK_BIN (tree_column->button));
alignment = tree_column->alignment;
arrow = tree_column->arrow;
- current_child = GTK_BIN (alignment)->child;
+ current_child = gtk_bin_get_child (GTK_BIN (alignment));
/* Set up the actual button */
gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
"");
}
- switch (tree_column->sort_order)
+ if (GTK_IS_TREE_SORTABLE (model))
+ gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
+ &sort_column_id,
+ NULL);
+
+ if (tree_column->show_sort_indicator)
{
- case GTK_SORT_ASCENDING:
- gtk_arrow_set (GTK_ARROW (arrow),
- GTK_ARROW_DOWN,
- GTK_SHADOW_IN);
- break;
+ gboolean alternative;
- case GTK_SORT_DESCENDING:
- gtk_arrow_set (GTK_ARROW (arrow),
- GTK_ARROW_UP,
- GTK_SHADOW_IN);
- break;
-
- default:
- g_warning (G_STRLOC": bad sort order");
- break;
+ g_object_get (gtk_widget_get_settings (tree_column->tree_view),
+ "gtk-alternative-sort-arrows", &alternative,
+ NULL);
+
+ switch (tree_column->sort_order)
+ {
+ case GTK_SORT_ASCENDING:
+ arrow_type = alternative ? GTK_ARROW_UP : GTK_ARROW_DOWN;
+ break;
+
+ case GTK_SORT_DESCENDING:
+ arrow_type = alternative ? GTK_ARROW_DOWN : GTK_ARROW_UP;
+ break;
+
+ default:
+ g_warning (G_STRLOC": bad sort order");
+ break;
+ }
}
+ gtk_arrow_set (GTK_ARROW (arrow),
+ arrow_type,
+ GTK_SHADOW_IN);
+
/* Put arrow on the right if the text is left-or-center justified, and on the
* left otherwise; do this by packing boxes, so flipping text direction will
* reverse things
}
g_object_unref (arrow);
- if (tree_column->show_sort_indicator)
+ if (tree_column->show_sort_indicator
+ || (GTK_IS_TREE_SORTABLE (model) && tree_column->sort_column_id >= 0))
gtk_widget_show (arrow);
else
gtk_widget_hide (arrow);
* if you show it before it's realized, it'll get the wrong window. */
if (tree_column->button &&
tree_column->tree_view != NULL &&
- GTK_WIDGET_REALIZED (tree_column->tree_view))
+ gtk_widget_get_realized (tree_column->tree_view))
{
if (tree_column->visible)
{
if (tree_column->reorderable || tree_column->clickable)
{
- GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
+ gtk_widget_set_can_focus (tree_column->button, TRUE);
}
else
{
- GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
- if (GTK_WIDGET_HAS_FOCUS (tree_column->button))
+ gtk_widget_set_can_focus (tree_column->button, FALSE);
+ if (gtk_widget_has_focus (tree_column->button))
{
GtkWidget *toplevel = gtk_widget_get_toplevel (tree_column->tree_view);
- if (GTK_WIDGET_TOPLEVEL (toplevel))
+ if (gtk_widget_is_toplevel (toplevel))
{
gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
}
/* Queue a resize on the assumption that we always want to catch all changes
* and columns don't change all that often.
*/
- if (GTK_WIDGET_REALIZED (tree_column->tree_view))
+ if (gtk_widget_get_realized (tree_column->tree_view))
gtk_widget_queue_resize (tree_column->tree_view);
}
((GdkEventButton *)event)->button == 1)
{
column->maybe_reordered = TRUE;
- gdk_window_get_pointer (widget->window,
+ gdk_window_get_pointer (GTK_BUTTON (widget)->event_window,
&column->drag_x,
&column->drag_y,
NULL);
(gint) ((GdkEventMotion *)event)->y)))
{
column->maybe_reordered = FALSE;
- /* this is to change our drag_x to be relative to
- * tree_view->priv->bin_window, instead of our window.
- */
- column->drag_x -= column->button->allocation.x;
- _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column);
+ _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view), column,
+ event->motion.device);
return TRUE;
}
if (column->clickable == FALSE)
GTK_TREE_VIEW (column->tree_view)->priv->focus_column = column;
if (column->clickable)
gtk_button_clicked (GTK_BUTTON (column->button));
- else if (GTK_WIDGET_CAN_FOCUS (column->button))
+ else if (gtk_widget_get_can_focus (column->button))
gtk_widget_grab_focus (column->button);
else
gtk_widget_grab_focus (column->tree_view);
if (tree_column->sort_column_changed_signal == 0)
tree_column->sort_column_changed_signal =
- g_signal_connect (model, "sort_column_changed",
+ g_signal_connect (model, "sort-column-changed",
G_CALLBACK (gtk_tree_view_model_sort_column_changed),
tree_column);
void
_gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
{
+ GtkAllocation allocation;
GtkTreeView *tree_view;
GdkWindowAttr attr;
guint attributes_mask;
rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
- g_return_if_fail (GTK_WIDGET_REALIZED (tree_view));
+ g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (tree_view)));
g_return_if_fail (tree_view->priv->header_window != NULL);
g_return_if_fail (column->button != NULL);
attr.window_type = GDK_WINDOW_CHILD;
attr.wclass = GDK_INPUT_ONLY;
attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
- attr.colormap = gtk_widget_get_colormap (GTK_WIDGET (tree_view));
attr.event_mask = gtk_widget_get_events (GTK_WIDGET (tree_view)) |
(GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_HINT_MASK |
GDK_KEY_PRESS_MASK);
attributes_mask = GDK_WA_CURSOR | GDK_WA_X | GDK_WA_Y;
- attr.cursor = gdk_cursor_new_for_display (gdk_drawable_get_display (tree_view->priv->header_window),
+ attr.cursor = gdk_cursor_new_for_display (gdk_window_get_display (tree_view->priv->header_window),
GDK_SB_H_DOUBLE_ARROW);
attr.y = 0;
attr.width = TREE_VIEW_DRAG_WIDTH;
attr.height = tree_view->priv->header_height;
- attr.x = (column->button->allocation.x + (rtl ? 0 : column->button->allocation.width)) - 3;
+ gtk_widget_get_allocation (column->button, &allocation);
+ attr.x = (allocation.x + (rtl ? 0 : allocation.width)) - TREE_VIEW_DRAG_WIDTH / 2;
column->window = gdk_window_new (tree_view->priv->header_window,
&attr, attributes_mask);
gdk_window_set_user_data (column->window, tree_view);
gboolean
_gtk_tree_view_column_has_editable_cell (GtkTreeViewColumn *column)
{
+ GtkCellRenderer *cell;
+ GtkCellRendererMode mode;
GList *list;
for (list = column->cell_list; list; list = list->next)
- if (((GtkTreeViewColumnCellInfo *)list->data)->cell->mode ==
- GTK_CELL_RENDERER_MODE_EDITABLE)
- return TRUE;
+ {
+ cell = ((GtkTreeViewColumnCellInfo *)list->data)->cell;
+ g_object_get (cell, "mode", &mode, NULL);
+ if (mode == GTK_CELL_RENDERER_MODE_EDITABLE)
+ return TRUE;
+ }
return FALSE;
}
for (list = column->cell_list; list; list = list->next)
{
+ GtkCellRendererMode mode;
GtkTreeViewColumnCellInfo *cellinfo = list->data;
- if ((cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
- cellinfo->cell->mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
- cellinfo->cell->visible)
+ g_object_get (cellinfo->cell, "mode", &mode, NULL);
+ if ((mode == GTK_CELL_RENDERER_MODE_EDITABLE ||
+ mode == GTK_CELL_RENDERER_MODE_ACTIVATABLE) &&
+ gtk_cell_renderer_get_visible (cellinfo->cell))
i++;
}
* gtk_tree_view_column_set_attributes() on the newly created #GtkTreeViewColumn.
*
* Here's a simple example:
- * <informalexample><programlisting>
+ * |[
* enum { TEXT_COLUMN, COLOR_COLUMN, N_COLUMNS };
* ...
* {
* GtkTreeViewColumn *column;
- * GtkCellRenderer *renderer = gtk_cell_renderer_text_new (<!-- -->);
+ * GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
*
* column = gtk_tree_view_column_new_with_attributes ("Title",
* renderer,
* "foreground", COLOR_COLUMN,
* NULL);
* }
- * </programlisting></informalexample>
+ * ]|
*
* Return value: A newly created #GtkTreeViewColumn.
**/
gtk_cell_layout_clear (GTK_CELL_LAYOUT (tree_column));
}
-/**
- * gtk_tree_view_column_get_cell_renderers:
- * @tree_column: A #GtkTreeViewColumn
- *
- * Returns a newly-allocated #GList of all the cell renderers in the column,
- * in no particular order. The list must be freed with g_list_free().
- *
- * Return value: A list of #GtkCellRenderers
- **/
-GList *
-gtk_tree_view_column_get_cell_renderers (GtkTreeViewColumn *tree_column)
+static GList *
+gtk_tree_view_column_cell_layout_get_cells (GtkCellLayout *layout)
{
+ GtkTreeViewColumn *tree_column = GTK_TREE_VIEW_COLUMN (layout);
GList *retval = NULL, *list;
g_return_val_if_fail (tree_column != NULL, NULL);
GtkCellRenderer *cell_renderer,
GtkTreeCellDataFunc func,
gpointer func_data,
- GtkDestroyNotify destroy)
+ GDestroyNotify destroy)
{
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (tree_column),
cell_renderer,
tree_column->use_resized_width = FALSE;
if (tree_column->tree_view &&
- GTK_WIDGET_REALIZED (tree_column->tree_view) &&
+ gtk_widget_get_realized (tree_column->tree_view) &&
tree_column->column_type == GTK_TREE_VIEW_COLUMN_FIXED)
{
gtk_widget_queue_resize (tree_column->tree_view);
if (tree_column->visible &&
tree_column->tree_view != NULL &&
- GTK_WIDGET_REALIZED (tree_column->tree_view))
+ gtk_widget_get_realized (tree_column->tree_view))
{
if (min_width > tree_column->width)
gtk_widget_queue_resize (tree_column->tree_view);
if (tree_column->visible &&
tree_column->tree_view != NULL &&
- GTK_WIDGET_REALIZED (tree_column->tree_view))
+ gtk_widget_get_realized (tree_column->tree_view))
{
if (max_width != -1 && max_width < tree_column->width)
gtk_widget_queue_resize (tree_column->tree_view);
if (tree_column->visible &&
tree_column->tree_view != NULL &&
- GTK_WIDGET_REALIZED (tree_column->tree_view))
+ gtk_widget_get_realized (tree_column->tree_view))
{
+ /* We want to continue using the original width of the
+ * column that includes additional space added by the user
+ * resizing the columns and possibly extra (expanded) space, which
+ * are not included in the resized width.
+ */
+ tree_column->use_resized_width = FALSE;
+
gtk_widget_queue_resize (tree_column->tree_view);
}
/**
* gtk_tree_view_column_set_widget:
* @tree_column: A #GtkTreeViewColumn.
- * @widget: A child #GtkWidget, or %NULL.
- *
+ * @widget: (allow-none): A child #GtkWidget, or %NULL.
+ *
* Sets the widget in the header to be @widget. If widget is %NULL, then the
* header button is set with a #GtkLabel set to the title of @tree_column.
**/
g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
if (widget)
- {
- g_object_ref (widget);
- gtk_object_sink (GTK_OBJECT (widget));
- }
+ g_object_ref_sink (widget);
if (tree_column->child)
g_object_unref (tree_column->child);
/**
* gtk_tree_view_column_get_widget:
* @tree_column: A #GtkTreeViewColumn.
- *
- * Returns the #GtkWidget in the button on the column header. If a custom
- * widget has not been set then %NULL is returned.
- *
- * Return value: The #GtkWidget in the column header, or %NULL
+ *
+ * Returns the #GtkWidget in the button on the column header.
+ * If a custom widget has not been set then %NULL is returned.
+ *
+ * Return value: (transfer none): The #GtkWidget in the column
+ * header, or %NULL
**/
GtkWidget *
gtk_tree_view_column_get_widget (GtkTreeViewColumn *tree_column)
gtk_tree_view_column_set_sort_order (tree_column, GTK_SORT_ASCENDING);
gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
gtk_tree_view_column_set_clickable (tree_column, FALSE);
+ g_object_notify (G_OBJECT (tree_column), "sort-column-id");
return;
}
NULL);
gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
+ g_object_notify (G_OBJECT (tree_column), "sort-column-id");
}
/**
GSList *list;
GValue value = { 0, };
GList *cell_list;
+ gboolean cell_is_expander, cell_is_expanded;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
g_object_freeze_notify (cell);
- if (info->cell->is_expander != is_expander)
+ g_object_get (cell, "is-expander", &cell_is_expander, NULL);
+ if (cell_is_expander != is_expander)
g_object_set (cell, "is-expander", is_expander, NULL);
- if (info->cell->is_expanded != is_expanded)
+ g_object_get (cell, "is-expanded", &cell_is_expanded, NULL);
+ if (cell_is_expanded != is_expanded)
g_object_set (cell, "is-expanded", is_expanded, NULL);
while (list && list->next)
/**
* gtk_tree_view_column_cell_get_size:
* @tree_column: A #GtkTreeViewColumn.
- * @cell_area: The area a cell in the column will be allocated, or %NULL
- * @x_offset: location to return x offset of a cell relative to @cell_area, or %NULL
- * @y_offset: location to return y offset of a cell relative to @cell_area, or %NULL
- * @width: location to return width needed to render a cell, or %NULL
- * @height: location to return height needed to render a cell, or %NULL
+ * @cell_area: (allow-none): The area a cell in the column will be allocated, or %NULL
+ * @x_offset: (allow-none): location to return x offset of a cell relative to @cell_area, or %NULL
+ * @y_offset: (allow-none): location to return y offset of a cell relative to @cell_area, or %NULL
+ * @width: (allow-none): location to return width needed to render a cell, or %NULL
+ * @height: (allow-none): location to return height needed to render a cell, or %NULL
*
* Obtains the width and height needed to render the column. This is used
* primarily by the #GtkTreeView.
**/
void
-gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
- GdkRectangle *cell_area,
- gint *x_offset,
- gint *y_offset,
- gint *width,
- gint *height)
-{
+gtk_tree_view_column_cell_get_size (GtkTreeViewColumn *tree_column,
+ const GdkRectangle *cell_area,
+ gint *x_offset,
+ gint *y_offset,
+ gint *width,
+ gint *height)
+{
+ GtkRequisition min_size;
GList *list;
gboolean first_cell = TRUE;
gint focus_line_width;
{
GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
gboolean visible;
- gint new_height = 0;
- gint new_width = 0;
g_object_get (info->cell, "visible", &visible, NULL);
if (visible == FALSE)
if (first_cell == FALSE && width)
*width += tree_column->spacing;
- gtk_cell_renderer_get_size (info->cell,
- tree_column->tree_view,
- cell_area,
- x_offset,
- y_offset,
- &new_width,
- &new_height);
+ gtk_cell_renderer_get_preferred_size (info->cell,
+ GTK_WIDGET (tree_column->tree_view),
+ &min_size, NULL);
if (height)
- * height = MAX (*height, new_height + focus_line_width * 2);
- info->requested_width = MAX (info->requested_width, new_width + focus_line_width * 2);
+ * height = MAX (*height, min_size.height + focus_line_width * 2);
+ info->requested_width = MAX (info->requested_width, min_size.width + focus_line_width * 2);
if (width)
* width += info->requested_width;
first_cell = FALSE;
static gboolean
gtk_tree_view_column_cell_process_action (GtkTreeViewColumn *tree_column,
- GdkWindow *window,
- GdkRectangle *background_area,
- GdkRectangle *cell_area,
+ cairo_t *cr,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
guint flags,
gint action,
- GdkRectangle *expose_area, /* RENDER */
GdkRectangle *focus_rectangle, /* FOCUS */
GtkCellEditable **editable_widget, /* EVENT */
GdkEvent *event, /* EVENT */
GList *list;
GdkRectangle real_cell_area;
GdkRectangle real_background_area;
- GdkRectangle real_expose_area = *cell_area;
gint depth = 0;
gint expand_cell_count = 0;
gint full_requested_width = 0;
gint special_cells;
gint horizontal_separator;
gboolean cursor_row = FALSE;
+ gboolean first_cell = TRUE;
gboolean rtl;
/* If we have rtl text, we need to transform our areas */
GdkRectangle rtl_cell_area;
real_cell_area = *cell_area;
real_background_area = *background_area;
- depth = real_cell_area.x - real_background_area.x - horizontal_separator/2;
real_cell_area.x += focus_line_width;
real_cell_area.y += focus_line_width;
real_cell_area.height -= 2 * focus_line_width;
+ if (rtl)
+ depth = real_background_area.width - real_cell_area.width;
+ else
+ depth = real_cell_area.x - real_background_area.x;
+
/* Find out how much extra space we have to allocate */
for (list = tree_column->cell_list; list; list = list->next)
{
GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *)list->data;
- if (! info->cell->visible)
+ if (!gtk_cell_renderer_get_visible (info->cell))
continue;
if (info->expand == TRUE)
expand_cell_count ++;
full_requested_width += info->requested_width;
- /* FIXME: We prolly need to include tree_column->spacing here */
+
+ if (!first_cell)
+ full_requested_width += tree_column->spacing;
+
+ first_cell = FALSE;
}
extra_space = cell_area->width - full_requested_width;
if (info->pack == GTK_PACK_END)
continue;
- if (! info->cell->visible)
+ if (!gtk_cell_renderer_get_visible (info->cell))
continue;
if ((info->has_focus || special_cells == 1) && cursor_row)
real_cell_area.width = info->real_width;
real_cell_area.width -= 2 * focus_line_width;
- real_background_area.width = info->real_width + horizontal_separator + depth;
+
+ if (list->next)
+ {
+ real_background_area.width = info->real_width + depth;
+ }
+ else
+ {
+ /* fill the rest of background for the last cell */
+ real_background_area.width = background_area->x + background_area->width - real_background_area.x;
+ }
rtl_cell_area = real_cell_area;
rtl_background_area = real_background_area;
if (action == CELL_ACTION_RENDER)
{
gtk_cell_renderer_render (info->cell,
- window,
- tree_column->tree_view,
- &rtl_background_area,
- &rtl_cell_area,
- &real_expose_area,
- flags);
+ cr,
+ tree_column->tree_view,
+ &rtl_background_area,
+ &rtl_cell_area,
+ flags);
}
-
/* FOCUS */
else if (action == CELL_ACTION_FOCUS)
{
- gint x_offset, y_offset, width, height;
+ gint x_offset, y_offset;
+ GtkRequisition min_size;
- gtk_cell_renderer_get_size (info->cell,
- tree_column->tree_view,
- &rtl_cell_area,
- &x_offset, &y_offset,
- &width, &height);
+ gtk_cell_renderer_get_preferred_size (info->cell,
+ tree_column->tree_view,
+ &min_size, NULL);
+
+ _gtk_cell_renderer_calc_offset (info->cell, &rtl_cell_area,
+ gtk_widget_get_direction (tree_column->tree_view),
+ min_size.width, min_size.height,
+ &x_offset, &y_offset);
if (special_cells > 1)
{
if (info->has_focus)
{
min_x = rtl_cell_area.x + x_offset;
- max_x = min_x + width;
+ max_x = min_x + min_size.width;
min_y = rtl_cell_area.y + y_offset;
- max_y = min_y + height;
+ max_y = min_y + min_size.height;
}
}
else
{
if (min_x > (rtl_cell_area.x + x_offset))
min_x = rtl_cell_area.x + x_offset;
- if (max_x < rtl_cell_area.x + x_offset + width)
- max_x = rtl_cell_area.x + x_offset + width;
+ if (max_x < rtl_cell_area.x + x_offset + min_size.width)
+ max_x = rtl_cell_area.x + x_offset + min_size.width;
if (min_y > (rtl_cell_area.y + y_offset))
min_y = rtl_cell_area.y + y_offset;
- if (max_y < rtl_cell_area.y + y_offset + height)
- max_y = rtl_cell_area.y + y_offset + height;
+ if (max_y < rtl_cell_area.y + y_offset + min_size.height)
+ max_y = rtl_cell_area.y + y_offset + min_size.height;
}
}
/* EVENT */
flags &= ~GTK_CELL_RENDERER_FOCUSED;
- real_cell_area.x += (real_cell_area.width + tree_column->spacing);
- real_background_area.x += (real_background_area.width + tree_column->spacing);
+ real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
+ real_background_area.x += real_background_area.width + tree_column->spacing;
+
+ /* Only needed for first cell */
+ depth = 0;
}
/* iterate list for PACK_END cells */
if (info->pack == GTK_PACK_START)
continue;
- if (! info->cell->visible)
+ if (!gtk_cell_renderer_get_visible(info->cell))
continue;
if ((info->has_focus || special_cells == 1) && cursor_row)
real_cell_area.width = info->real_width;
real_cell_area.width -= 2 * focus_line_width;
- real_background_area.width = info->real_width + horizontal_separator + depth;
+ real_background_area.width = info->real_width + depth;
rtl_cell_area = real_cell_area;
rtl_background_area = real_background_area;
if (action == CELL_ACTION_RENDER)
{
gtk_cell_renderer_render (info->cell,
- window,
- tree_column->tree_view,
- &rtl_background_area,
- &rtl_cell_area,
- &real_expose_area,
- flags);
+ cr,
+ tree_column->tree_view,
+ &rtl_background_area,
+ &rtl_cell_area,
+ flags);
}
/* FOCUS */
else if (action == CELL_ACTION_FOCUS)
{
- gint x_offset, y_offset, width, height;
+ gint x_offset, y_offset;
+ GtkRequisition min_size;
- gtk_cell_renderer_get_size (info->cell,
- tree_column->tree_view,
- &rtl_cell_area,
- &x_offset, &y_offset,
- &width, &height);
+ gtk_cell_renderer_get_preferred_size (info->cell,
+ tree_column->tree_view,
+ &min_size, NULL);
+
+ _gtk_cell_renderer_calc_offset (info->cell, &rtl_cell_area,
+ gtk_widget_get_direction (tree_column->tree_view),
+ min_size.width, min_size.height,
+ &x_offset, &y_offset);
if (special_cells > 1)
{
if (info->has_focus)
{
min_x = rtl_cell_area.x + x_offset;
- max_x = min_x + width;
+ max_x = min_x + min_size.width;
min_y = rtl_cell_area.y + y_offset;
- max_y = min_y + height;
+ max_y = min_y + min_size.height;
}
}
else
{
if (min_x > (rtl_cell_area.x + x_offset))
min_x = rtl_cell_area.x + x_offset;
- if (max_x < rtl_cell_area.x + x_offset + width)
- max_x = rtl_cell_area.x + x_offset + width;
+ if (max_x < rtl_cell_area.x + x_offset + min_size.width)
+ max_x = rtl_cell_area.x + x_offset + min_size.width;
if (min_y > (rtl_cell_area.y + y_offset))
min_y = rtl_cell_area.y + y_offset;
- if (max_y < rtl_cell_area.y + y_offset + height)
- max_y = rtl_cell_area.y + y_offset + height;
+ if (max_y < rtl_cell_area.y + y_offset + min_size.height)
+ max_y = rtl_cell_area.y + y_offset + min_size.height;
}
}
/* EVENT */
cell_area->x + cell_area->width > ((GdkEventButton *)event)->x)
try_event = TRUE;
}
- else if (real_cell_area.x <= ((GdkEventButton *)event)->x &&
- real_cell_area.x + real_cell_area.width > ((GdkEventButton *)event)->x)
+ else if (rtl_cell_area.x <= ((GdkEventButton *)event)->x &&
+ rtl_cell_area.x + rtl_cell_area.width > ((GdkEventButton *)event)->x)
/* only activate cell if the user clicked on an individual
* cell
*/
flags &= ~GTK_CELL_RENDERER_FOCUSED;
- real_cell_area.x += (real_cell_area.width + tree_column->spacing);
+ real_cell_area.x += (real_cell_area.width + 2 * focus_line_width + tree_column->spacing);
real_background_area.x += (real_background_area.width + tree_column->spacing);
+
+ /* Only needed for first cell */
+ depth = 0;
}
/* fill focus_rectangle when required */
/**
* gtk_tree_view_column_cell_render:
* @tree_column: A #GtkTreeViewColumn.
- * @window: a #GdkDrawable to draw to
+ * @cr: cairo context to draw to
* @background_area: entire cell area (including tree expanders and maybe padding on the sides)
* @cell_area: area normally rendered by a cell renderer
- * @expose_area: area that actually needs updating
* @flags: flags that affect rendering
*
* Renders the cell contained by #tree_column. This is used primarily by the
* #GtkTreeView.
**/
void
-_gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
- GdkWindow *window,
- GdkRectangle *background_area,
- GdkRectangle *cell_area,
- GdkRectangle *expose_area,
- guint flags)
+_gtk_tree_view_column_cell_render (GtkTreeViewColumn *tree_column,
+ cairo_t *cr,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
+ guint flags)
{
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
+ g_return_if_fail (cr != NULL);
g_return_if_fail (background_area != NULL);
g_return_if_fail (cell_area != NULL);
- g_return_if_fail (expose_area != NULL);
+
+ cairo_save (cr);
gtk_tree_view_column_cell_process_action (tree_column,
- window,
+ cr,
background_area,
cell_area,
flags,
CELL_ACTION_RENDER,
- expose_area,
NULL, NULL, NULL, NULL);
+
+ cairo_restore (cr);
}
gboolean
GtkCellEditable **editable_widget,
GdkEvent *event,
gchar *path_string,
- GdkRectangle *background_area,
- GdkRectangle *cell_area,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
guint flags)
{
g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
return gtk_tree_view_column_cell_process_action (tree_column,
- NULL,
+ NULL,
background_area,
cell_area,
flags,
CELL_ACTION_EVENT,
- NULL, NULL,
+ NULL,
editable_widget,
event,
path_string);
}
+void
+_gtk_tree_view_column_get_focus_area (GtkTreeViewColumn *tree_column,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
+ GdkRectangle *focus_area)
+{
+ gtk_tree_view_column_cell_process_action (tree_column,
+ NULL,
+ background_area,
+ cell_area,
+ 0,
+ CELL_ACTION_FOCUS,
+ focus_area,
+ NULL, NULL, NULL);
+}
+
+
/* cell list manipulation */
static GList *
gtk_tree_view_column_cell_first (GtkTreeViewColumn *tree_column)
gboolean right)
{
gint count;
+ gboolean rtl;
count = _gtk_tree_view_column_count_special_cells (tree_column);
+ rtl = gtk_widget_get_direction (GTK_WIDGET (tree_column->tree_view)) == GTK_TEXT_DIR_RTL;
/* if we are the current focus column and have multiple editable cells,
* try to select the next one, else move the focus to the next column
if (!list || !info || !info->has_focus)
return FALSE;
- next = gtk_tree_view_column_cell_next (tree_column, list);
- prev = gtk_tree_view_column_cell_prev (tree_column, list);
+ if (rtl)
+ {
+ prev = gtk_tree_view_column_cell_next (tree_column, list);
+ next = gtk_tree_view_column_cell_prev (tree_column, list);
+ }
+ else
+ {
+ next = gtk_tree_view_column_cell_next (tree_column, list);
+ prev = gtk_tree_view_column_cell_prev (tree_column, list);
+ }
info->has_focus = FALSE;
if (direction > 0 && next)
}
else if (direction > 0 && !next && !right)
{
- /* keep focus on latest cell */
- info = gtk_tree_view_column_cell_last (tree_column)->data;
+ /* keep focus on last cell */
+ if (rtl)
+ info = gtk_tree_view_column_cell_first (tree_column)->data;
+ else
+ info = gtk_tree_view_column_cell_last (tree_column)->data;
+
info->has_focus = TRUE;
return TRUE;
}
else if (direction < 0 && !prev && !left)
{
/* keep focus on first cell */
- info = gtk_tree_view_column_cell_first (tree_column)->data;
+ if (rtl)
+ info = gtk_tree_view_column_cell_last (tree_column)->data;
+ else
+ info = gtk_tree_view_column_cell_first (tree_column)->data;
+
info->has_focus = TRUE;
return TRUE;
}
info->has_focus = FALSE;
}
- if (direction > 0)
- ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_first (tree_column)->data)->has_focus = TRUE;
- else if (direction < 0)
- ((GtkTreeViewColumnCellInfo *)gtk_tree_view_column_cell_last (tree_column)->data)->has_focus = TRUE;
+ list = NULL;
+ if (rtl)
+ {
+ if (direction > 0)
+ list = gtk_tree_view_column_cell_last (tree_column);
+ else if (direction < 0)
+ list = gtk_tree_view_column_cell_first (tree_column);
+ }
+ else
+ {
+ if (direction > 0)
+ list = gtk_tree_view_column_cell_first (tree_column);
+ else if (direction < 0)
+ list = gtk_tree_view_column_cell_last (tree_column);
+ }
+
+ if (list)
+ ((GtkTreeViewColumnCellInfo *) list->data)->has_focus = TRUE;
}
+
return TRUE;
}
void
-_gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn *tree_column,
- GdkWindow *window,
- GdkRectangle *background_area,
- GdkRectangle *cell_area,
- GdkRectangle *expose_area,
- guint flags)
+_gtk_tree_view_column_cell_draw_focus (GtkTreeViewColumn *tree_column,
+ cairo_t *cr,
+ const GdkRectangle *background_area,
+ const GdkRectangle *cell_area,
+ guint flags)
{
gint focus_line_width;
GtkStateType cell_state;
g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
+ g_return_if_fail (cr != NULL);
+
gtk_widget_style_get (GTK_WIDGET (tree_column->tree_view),
"focus-line-width", &focus_line_width, NULL);
if (tree_column->editable_widget)
#if 0
gtk_paint_focus (tree_column->tree_view->style,
window,
- GTK_WIDGET_STATE (tree_column->tree_view),
+ gtk_widget_get_state (tree_column->tree_view),
NULL,
tree_column->tree_view,
"treeview",
{
GdkRectangle focus_rectangle;
gtk_tree_view_column_cell_process_action (tree_column,
- window,
+ cr,
background_area,
cell_area,
flags,
CELL_ACTION_FOCUS,
- expose_area,
&focus_rectangle,
NULL, NULL, NULL);
cell_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 (tree_column->tree_view->style,
- window,
- cell_state,
- cell_area,
- tree_column->tree_view,
- "treeview",
- focus_rectangle.x,
- focus_rectangle.y,
- focus_rectangle.width,
- focus_rectangle.height);
+ gtk_paint_focus (gtk_widget_get_style (tree_column->tree_view),
+ cr,
+ cell_state,
+ tree_column->tree_view,
+ "treeview",
+ focus_rectangle.x,
+ focus_rectangle.y,
+ focus_rectangle.width,
+ focus_rectangle.height);
}
}
{
GtkTreeViewColumnCellInfo *info = (GtkTreeViewColumnCellInfo *) list->data;
- if (info->cell->visible)
+ if (gtk_cell_renderer_get_visible (info->cell))
return TRUE;
}
tree_column->width = 0;
if (tree_column->tree_view &&
- GTK_WIDGET_REALIZED (tree_column->tree_view))
+ gtk_widget_get_realized (tree_column->tree_view))
{
if (install_handler)
_gtk_tree_view_install_mark_rows_col_dirty (GTK_TREE_VIEW (tree_column->tree_view));
gint *right)
{
GList *list;
- gint *rtl_left, *rtl_right;
-
- if (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL)
- {
- rtl_left = right;
- rtl_right = left;
- }
- else
- {
- rtl_left = left;
- rtl_right = right;
- }
+ GtkTreeViewColumnCellInfo *info;
+ gint l, r;
+ gboolean rtl;
- if (rtl_left)
- {
- *rtl_left = 0;
- list = gtk_tree_view_column_cell_first (column);
+ l = r = 0;
- for (; list; list = gtk_tree_view_column_cell_next (column, list))
- {
- GtkTreeViewColumnCellInfo *info =
- (GtkTreeViewColumnCellInfo *)list->data;
+ list = gtk_tree_view_column_cell_first (column);
- if (info->cell == cell)
- break;
+ while (list)
+ {
+ info = (GtkTreeViewColumnCellInfo *)list->data;
+
+ list = gtk_tree_view_column_cell_next (column, list);
- if (info->cell->visible)
- *rtl_left += info->real_width;
- }
+ if (info->cell == cell)
+ break;
+
+ if (gtk_cell_renderer_get_visible (info->cell))
+ l += info->real_width + column->spacing;
}
- if (rtl_right)
+ while (list)
{
- GList *next;
-
- *rtl_right = 0;
- list = gtk_tree_view_column_cell_first (column);
-
- for (; list; list = gtk_tree_view_column_cell_next (column, list))
- {
- GtkTreeViewColumnCellInfo *info =
- (GtkTreeViewColumnCellInfo *)list->data;
+ info = (GtkTreeViewColumnCellInfo *)list->data;
+
+ list = gtk_tree_view_column_cell_next (column, list);
- if (info->cell == cell)
- break;
- }
+ if (gtk_cell_renderer_get_visible (info->cell))
+ r += info->real_width + column->spacing;
+ }
- /* skip cell */
- next = gtk_tree_view_column_cell_next (column, list);
- if (list && next)
- {
- list = next;
- for ( ; list; list = gtk_tree_view_column_cell_next (column, list))
- {
- GtkTreeViewColumnCellInfo *info =
- (GtkTreeViewColumnCellInfo *)list->data;
+ rtl = (gtk_widget_get_direction (GTK_WIDGET (column->tree_view)) == GTK_TEXT_DIR_RTL);
+ if (left)
+ *left = rtl ? r : l;
- if (info->cell->visible)
- *rtl_right += info->real_width;
- }
- }
- }
+ if (right)
+ *right = rtl ? l : r;
}
/**
break;
}
- if (cellinfo->cell->visible)
+ if (gtk_cell_renderer_get_visible (cellinfo->cell))
current_x += cellinfo->real_width;
}
void
gtk_tree_view_column_queue_resize (GtkTreeViewColumn *tree_column)
{
- g_return_if_fail (tree_column != NULL);
+ g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
if (tree_column->tree_view)
_gtk_tree_view_column_cell_set_dirty (tree_column, TRUE);
}
-#define __GTK_TREE_VIEW_COLUMN_C__
-#include "gtkaliasdef.c"
+/**
+ * gtk_tree_view_column_get_tree_view:
+ * @tree_column: A #GtkTreeViewColumn
+ *
+ * Returns the #GtkTreeView wherein @tree_column has been inserted.
+ * If @column is currently not inserted in any tree view, %NULL is
+ * returned.
+ *
+ * Return value: (transfer none): The tree view wherein @column has
+ * been inserted if any, %NULL otherwise.
+ *
+ * Since: 2.12
+ */
+GtkWidget *
+gtk_tree_view_column_get_tree_view (GtkTreeViewColumn *tree_column)
+{
+ g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), NULL);
+
+ return tree_column->tree_view;
+}