2 * This file is a part of hildon
4 * Copyright (C) 2005, 2008 Nokia Corporation.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version. or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * SECTION:hildon-touch-selector
23 * @short_description: A selector widget with several columns.
25 * #HildonTouchSelector is a selector widget, that allows users to
26 * select items from one to many predefined lists. It is very similar
27 * to #GtkComboBox, but with several individual pannable columns.
29 * Normally, you would use #HildonTouchSelector together with a
30 * #HildonPickerDialog activated from a button. For the most common
31 * cases, you should use #HildonPickerButton.
33 * The contents of each #HildonTouchSelector column are stored in a
34 * #GtkTreeModel. To add a new column to a #HildonTouchSelector, use
35 * hildon_touch_selector_append_column(). If you want to add a
36 * text-only column, without special attributes, use
37 * hildon_touch_selector_append_text_column().
39 * It is highly recommended that you use only one column
40 * #HildonTouchSelector<!-- -->s.
41 * If you only need a text only, one column selector, you can create it with
42 * hildon_touch_selector_new_text() and populate with
43 * hildon_touch_selector_append_text(), hildon_touch_selector_prepend_text(),
44 * and hildon_touch_selector_insert_text().
46 * If you need a selector widget that also accepts user inputs, you
47 * can use #HildonTouchSelectorEntry.
49 * The current selection has a string representation. In the most common cases,
50 * each column model will contain a text column. You can configure
51 * which column in particular using the #HildonTouchSelectorColumn property
52 * #HildonTouchSelectorColumn:text-column
54 * You can get this string representation using
55 * hildon_touch_selector_get_current_text().
56 * You can configure how the selection is printed with
57 * hildon_touch_selector_set_print_func(), that sets the current hildon touch
58 * selector print function. The widget has a default print function, that
59 * uses the #HildonTouchSelectorColumn:text-column property on each
60 * #HildonTouchSelectorColumn to compose the final representation.
62 * If you create the selector using hildon_touch_selector_new_text() you
63 * don't need to take care of this property, as the model is created internally.
64 * If you create the selector using hildon_touch_selector_new(), you
65 * need to specify properly the property for your custom model in order to get a
66 * non-empty string representation, or define your custom print function.
69 * <title>Creating a HildonTouchSelector</title>
72 * selection_changed (HildonTouchSelector * selector,
73 * gpointer *user_data)
75 * gchar *current_selection = NULL;
77 * current_selection = hildon_touch_selector_get_current_text (selector);
78 * g_debug ("Current selection : %s", current_selection);
82 * create_customized_selector ()
84 * GtkWidget *selector = NULL;
85 * GSList *icon_list = NULL;
86 * GtkListStore *store_icons = NULL;
87 * GSList *item = NULL;
88 * GtkCellRenderer *renderer = NULL;
89 * HildonTouchSelectorColumn *column = NULL;
91 * selector = hildon_touch_selector_new ();
93 * icon_list = gtk_stock_list_ids ();
95 * store_icons = gtk_list_store_new (1, G_TYPE_STRING);
96 * for (item = icon_list; item; item = g_slist_next (item)) {
98 * gchar *label = item->data;
100 * gtk_list_store_append (store_icons, &iter);
101 * gtk_list_store_set (store_icons, &iter, 0, label, -1);
104 * g_slist_free (icon_list);
106 * renderer = gtk_cell_renderer_pixbuf_new ();
107 * gtk_cell_renderer_set_fixed_size (renderer, -1, 100);
109 * column = hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector),
110 * GTK_TREE_MODEL (store_icons),
111 * renderer, "stock-id", 0, NULL);
113 * hildon_touch_selector_column_set_text_column (column, 0);
115 * hildon_touch_selector_set_column_selection_mode (HILDON_TOUCH_SELECTOR (selector),
116 * HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
118 * g_signal_connect (G_OBJECT (selector), "changed",
119 * G_CALLBACK (selection_changed), NULL);
125 * create_simple_selector ()
127 * GtkWidget *selector = NULL;
130 * selector = hildon_touch_selector_new_text ();
131 * hildon_touch_selector_set_column_selection_mode (HILDON_TOUCH_SELECTOR (selector),
132 * HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE);
134 * g_signal_connect (G_OBJECT (selector), "changed",
135 * G_CALLBACK (selection_changed), NULL);
137 * for (i = 1; i <= 10 ; i++) {
138 * gchar *label = g_strdup_printf ("Item &percnt;d", i);
140 * hildon_touch_selector_append_text (HILDON_TOUCH_SELECTOR (selector),
153 * SECTION:hildon-touch-selector-column
154 * @short_description: A visible column in a #HildonTouchSelector
155 * @see_also: #HildonTouchSelector
157 * A #HildonTouchSelectorColumn is a column in a
158 * #HildonTouchSelector. This class implements the #GtkCellLayout interface, allowing
159 * a flexible management of the cellrenderers in each #HildonTouchSelector column.
162 #undef HILDON_DISABLE_DEPRECATED
171 #include "hildon-gtk.h"
173 #include "hildon-pannable-area.h"
174 #include "hildon-touch-selector.h"
175 #include "hildon-touch-selector-private.h"
177 #define HILDON_TOUCH_SELECTOR_GET_PRIVATE(obj) \
178 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), HILDON_TYPE_TOUCH_SELECTOR, HildonTouchSelectorPrivate))
180 G_DEFINE_TYPE (HildonTouchSelector, hildon_touch_selector, GTK_TYPE_VBOX)
183 * IMPLEMENTATION NOTES:
184 * Struct to maintain the data of each column. The columns are the elements
185 * of the widget that belongs properly to the selection behaviour. Although
186 * internally the columns are arranged in a private #GtkHBox, as the selector
187 * itself is a #GtkVBox, you can add more widgets, like buttons etc., so
188 * you finally could have a widget with more elements that the columns, but
189 * this doesn't belongs to the selection logic
191 struct _HildonTouchSelectorColumnPrivate
193 HildonTouchSelector *parent; /* the selector that contains this column */
196 GtkTreeView *tree_view;
197 gulong realize_handler;
198 GtkTreePath *initial_path;
200 GtkWidget *panarea; /* the pannable widget */
203 struct _HildonTouchSelectorPrivate
205 GSList *columns; /* the selection columns */
206 GtkWidget *hbox; /* the container for the selector's columns */
207 gboolean initial_scroll; /* whether initial fancy scrolling to selection */
209 gboolean changed_blocked;
211 HildonTouchSelectorPrintFunc print_func;
212 gpointer print_user_data;
213 GDestroyNotify print_destroy_func;
218 PROP_HAS_MULTIPLE_SELECTION = 1,
229 static gint hildon_touch_selector_signals[LAST_SIGNAL] = { 0 };
232 hildon_touch_selector_dispose (GObject * object);
235 hildon_touch_selector_get_property (GObject * object,
240 hildon_touch_selector_set_property (GObject *object,
247 static void hildon_touch_selector_remove (GtkContainer * container,
249 /* private functions */
250 static void _row_tapped_cb (GtkTreeView * tree_view,
253 static gchar *_default_print_func (HildonTouchSelector * selector,
256 static HildonTouchSelectorColumn *_create_new_column (HildonTouchSelector * selector,
257 GtkTreeModel * model,
258 gboolean *emit_changed,
259 GtkCellRenderer * renderer,
262 on_realize_cb (GtkWidget *widget,
265 on_row_changed (GtkTreeModel *model,
271 hildon_touch_selector_scroll_to (HildonTouchSelectorColumn *column,
275 _hildon_touch_selector_center_on_selected_items (HildonTouchSelector *selector,
276 HildonTouchSelectorColumn *column);
278 _hildon_touch_selector_set_model (HildonTouchSelector * selector,
280 GtkTreeModel * model);
282 _hildon_touch_selector_has_multiple_selection (HildonTouchSelector * selector);
285 hildon_touch_selector_emit_value_changed (HildonTouchSelector *selector,
288 /* GtkCellLayout implementation (HildonTouchSelectorColumn)*/
289 static void hildon_touch_selector_column_cell_layout_init (GtkCellLayoutIface *iface);
291 static void hildon_touch_selector_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
292 GtkCellRenderer *cell,
294 static void hildon_touch_selector_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
295 GtkCellRenderer *cell,
297 static void hildon_touch_selector_column_cell_layout_clear (GtkCellLayout *cell_layout);
298 static void hildon_touch_selector_column_cell_layout_add_attribute(GtkCellLayout *cell_layout,
299 GtkCellRenderer *cell,
300 const gchar *attribute,
302 static void hildon_touch_selector_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
303 GtkCellRenderer *cell,
304 GtkCellLayoutDataFunc func,
306 GDestroyNotify destroy);
307 static void hildon_touch_selector_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
308 GtkCellRenderer *cell);
309 static void hildon_touch_selector_column_cell_layout_reorder (GtkCellLayout *cell_layout,
310 GtkCellRenderer *cell,
312 static GList *hildon_touch_selector_column_cell_layout_get_cells (GtkCellLayout *cell_layout);
316 hildon_touch_selector_class_init (HildonTouchSelectorClass * class)
318 GObjectClass *gobject_class;
319 GtkObjectClass *object_class;
320 GtkContainerClass *container_class;
322 gobject_class = G_OBJECT_CLASS (class);
323 object_class = GTK_OBJECT_CLASS (class);
324 container_class = GTK_CONTAINER_CLASS (class);
327 gobject_class->dispose = hildon_touch_selector_dispose;
328 gobject_class->get_property = hildon_touch_selector_get_property;
329 gobject_class->set_property = hildon_touch_selector_set_property;
334 container_class->remove = hildon_touch_selector_remove;
336 /* HildonTouchSelector */
337 class->changed = NULL;
338 class->set_model = _hildon_touch_selector_set_model;
340 class->has_multiple_selection = _hildon_touch_selector_has_multiple_selection;
344 * HildonTouchSelector::changed:
345 * @widget: the object which received the signal
346 * @column: the number of the column that has changed
348 * The "changed" signal is emitted when the active item on any column is changed.
349 * This can be due to the user selecting a different item from the list, or
350 * due to a call to hildon_touch_selector_select_iter() on one of the columns.
354 hildon_touch_selector_signals[CHANGED] =
355 g_signal_new ("changed",
356 G_OBJECT_CLASS_TYPE (class),
358 G_STRUCT_OFFSET (HildonTouchSelectorClass, changed),
360 g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
363 * HildonTouchSelector::columns-changed:
364 * @selector: the object which received the signal
366 * The "columns-changed" signal is emitted when the number
367 * of columns in the #HildonTouchSelector change.
371 hildon_touch_selector_signals[COLUMNS_CHANGED] =
372 g_signal_new ("columns-changed",
373 G_OBJECT_CLASS_TYPE (class),
374 G_SIGNAL_RUN_LAST, 0,
376 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
380 g_object_class_install_property (gobject_class, PROP_HAS_MULTIPLE_SELECTION,
381 g_param_spec_boolean ("has-multiple-selection",
382 "has multiple selection",
383 "Whether the widget has multiple "
384 "selection (like multiple columns, "
385 "multiselection mode, or multiple "
386 "internal widgets) and therefore "
387 "it may need a confirmation button, "
392 g_object_class_install_property (G_OBJECT_CLASS (gobject_class),
394 g_param_spec_boolean ("initial-scroll",
396 "Whether to scroll to the"
397 "current selection when"
398 "the selector is first"
401 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
403 /* style properties */
404 /* We need to ensure fremantle mode for the treeview in order to work
405 properly. This is not about the appearance, this is about behaviour */
406 gtk_rc_parse_string ("style \"fremantle-htst\" {\n"
407 " GtkWidget::hildon-mode = 1\n"
408 "} widget \"*.fremantle-htst\" style \"fremantle-htst\""
409 "widget_class \"*<HildonPannableArea>.GtkTreeView\" style :highest \"fremantle-htst\"");
411 g_type_class_add_private (object_class, sizeof (HildonTouchSelectorPrivate));
415 hildon_touch_selector_get_property (GObject * object,
417 GValue * value, GParamSpec * pspec)
419 HildonTouchSelectorPrivate *priv = HILDON_TOUCH_SELECTOR (object)->priv;
422 case PROP_HAS_MULTIPLE_SELECTION:
423 g_value_set_boolean (value,
424 hildon_touch_selector_has_multiple_selection (HILDON_TOUCH_SELECTOR (object)));
426 case PROP_INITIAL_SCROLL:
427 g_value_set_boolean (value, priv->initial_scroll);
430 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
436 hildon_touch_selector_set_property (GObject *object, guint prop_id,
437 const GValue *value, GParamSpec *pspec)
439 HildonTouchSelectorPrivate *priv = HILDON_TOUCH_SELECTOR (object)->priv;
442 case PROP_INITIAL_SCROLL:
443 priv->initial_scroll = g_value_get_boolean (value);
446 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
453 hildon_touch_selector_init (HildonTouchSelector * selector)
455 selector->priv = HILDON_TOUCH_SELECTOR_GET_PRIVATE (selector);
457 GTK_WIDGET_SET_FLAGS (GTK_WIDGET (selector), GTK_NO_WINDOW);
458 gtk_widget_set_redraw_on_allocate (GTK_WIDGET (selector), FALSE);
460 selector->priv->columns = NULL;
462 selector->priv->print_func = NULL;
463 selector->priv->print_user_data = NULL;
464 selector->priv->print_destroy_func = NULL;
465 selector->priv->initial_scroll = TRUE;
466 selector->priv->hbox = gtk_hbox_new (FALSE, 0);
468 selector->priv->changed_blocked = FALSE;
470 gtk_box_pack_end (GTK_BOX (selector), selector->priv->hbox,
472 gtk_widget_show (selector->priv->hbox);
476 hildon_touch_selector_dispose (GObject * object)
478 GObjectClass *gobject_class;
480 hildon_touch_selector_set_print_func_full (HILDON_TOUCH_SELECTOR (object),
483 gobject_class = G_OBJECT_CLASS (hildon_touch_selector_parent_class);
485 if (gobject_class->dispose)
486 (* gobject_class->dispose) (object);
490 disconnect_model_handlers (HildonTouchSelectorColumn *col, HildonTouchSelector *selector)
492 g_signal_handlers_disconnect_by_func (col->priv->model,
493 on_row_changed, selector);
497 * IMPLEMENTATION NOTES:
498 * Some people sent questions regarding a missing dispose/finalize function on
499 * this widget that could lead to leak memory, so we will clarify this topic.
501 * This is not required as #HildonTouchSelector extends #GtkContainer. When the
502 * widget is freed, the #GtkContainer freeing memory functions are called. This
503 * process includes remove each widget individually, so all the widgets are
506 * In the same way, this widget redefines gtk_container->remove function, in
507 * order to free the column related information if it is required.
509 * Please take a look to hildon_touch_selector_remove for more information.
512 /*------------------------------ GtkContainer ------------------------------ */
515 * Required in order to free the column at the columns list
518 hildon_touch_selector_remove (GtkContainer * container, GtkWidget * widget)
520 HildonTouchSelector *selector = NULL;
522 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (container));
523 selector = HILDON_TOUCH_SELECTOR (container);
525 /* Remove the extra data related to the columns, if required. */
526 if (widget == selector->priv->hbox) {
527 g_slist_foreach (selector->priv->columns, (GFunc) disconnect_model_handlers, selector);
528 g_slist_foreach (selector->priv->columns, (GFunc) g_object_unref, NULL);
530 g_slist_free (selector->priv->columns);
532 selector->priv->columns = NULL;
534 g_debug ("Freeing a widget outside the columns logic");
537 /* Now remove the widget itself from the container */
538 GTK_CONTAINER_CLASS (hildon_touch_selector_parent_class)->remove (container, widget);
541 /* ------------------------------ PRIVATE METHODS ---------------------------- */
543 hildon_touch_selector_block_changed (HildonTouchSelector *selector)
545 selector->priv->changed_blocked = TRUE;
549 hildon_touch_selector_unblock_changed (HildonTouchSelector *selector)
551 selector->priv->changed_blocked = FALSE;
555 hildon_touch_selector_emit_value_changed (HildonTouchSelector *selector,
558 if (!selector->priv->changed_blocked) {
559 g_signal_emit (selector, hildon_touch_selector_signals[CHANGED], 0, column);
564 * default_print_func:
565 * @selector: a #HildonTouchSelector
567 * Default print function
569 * Returns: a new string that represents the selected items
574 _default_print_func (HildonTouchSelector * selector, gpointer user_data)
576 gchar *result = NULL;
578 gint num_columns = 0;
580 GtkTreeModel *model = NULL;
581 gchar *current_string = NULL;
583 HildonTouchSelectorSelectionMode mode;
585 GtkTreePath *current_path = NULL;
586 GList *selected_rows = NULL;
587 gint initial_value = 0;
588 gint text_column = -1;
589 HildonTouchSelectorColumn *column = NULL;
591 num_columns = hildon_touch_selector_get_num_columns (selector);
593 mode = hildon_touch_selector_get_column_selection_mode (selector);
595 if ((mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE)
596 && (num_columns > 0)) {
597 /* In this case we get the first column first */
598 selected_rows = hildon_touch_selector_get_selected_rows (selector, 0);
599 model = hildon_touch_selector_get_model (selector, 0);
600 column = hildon_touch_selector_get_column (selector, 0);
601 text_column = hildon_touch_selector_column_get_text_column (column);
603 result = g_strdup_printf ("(");
605 for (item = selected_rows; item; item = g_list_next (item)) {
606 current_path = item->data;
607 gtk_tree_model_get_iter (model, &iter, current_path);
609 if (text_column != -1) {
610 gtk_tree_model_get (model, &iter, text_column, ¤t_string, -1);
613 if (i < g_list_length (selected_rows) - 1) {
614 aux = g_strconcat (result, current_string, ",", NULL);
618 aux = g_strconcat (result, current_string, NULL);
623 if (current_string) {
624 g_free (current_string);
625 current_string = NULL;
631 aux = g_strconcat (result, ")", NULL);
635 g_list_foreach (selected_rows, (GFunc) (gtk_tree_path_free), NULL);
636 g_list_free (selected_rows);
642 for (i = initial_value; i < num_columns; i++) {
643 model = hildon_touch_selector_get_model (selector, i);
644 column = hildon_touch_selector_get_column (selector, i);
645 text_column = hildon_touch_selector_column_get_text_column (column);
647 if (hildon_touch_selector_get_selected (selector, i, &iter)) {
648 if (text_column == -1 ) {
649 g_warning ("Trying to use the default print function in HildonTouchSelector, but "
650 "\"text-column\" property is not set for HildonTouchSelectorColumn %p.", column);
651 current_string = NULL;
653 gtk_tree_model_get (model, &iter, text_column, ¤t_string, -1);
657 result = current_string;
659 aux = g_strconcat (result, ":", current_string, NULL);
661 g_free (current_string);
662 current_string = NULL;
672 _row_tapped_cb (GtkTreeView * tree_view, GtkTreePath * path, gpointer user_data)
674 HildonTouchSelector *selector = NULL;
675 HildonTouchSelectorColumn *column = NULL;
676 gint num_column = -1;
678 column = HILDON_TOUCH_SELECTOR_COLUMN (user_data);
679 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (column->priv->parent));
681 selector = column->priv->parent;
683 num_column = g_slist_index (selector->priv->columns, column);
685 hildon_touch_selector_emit_value_changed (selector, num_column);
689 static HildonTouchSelectorColumn *
690 _create_new_column (HildonTouchSelector * selector,
691 GtkTreeModel * model,
692 gboolean *emit_changed,
693 GtkCellRenderer * renderer, va_list args)
695 HildonTouchSelectorColumn *new_column = NULL;
696 GtkTreeViewColumn *tree_column = NULL;
697 GtkTreeView *tv = NULL;
698 GtkWidget *panarea = NULL;
699 GtkTreeSelection *selection = NULL;
704 tree_column = gtk_tree_view_column_new ();
706 if (renderer != NULL) {
707 gtk_tree_view_column_pack_start (tree_column, renderer, TRUE);
709 attribute = va_arg (args, gchar *);
710 while (attribute != NULL) {
711 value = va_arg (args, gint);
712 gtk_tree_view_column_add_attribute (tree_column, renderer, attribute,
714 attribute = va_arg (args, gchar *);
719 tv = GTK_TREE_VIEW (hildon_gtk_tree_view_new (HILDON_UI_MODE_EDIT));
721 tv = GTK_TREE_VIEW (gtk_tree_view_new ());
722 #endif /* MAEMO_GTK */
724 gtk_tree_view_set_enable_search (tv, FALSE);
725 GTK_WIDGET_UNSET_FLAGS (GTK_WIDGET (tv), GTK_CAN_FOCUS);
727 gtk_tree_view_set_model (tv, model);
728 g_signal_connect (model, "row-changed",
729 G_CALLBACK (on_row_changed), selector);
730 gtk_tree_view_set_rules_hint (tv, TRUE);
732 gtk_tree_view_append_column (GTK_TREE_VIEW (tv), tree_column);
734 new_column = g_object_new (HILDON_TYPE_TOUCH_SELECTOR_COLUMN, NULL);
735 new_column->priv->parent = selector;
737 panarea = hildon_pannable_area_new ();
739 g_object_set (G_OBJECT (panarea),
740 "initial-hint", FALSE, NULL);
742 gtk_container_add (GTK_CONTAINER (panarea), GTK_WIDGET (tv));
744 new_column->priv->model = model;
745 new_column->priv->tree_view = tv;
746 new_column->priv->panarea = panarea;
747 new_column->priv->realize_handler = 0;
748 new_column->priv->initial_path = NULL;
750 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
751 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
753 /* select the first item */
754 *emit_changed = FALSE;
755 if (gtk_tree_model_get_iter_first (model, &iter)) {
756 gtk_tree_selection_select_iter (selection, &iter);
757 *emit_changed = TRUE;
760 gtk_widget_grab_focus (GTK_WIDGET (tv));
762 /* connect to the hildon-row-tapped signal connection */
763 g_signal_connect (G_OBJECT (tv), "hildon-row-tapped",
764 G_CALLBACK (_row_tapped_cb), new_column);
770 /* ------------------------ HildonTouchSelectorColumn implementation ---------------------- */
771 G_DEFINE_TYPE_WITH_CODE (HildonTouchSelectorColumn, hildon_touch_selector_column, G_TYPE_OBJECT,
772 G_IMPLEMENT_INTERFACE (GTK_TYPE_CELL_LAYOUT,
773 hildon_touch_selector_column_cell_layout_init))
781 hildon_touch_selector_column_class_init (HildonTouchSelectorColumnClass *klass);
784 hildon_touch_selector_column_get_property (GObject *object, guint property_id,
785 GValue *value, GParamSpec *pspec);
788 hildon_touch_selector_column_set_property (GObject *object, guint property_id,
789 const GValue *value, GParamSpec *pspec);
793 hildon_touch_selector_column_class_init (HildonTouchSelectorColumnClass *klass)
795 GObjectClass *gobject_class = NULL;
797 gobject_class = G_OBJECT_CLASS (klass);
799 g_type_class_add_private (gobject_class, sizeof (HildonTouchSelectorColumnPrivate));
802 gobject_class->get_property = hildon_touch_selector_column_get_property;
803 gobject_class->set_property = hildon_touch_selector_column_set_property;
806 * HildonTouchSelectorColumn:text-column:
808 * A column in the data source model to get the strings from.
812 g_object_class_install_property (G_OBJECT_CLASS(klass),
814 g_param_spec_int ("text-column",
816 "A column in the data source model to get the strings from.",
824 hildon_touch_selector_column_init (HildonTouchSelectorColumn *column)
826 column->priv = G_TYPE_INSTANCE_GET_PRIVATE (column, HILDON_TYPE_TOUCH_SELECTOR_COLUMN,
827 HildonTouchSelectorColumnPrivate);
828 column->priv->text_column = -1;
832 * hildon_touch_selector_column_set_text_column:
833 * @column: A #HildonTouchSelectorColumn
834 * @text_column: the index of a model column in the model for @column.
836 * Sets the model column to be displayed in @column. @text_column must point to a
837 * column in the model used with type %G_TYPE_STRING. Initially, this property
838 * is unset. You should set it before using the #HildonTouchSelector that uses
844 hildon_touch_selector_column_set_text_column (HildonTouchSelectorColumn *column,
847 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (column));
848 g_return_if_fail (text_column >= -1);
850 column->priv->text_column = text_column;
852 g_object_notify (G_OBJECT (column), "text-column");
856 * hildon_touch_selector_column_get_text_column:
857 * @column: a #HildonTouchSelectorColumn
859 * Gets the model column set as the text source for @column.
861 * Returns: the index of the text column for @column, or -1 if unset.
866 hildon_touch_selector_column_get_text_column (HildonTouchSelectorColumn *column)
868 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (column), -1);
870 return column->priv->text_column;
874 hildon_touch_selector_column_get_property (GObject *object, guint property_id,
875 GValue *value, GParamSpec *pspec)
877 switch (property_id) {
878 case PROP_TEXT_COLUMN:
879 g_value_set_int (value,
880 hildon_touch_selector_column_get_text_column (HILDON_TOUCH_SELECTOR_COLUMN (object)));
883 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
888 hildon_touch_selector_column_set_property (GObject *object, guint property_id,
889 const GValue *value, GParamSpec *pspec)
891 switch (property_id) {
892 case PROP_TEXT_COLUMN:
893 hildon_touch_selector_column_set_text_column (HILDON_TOUCH_SELECTOR_COLUMN (object),
894 g_value_get_int (value));
897 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
901 /* ------------------------ GtkCellLayout implementation -------------------- */
903 hildon_touch_selector_column_cell_layout_init (GtkCellLayoutIface *iface)
905 iface->pack_start = hildon_touch_selector_column_cell_layout_pack_start;
906 iface->pack_end = hildon_touch_selector_column_cell_layout_pack_end;
907 iface->clear = hildon_touch_selector_column_cell_layout_clear;
908 iface->add_attribute = hildon_touch_selector_column_cell_layout_add_attribute;
909 iface->set_cell_data_func = hildon_touch_selector_column_cell_layout_set_cell_data_func;
910 iface->clear_attributes = hildon_touch_selector_column_cell_layout_clear_attributes;
911 iface->reorder = hildon_touch_selector_column_cell_layout_reorder;
912 iface->get_cells = hildon_touch_selector_column_cell_layout_get_cells;
916 hildon_touch_selector_column_cell_layout_pack_start (GtkCellLayout *cell_layout,
917 GtkCellRenderer *cell,
920 HildonTouchSelectorColumn *sel_column = NULL;
921 GtkTreeViewColumn *view_column = NULL;
923 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
924 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
926 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
928 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(view_column), cell, expand);
933 hildon_touch_selector_column_cell_layout_pack_end (GtkCellLayout *cell_layout,
934 GtkCellRenderer *cell,
937 HildonTouchSelectorColumn *sel_column = NULL;
938 GtkTreeViewColumn *view_column = NULL;
940 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
941 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
943 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
945 gtk_cell_layout_pack_end (GTK_CELL_LAYOUT(view_column), cell, expand);
949 hildon_touch_selector_column_cell_layout_clear (GtkCellLayout *cell_layout)
951 HildonTouchSelectorColumn *sel_column = NULL;
952 GtkTreeViewColumn *view_column = NULL;
954 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
955 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
957 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
959 gtk_cell_layout_clear (GTK_CELL_LAYOUT(view_column));
963 hildon_touch_selector_column_cell_layout_add_attribute (GtkCellLayout *cell_layout,
964 GtkCellRenderer *cell,
965 const gchar *attribute,
968 HildonTouchSelectorColumn *sel_column = NULL;
969 GtkTreeViewColumn *view_column = NULL;
971 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
972 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
974 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
976 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT(view_column), cell, attribute, column);
981 hildon_touch_selector_column_cell_layout_set_cell_data_func (GtkCellLayout *cell_layout,
982 GtkCellRenderer *cell,
983 GtkCellLayoutDataFunc func,
985 GDestroyNotify destroy)
987 HildonTouchSelectorColumn *sel_column = NULL;
988 GtkTreeViewColumn *view_column = NULL;
990 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
991 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
993 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
995 gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT(view_column), cell, func,
1000 hildon_touch_selector_column_cell_layout_clear_attributes (GtkCellLayout *cell_layout,
1001 GtkCellRenderer *cell)
1003 HildonTouchSelectorColumn *sel_column = NULL;
1004 GtkTreeViewColumn *view_column = NULL;
1006 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1007 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1009 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1011 gtk_cell_layout_clear_attributes (GTK_CELL_LAYOUT (view_column), cell);
1015 hildon_touch_selector_column_cell_layout_reorder (GtkCellLayout *cell_layout,
1016 GtkCellRenderer *cell,
1019 HildonTouchSelectorColumn *sel_column = NULL;
1020 GtkTreeViewColumn *view_column = NULL;
1022 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout));
1023 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1025 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1027 gtk_cell_layout_reorder (GTK_CELL_LAYOUT(view_column), cell, position);
1031 hildon_touch_selector_column_cell_layout_get_cells (GtkCellLayout *cell_layout)
1033 HildonTouchSelectorColumn *sel_column = NULL;
1034 GtkTreeViewColumn *view_column = NULL;
1036 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR_COLUMN (cell_layout), NULL);
1037 sel_column = HILDON_TOUCH_SELECTOR_COLUMN (cell_layout);
1039 view_column = gtk_tree_view_get_column (sel_column->priv->tree_view, 0);
1041 return gtk_cell_layout_get_cells (GTK_CELL_LAYOUT(view_column));
1044 /* ------------------------------ PUBLIC METHODS ---------------------------- */
1047 * hildon_touch_selector_new:
1049 * Creates a new empty #HildonTouchSelector.
1051 * Returns: a new #HildonTouchSelector.
1056 hildon_touch_selector_new (void)
1058 return g_object_new (HILDON_TYPE_TOUCH_SELECTOR, NULL);
1062 * hildon_touch_selector_new_text:
1064 * Creates a #HildonTouchSelector with a single text column that
1065 * can be populated conveniently through hildon_touch_selector_append_text(),
1066 * hildon_touch_selector_prepend_text(), hildon_touch_selector_insert_text().
1068 * Returns: A new #HildonTouchSelector
1073 hildon_touch_selector_new_text (void)
1075 GtkWidget *selector;
1076 GtkListStore *store;
1077 HildonTouchSelectorColumn *column = NULL;
1079 selector = hildon_touch_selector_new ();
1080 store = gtk_list_store_new (1, G_TYPE_STRING);
1082 column = hildon_touch_selector_append_text_column (HILDON_TOUCH_SELECTOR (selector),
1083 GTK_TREE_MODEL (store), TRUE);
1085 hildon_touch_selector_column_set_text_column (column, 0);
1091 * hildon_touch_selector_append_text:
1092 * @selector: A #HildonTouchSelector.
1093 * @text: a non %NULL text string.
1095 * Appends a new entry in a #HildonTouchSelector created with
1096 * hildon_touch_selector_new_text().
1101 hildon_touch_selector_append_text (HildonTouchSelector * selector,
1105 GtkTreeModel *model;
1107 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1108 g_return_if_fail (text != NULL);
1110 model = hildon_touch_selector_get_model (HILDON_TOUCH_SELECTOR (selector), 0);
1112 g_return_if_fail (GTK_IS_LIST_STORE (model));
1114 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1115 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text, -1);
1119 * hildon_touch_selector_prepend_text:
1120 * @selector: A #HildonTouchSelector.
1121 * @text: a non %NULL text string.
1123 * Prepends a new entry in a #HildonTouchSelector created with
1124 * hildon_touch_selector_new_text().
1129 hildon_touch_selector_prepend_text (HildonTouchSelector * selector,
1133 GtkTreeModel *model;
1135 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1136 g_return_if_fail (text != NULL);
1138 model = hildon_touch_selector_get_model (HILDON_TOUCH_SELECTOR (selector), 0);
1140 g_return_if_fail (GTK_IS_LIST_STORE (model));
1142 gtk_list_store_prepend (GTK_LIST_STORE (model), &iter);
1143 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text, -1);
1147 * hildon_touch_selector_insert_text:
1148 * @selector: a #HildonTouchSelector.
1149 * @position: the position to insert @text.
1150 * @text: A non %NULL text string.
1152 * Inserts a new entry in a particular position of a
1153 * #HildonTouchSelector created with hildon_touch_selector_new_text().
1158 hildon_touch_selector_insert_text (HildonTouchSelector * selector,
1159 gint position, const gchar * text)
1162 GtkTreeModel *model;
1164 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1165 g_return_if_fail (text != NULL);
1166 g_return_if_fail (position >= 0);
1168 model = hildon_touch_selector_get_model (HILDON_TOUCH_SELECTOR (selector), 0);
1170 g_return_if_fail (GTK_IS_LIST_STORE (model));
1172 gtk_list_store_insert (GTK_LIST_STORE (model), &iter, position);
1173 gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, text, -1);
1177 * hildon_touch_selector_append_column
1178 * @selector: a #HildonTouchSelector
1179 * @model: the #GtkTreeModel with the data of the column
1180 * @cell_renderer: The #GtkCellRenderer where to draw each row contents.
1181 * @Varargs: a %NULL-terminated pair of attributes and column numbers.
1183 * This functions adds a new column to the widget, whose data will
1184 * be obtained from the model. Only widgets added this way should used on
1185 * the selection logic, the print function, the #HildonTouchSelector::changed
1186 * signal, etc. Internally, a #GtkTreeView will be added to the widget, using
1187 * @model as the data source.
1189 * You can optionally pass a #GtkCellRenderer in @cell_renderer,
1190 * together with a %NULL-terminated list of pairs property/value, in
1191 * the same way you would use gtk_tree_view_column_set_attributes().
1192 * This will pack @cell_renderer at the start of the column, expanded
1193 * by default. If you prefer not to add it this way, you can simply
1194 * pass %NULL to @cell_renderer and use the #GtkCellLayout interface
1195 * on the returned #HildonTouchSelectorColumn to set your
1196 * renderers. Please note that the returned #HildonTouchSelectorColumn
1197 * is owned by @selector, you shouldn't unref it after setting it
1200 * Initially, the returned #HildonTouchSelectorColumn will have its
1201 * #HildonTouchSelectorColumn:text-column property unset. You should set
1202 * it to a column in @model with type %G_TYPE_STRING. See
1203 * hildon_touch_selector_column_set_text_column().
1205 * Returns: the new column added added, %NULL otherwise.
1210 HildonTouchSelectorColumn*
1211 hildon_touch_selector_append_column (HildonTouchSelector * selector,
1212 GtkTreeModel * model,
1213 GtkCellRenderer * cell_renderer, ...)
1216 HildonTouchSelectorColumn *new_column = NULL;
1217 gboolean emit_changed = FALSE;
1220 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1221 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
1223 if (model != NULL) {
1225 va_start (args, cell_renderer);
1226 new_column = _create_new_column (selector, model, &emit_changed, cell_renderer, args);
1229 selector->priv->columns = g_slist_append (selector->priv->columns,
1231 gtk_box_pack_start (GTK_BOX (selector->priv->hbox),
1232 new_column->priv->panarea,
1235 gtk_widget_show_all (new_column->priv->panarea);
1237 if (selector->priv->initial_scroll) {
1238 _hildon_touch_selector_center_on_selected_items (selector, new_column);
1245 g_signal_emit (selector, hildon_touch_selector_signals[COLUMNS_CHANGED], 0);
1247 colnum = g_slist_length (selector->priv->columns);
1248 hildon_touch_selector_emit_value_changed (selector, colnum);
1255 * hildon_touch_selector_append_text_column
1256 * @selector: a #HildonTouchSelector
1257 * @model: a #GtkTreeModel with data for the column
1258 * @center: whether to center the text on the column
1260 * Equivalent to hildon_touch_selector_append_column(), but using a
1261 * default text cell renderer. This is the most common use case of the
1264 * Returns: the new column added, NULL otherwise.
1268 HildonTouchSelectorColumn*
1269 hildon_touch_selector_append_text_column (HildonTouchSelector * selector,
1270 GtkTreeModel * model, gboolean center)
1272 gfloat xalign = center ? 0.5 : 0.0;
1273 GtkCellRenderer *renderer;
1275 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1276 g_return_val_if_fail (GTK_IS_TREE_MODEL (model), NULL);
1278 renderer = gtk_cell_renderer_text_new ();
1280 g_object_set (renderer,
1285 return hildon_touch_selector_append_column (selector, model, renderer,
1290 * hildon_touch_selector_remove_column:
1291 * @selector: a #HildonTouchSelector
1292 * @column: the position of the column to be removed
1294 * Removes a column from @selector.
1296 * Returns: %TRUE if the column was removed, %FALSE otherwise
1301 hildon_touch_selector_remove_column (HildonTouchSelector * selector, gint column)
1303 HildonTouchSelectorColumn *current_column = NULL;
1304 HildonTouchSelectorPrivate *priv;
1306 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), FALSE);
1307 g_return_val_if_fail (column <
1308 hildon_touch_selector_get_num_columns (selector), FALSE);
1310 priv = HILDON_TOUCH_SELECTOR_GET_PRIVATE (selector);
1311 current_column = g_slist_nth_data (priv->columns, column);
1313 gtk_container_remove (GTK_CONTAINER (priv->hbox), current_column->priv->panarea);
1314 priv->columns = g_slist_remove (priv->columns, current_column);
1315 g_object_unref (current_column);
1317 g_signal_emit (selector, hildon_touch_selector_signals[COLUMNS_CHANGED], 0);
1323 * hildon_touch_selector_set_column_attributes:
1324 * @selector: a #HildonTouchSelector
1325 * @num_column: the number of the column whose attributes we're setting
1326 * @cell_renderer: the #GtkCellRendere we're setting the attributes of
1327 * @Varargs: A %NULL-terminated list of attributes.
1329 * Sets the attributes for the given column. The attributes must be given
1330 * in attribute/column pairs, just like in gtk_tree_view_column_set_attributes().
1331 * All existing attributes are removed and replaced with the new ones.
1333 * Deprecated: #HildonTouchSelectorColumn implements #GtkCellLayout, use this
1334 * interface instead. See
1335 * hildon_touch_selector_get_column().
1340 hildon_touch_selector_set_column_attributes (HildonTouchSelector * selector,
1342 GtkCellRenderer * cell_renderer,
1346 GtkTreeViewColumn *tree_column = NULL;
1347 HildonTouchSelectorColumn *current_column = NULL;
1348 gchar *attribute = NULL;
1351 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1352 g_return_if_fail (num_column <
1353 hildon_touch_selector_get_num_columns (selector));
1355 current_column = g_slist_nth_data (selector->priv->columns, num_column);
1357 tree_column = gtk_tree_view_get_column (current_column->priv->tree_view, 0);
1358 gtk_tree_view_remove_column (current_column->priv->tree_view, tree_column);
1360 tree_column = gtk_tree_view_column_new ();
1361 gtk_tree_view_column_pack_start (tree_column, cell_renderer, TRUE);
1363 va_start (args, cell_renderer);
1364 attribute = va_arg (args, gchar *);
1366 gtk_tree_view_column_clear_attributes (tree_column, cell_renderer);
1368 while (attribute != NULL) {
1369 value = va_arg (args, gint);
1370 gtk_tree_view_column_add_attribute (tree_column, cell_renderer,
1372 attribute = va_arg (args, gchar *);
1377 gtk_tree_view_append_column (current_column->priv->tree_view, tree_column);
1381 * hildon_touch_selector_get_num_columns:
1382 * @selector: a #HildonTouchSelector
1384 * Gets the number of columns in the #HildonTouchSelector.
1386 * Returns: the number of columns in @selector.
1391 hildon_touch_selector_get_num_columns (HildonTouchSelector * selector)
1393 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), -1);
1395 return g_slist_length (selector->priv->columns);
1399 * hildon_touch_selector_get_column_selection_mode:
1400 * @selector: a #HildonTouchSelector
1402 * Gets the selection mode of @selector.
1404 * Returns: one of #HildonTouchSelectorSelectionMode
1408 HildonTouchSelectorSelectionMode
1409 hildon_touch_selector_get_column_selection_mode (HildonTouchSelector * selector)
1411 HildonTouchSelectorSelectionMode result =
1412 HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE;
1413 GtkSelectionMode treeview_mode = GTK_SELECTION_BROWSE;
1414 HildonTouchSelectorColumn *column = NULL;
1415 GtkTreeSelection *selection = NULL;
1417 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), result);
1418 g_return_val_if_fail (hildon_touch_selector_get_num_columns (selector) > 0,
1421 column = HILDON_TOUCH_SELECTOR_COLUMN (selector->priv->columns->data);
1423 selection = gtk_tree_view_get_selection (column->priv->tree_view);
1424 treeview_mode = gtk_tree_selection_get_mode (selection);
1427 if (treeview_mode == GTK_SELECTION_MULTIPLE) {
1428 result = HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE;
1430 result = HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE;
1437 * hildon_touch_selector_set_column_selection_mode:
1438 * @selector: a #HildonTouchSelector
1439 * @mode: the #HildonTouchSelectorMode for @selector
1441 * Sets the selection mode for @selector. See #HildonTouchSelectorSelectionMode.
1446 hildon_touch_selector_set_column_selection_mode (HildonTouchSelector * selector,
1447 HildonTouchSelectorSelectionMode mode)
1449 GtkTreeView *tv = NULL;
1450 HildonTouchSelectorColumn *column = NULL;
1451 GtkTreeSelection *selection = NULL;
1452 GtkSelectionMode treeview_mode = GTK_SELECTION_MULTIPLE;
1454 HildonTouchSelectorSelectionMode current_mode;
1456 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1457 g_return_if_fail (hildon_touch_selector_get_num_columns (selector) > 0);
1459 current_mode = hildon_touch_selector_get_column_selection_mode (selector);
1461 if (current_mode == mode) {
1465 column = HILDON_TOUCH_SELECTOR_COLUMN ((g_slist_nth (selector->priv->columns, 0))->data);
1466 tv = column->priv->tree_view;
1470 case HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE:
1471 treeview_mode = GTK_SELECTION_BROWSE;
1473 case HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE:
1474 treeview_mode = GTK_SELECTION_MULTIPLE;
1478 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
1479 gtk_tree_selection_set_mode (selection, treeview_mode);
1481 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
1482 gtk_tree_model_get_iter_first (column->priv->model, &iter);
1483 gtk_tree_selection_unselect_all (selection);
1484 gtk_tree_selection_select_iter (selection, &iter);
1486 /* the column changed was the first one */
1487 hildon_touch_selector_emit_value_changed (selector, 0);
1493 * hildon_touch_selector_set_print_func:
1494 * @selector: a #HildonTouchSelector
1495 * @func: a #HildonTouchSelectorPrintFunc function
1497 * Sets the function to be used by hildon_touch_selector_get_current_text().
1498 * See hildon_touch_selector_set_print_func_full().
1503 hildon_touch_selector_set_print_func (HildonTouchSelector * selector,
1504 HildonTouchSelectorPrintFunc func)
1506 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1508 hildon_touch_selector_set_print_func_full (selector, func, NULL, NULL);
1512 * hildon_touch_selector_set_print_func_full:
1513 * @selector: a #HildonTouchSelector
1514 * @func: a #HildonTouchSelectorPrintFunc function
1515 * @user_data: a pointer to user data or %NULL
1516 * @destroy_func: a callback for freeing the user data or %NULL
1518 * Sets the function to be used by hildon_touch_selector_get_current_text()
1519 * to produce a text representation of the currently selected items in @selector.
1520 * The default function will return a concatenation of comma separated items
1521 * selected in each column in @selector. Use this to override this method if you
1522 * need a particular representation for your application.
1527 hildon_touch_selector_set_print_func_full (HildonTouchSelector *selector,
1528 HildonTouchSelectorPrintFunc func,
1530 GDestroyNotify destroy_func)
1532 gpointer old_user_data;
1533 GDestroyNotify old_destroy_func;
1535 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1537 old_user_data = selector->priv->print_user_data;
1538 old_destroy_func = selector->priv->print_destroy_func;
1540 selector->priv->print_func = func;
1541 selector->priv->print_user_data = user_data;
1542 selector->priv->print_destroy_func = destroy_func;
1544 if (old_destroy_func && old_user_data != user_data)
1545 (*old_destroy_func) (old_user_data);
1549 * hildon_touch_selector_get_print_func:
1550 * @selector: a #HildonTouchSelector
1552 * Gets the #HildonTouchSelectorPrintFunc currently used. See
1553 * hildon_touch_selector_set_print_func().
1555 * Returns: a #HildonTouchSelectorPrintFunc or %NULL if the default
1556 * one is currently used.
1558 HildonTouchSelectorPrintFunc
1559 hildon_touch_selector_get_print_func (HildonTouchSelector * selector)
1561 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1563 return selector->priv->print_func;
1567 * hildon_touch_selector_set_active:
1568 * @selector: a #HildonTouchSelector
1569 * @column: column number
1570 * @index: the index of the item to select, or -1 to have no active item
1572 * Sets the active item of the #HildonTouchSelector to @index. The
1573 * column number is taken from @column.
1575 * @selector must be in %HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE
1580 hildon_touch_selector_set_active (HildonTouchSelector *selector,
1584 GtkTreeSelection *selection = NULL;
1585 HildonTouchSelectorColumn *current_column = NULL;
1586 HildonTouchSelectorSelectionMode mode;
1589 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1590 g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1591 mode = hildon_touch_selector_get_column_selection_mode (selector);
1592 g_return_if_fail (mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE);
1594 current_column = g_slist_nth_data (selector->priv->columns, column);
1596 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (current_column->priv->tree_view));
1597 path = gtk_tree_path_new_from_indices (index, -1);
1598 gtk_tree_selection_unselect_all (selection);
1600 gtk_tree_selection_select_path (selection, path);
1602 hildon_touch_selector_emit_value_changed (selector, column);
1604 gtk_tree_path_free (path);
1608 * hildon_touch_selector_get_active:
1609 * @selector: a #HildonTouchSelector
1610 * @column: column number
1612 * Returns the index of the currently active item in column number
1613 * @column, or -1 if there's no active item.
1615 * @selector must be in %HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE
1617 * Returns: an integer which is the index of the currently active
1618 * item, or -1 if there's no active item.
1623 hildon_touch_selector_get_active (HildonTouchSelector *selector,
1626 GtkTreeSelection *selection = NULL;
1627 HildonTouchSelectorColumn *current_column = NULL;
1628 HildonTouchSelectorSelectionMode mode;
1629 GtkTreeModel *model;
1634 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), -1);
1635 g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector), -1);
1636 mode = hildon_touch_selector_get_column_selection_mode (selector);
1637 g_return_val_if_fail (mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE, -1);
1639 current_column = g_slist_nth_data (selector->priv->columns, column);
1641 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (current_column->priv->tree_view));
1642 g_return_val_if_fail (gtk_tree_selection_get_selected (selection, NULL, &iter), -1);
1644 model = gtk_tree_view_get_model (GTK_TREE_VIEW (current_column->priv->tree_view));
1645 path = gtk_tree_model_get_path (model, &iter);
1646 index = (gtk_tree_path_get_indices (path))[0];
1648 gtk_tree_path_free (path);
1654 * hildon_touch_selector_get_selected:
1655 * @selector: a #HildonTouchSelector
1656 * @column: the column number we want to get the element
1657 * @iter: #GtkTreeIter currently selected
1659 * Sets @iter to the currently selected node on the nth-column, if selection is
1660 * set to %HILDON_TOUCH_SELECTOR_SINGLE or %HILDON_TOUCH_SELECTOR_MULTIPLE with
1661 * a column different that the first one. @iter may be %NULL if you just want to
1662 * test if selection has any selected items.
1664 * This function will not work if selection is in
1665 * %HILDON_TOUCH_SELECTOR_MULTIPLE mode and the column is the first one.
1667 * See gtk_tree_selection_get_selected() for more information.
1669 * Returns: %TRUE if @iter was correctly set, %FALSE otherwise
1674 hildon_touch_selector_get_selected (HildonTouchSelector * selector,
1675 gint column, GtkTreeIter * iter)
1677 GtkTreeSelection *selection = NULL;
1678 HildonTouchSelectorColumn *current_column = NULL;
1679 HildonTouchSelectorSelectionMode mode;
1681 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), FALSE);
1682 g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector),
1684 mode = hildon_touch_selector_get_column_selection_mode (selector);
1685 g_return_val_if_fail
1686 ((mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE) ||
1687 ((mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE)&&(column>0)),
1690 current_column = g_slist_nth_data (selector->priv->columns, column);
1693 gtk_tree_view_get_selection (GTK_TREE_VIEW (current_column->priv->tree_view));
1695 return gtk_tree_selection_get_selected (selection, NULL, iter);
1699 * hildon_touch_selector_select_iter
1700 * @selector: a #HildonTouchSelector
1701 * @column: the column to selects
1702 * @iter: the #GtkTreeIter to be selected
1703 * @scroll_to: whether to smoothly scroll to the item
1705 * Sets the currently selected item in the column @column to the one pointed by @iter,
1706 * optionally smoothly scrolling to it.
1711 hildon_touch_selector_select_iter (HildonTouchSelector * selector,
1712 gint column, GtkTreeIter * iter,
1716 GtkTreeModel *model;
1717 HildonTouchSelectorColumn *current_column = NULL;
1718 GtkTreeView *tv = NULL;
1719 GtkTreeSelection *selection = NULL;
1721 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1722 g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1724 current_column = g_slist_nth_data (selector->priv->columns, column);
1726 tv = current_column->priv->tree_view;
1727 selection = gtk_tree_view_get_selection (tv);
1728 model = gtk_tree_view_get_model (tv);
1729 path = gtk_tree_model_get_path (model, iter);
1731 gtk_tree_selection_select_iter (selection, iter);
1734 hildon_touch_selector_scroll_to (current_column, tv, path);
1737 hildon_touch_selector_emit_value_changed (selector, column);
1739 gtk_tree_path_free (path);
1743 * hildon_touch_selector_unselect_iter
1744 * @selector: a #HildonTouchSelector
1745 * @column: the column to unselects from
1746 * @iter: the #GtkTreeIter to be unselected
1748 * Unselect the item pointed by @iter in the column @column
1753 void hildon_touch_selector_unselect_iter (HildonTouchSelector * selector,
1757 HildonTouchSelectorColumn *current_column = NULL;
1758 GtkTreeSelection *selection = NULL;
1760 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1761 g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1763 current_column = g_slist_nth_data (selector->priv->columns, column);
1764 selection = gtk_tree_view_get_selection (current_column->priv->tree_view);
1765 gtk_tree_selection_unselect_iter (selection, iter);
1767 hildon_touch_selector_emit_value_changed (selector, column);
1771 * hildon_touch_selector_unselect_all:
1772 * @selector: a #HildonTouchSelector
1773 * @column: the position of the column to get the selected rows from
1775 * Unselects all the selected items in the column @column.
1780 hildon_touch_selector_unselect_all (HildonTouchSelector * selector,
1783 HildonTouchSelectorColumn *current_column = NULL;
1784 GtkTreeSelection *selection = NULL;
1786 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
1787 g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1789 current_column = g_slist_nth_data (selector->priv->columns, column);
1790 selection = gtk_tree_view_get_selection (current_column->priv->tree_view);
1791 gtk_tree_selection_unselect_all (selection);
1793 hildon_touch_selector_emit_value_changed (selector, column);
1797 * hildon_touch_selector_get_selected_rows:
1798 * @selector: a #HildonTouchSelector
1799 * @column: the position of the column to get the selected rows from
1801 * Creates a list of #GtkTreePath<!-- -->s of all selected rows in a column. Additionally,
1802 * if you to plan to modify the model after calling this function, you may
1803 * want to convert the returned list into a list of GtkTreeRowReferences. To do this,
1804 * you can use gtk_tree_row_reference_new().
1806 * See gtk_tree_selection_get_selected_rows() for more information.
1808 * Returns: A new #GList containing a #GtkTreePath for each selected row in the column @column.
1813 hildon_touch_selector_get_selected_rows (HildonTouchSelector * selector,
1816 GList *result = NULL;
1817 HildonTouchSelectorColumn *current_column = NULL;
1818 GtkTreeSelection *selection = NULL;
1820 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1821 g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector),
1824 current_column = g_slist_nth_data (selector->priv->columns, column);
1825 selection = gtk_tree_view_get_selection (current_column->priv->tree_view);
1827 result = gtk_tree_selection_get_selected_rows (selection, NULL);
1833 * hildon_touch_selector_get_model:
1834 * @selector: a #HildonTouchSelector
1835 * @column: the position of the column in @selector
1837 * Gets the model of a column of @selector.
1839 * Returns: the #GtkTreeModel for the column @column of @selector.
1844 hildon_touch_selector_get_model (HildonTouchSelector * selector, gint column)
1846 HildonTouchSelectorColumn *current_column = NULL;
1848 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1849 g_return_val_if_fail (column < hildon_touch_selector_get_num_columns (selector),
1852 current_column = g_slist_nth_data (selector->priv->columns, column);
1854 return current_column->priv->model;
1858 on_row_changed (GtkTreeModel *model,
1863 HildonTouchSelector *selector;
1864 HildonTouchSelectorColumn *current_column;
1869 selector = HILDON_TOUCH_SELECTOR (userdata);
1871 for (col = selector->priv->columns; col != NULL; col = col->next) {
1872 current_column = HILDON_TOUCH_SELECTOR_COLUMN (col->data);
1873 if (current_column->priv->model == model &&
1874 gtk_tree_selection_path_is_selected (gtk_tree_view_get_selection (current_column->priv->tree_view),
1876 hildon_touch_selector_emit_value_changed (selector, column);
1883 _hildon_touch_selector_set_model (HildonTouchSelector * selector,
1884 gint column, GtkTreeModel * model)
1886 HildonTouchSelectorColumn *current_column = NULL;
1889 HILDON_TOUCH_SELECTOR_COLUMN (g_slist_nth_data (selector->priv->columns, column));
1891 if (current_column->priv->model) {
1892 g_signal_handlers_disconnect_by_func (current_column->priv->model,
1893 on_row_changed, selector);
1895 current_column->priv->model = model;
1896 gtk_tree_view_set_model (current_column->priv->tree_view,
1897 current_column->priv->model);
1898 g_signal_connect (model, "row-changed",
1899 G_CALLBACK (on_row_changed), selector);
1903 * hildon_touch_selector_set_model:
1904 * @selector: a #HildonTouchSelector
1905 * @column: the position of the column to set the model to
1906 * @model: a #GtkTreeModel
1908 * Sets the #GtkTreeModel for a particular column in @model.
1913 hildon_touch_selector_set_model (HildonTouchSelector * selector,
1914 gint column, GtkTreeModel * model)
1916 g_return_if_fail (HILDON_TOUCH_SELECTOR (selector));
1917 g_return_if_fail (column < hildon_touch_selector_get_num_columns (selector));
1919 HILDON_TOUCH_SELECTOR_GET_CLASS (selector)->set_model (selector, column, model);
1923 * hildon_touch_selector_get_current_text:
1924 * @selector: a #HildonTouchSelector
1926 * Returns a string representing the currently selected items for
1927 * each column of @selector. See hildon_touch_selector_set_print_func().
1929 * Returns: a newly allocated string.
1934 hildon_touch_selector_get_current_text (HildonTouchSelector * selector)
1936 gchar *result = NULL;
1937 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
1939 if (selector->priv->print_func) {
1940 result = (*selector->priv->print_func) (selector, selector->priv->print_user_data);
1942 result = _default_print_func (selector, NULL);
1949 search_nearest_element (HildonPannableArea *panarea,
1951 GList *selected_rows,
1952 GtkTreePath **nearest_path)
1954 GtkAdjustment *adj = NULL;
1955 gdouble target_value = 0;
1958 GtkTreePath *path = NULL;
1960 gdouble nearest_distance = -1;
1961 gdouble current_distance = -1;
1962 GtkTreePath *result_path = NULL;
1964 g_assert (nearest_path != NULL);
1966 if (selected_rows == NULL) {
1967 *nearest_path = NULL;
1971 adj = hildon_pannable_area_get_vadjustment (panarea);
1972 g_return_if_fail (adj != NULL);
1974 /* we add this in order to check the nearest to the center of
1976 target_value = gtk_adjustment_get_value (adj) + adj->page_size/2;
1978 path = result_path = selected_rows->data;
1979 gtk_tree_view_get_background_area (tv, path, NULL, &rect);
1980 gtk_tree_view_convert_bin_window_to_tree_coords (tv, 0, rect.y, NULL, &y);
1981 nearest_distance = abs (target_value - y);
1983 for (iter = selected_rows->next; iter; iter = g_list_next (iter)) {
1984 gtk_tree_view_get_background_area (tv, path, NULL, &rect);
1985 gtk_tree_view_convert_bin_window_to_tree_coords (tv, 0, rect.y, NULL, &y);
1986 current_distance = abs (target_value - y);
1987 if (current_distance < nearest_distance) {
1988 nearest_distance = current_distance;
1993 *nearest_path = result_path;
1997 on_realize_cb (GtkWidget *widget,
2000 HildonTouchSelectorColumn *column = NULL;
2004 column = HILDON_TOUCH_SELECTOR_COLUMN (data);
2006 if (column->priv->initial_path) {
2007 gtk_tree_view_get_background_area (GTK_TREE_VIEW (column->priv->tree_view),
2008 column->priv->initial_path, NULL, &rect);
2009 gtk_tree_view_convert_bin_window_to_tree_coords
2010 (GTK_TREE_VIEW (column->priv->tree_view),
2011 0, rect.y, NULL, &y);
2013 hildon_pannable_area_scroll_to (HILDON_PANNABLE_AREA (column->priv->panarea),
2016 gtk_tree_path_free (column->priv->initial_path);
2018 column->priv->initial_path = NULL;
2022 g_signal_handler_disconnect (column->priv->panarea,
2023 column->priv->realize_handler);
2029 hildon_touch_selector_scroll_to (HildonTouchSelectorColumn *column,
2033 if (GTK_WIDGET_REALIZED (column->priv->panarea)) {
2037 gtk_tree_view_get_background_area (tv,
2039 gtk_tree_view_convert_bin_window_to_tree_coords (tv,
2040 0, rect.y, NULL, &y);
2042 hildon_pannable_area_scroll_to (HILDON_PANNABLE_AREA
2043 (column->priv->panarea), -1, y);
2045 if (column->priv->realize_handler != 0) {
2047 if (column->priv->initial_path) {
2048 gtk_tree_path_free (column->priv->initial_path);
2049 column->priv->initial_path = NULL;
2052 g_signal_handler_disconnect (column->priv->panarea,
2053 column->priv->realize_handler);
2054 column->priv->realize_handler = 0;
2057 column->priv->initial_path = gtk_tree_path_copy (path);
2058 column->priv->realize_handler =
2059 g_signal_connect_after (G_OBJECT (column->priv->panarea), "realize",
2060 G_CALLBACK (on_realize_cb),
2067 * Center on the selected item of a concrete column
2069 * Returns: TRUE if was able to do that
2073 _hildon_touch_selector_center_on_selected_items (HildonTouchSelector *selector,
2074 HildonTouchSelectorColumn *column)
2076 GtkTreePath *path = NULL;
2077 GList *selected_rows = NULL;
2078 gint num_column = -1;
2080 num_column = g_slist_index (selector->priv->columns, column);
2082 selected_rows = hildon_touch_selector_get_selected_rows (selector, num_column);
2083 if (selected_rows) {
2084 search_nearest_element (HILDON_PANNABLE_AREA (column->priv->panarea),
2085 GTK_TREE_VIEW (column->priv->tree_view),
2090 hildon_touch_selector_scroll_to (column,
2091 GTK_TREE_VIEW (column->priv->tree_view),
2097 g_list_foreach (selected_rows, (GFunc) (gtk_tree_path_free), NULL);
2098 g_list_free (selected_rows);
2105 _hildon_touch_selector_has_multiple_selection (HildonTouchSelector * selector)
2107 HildonTouchSelectorSelectionMode mode;
2110 n_columns = hildon_touch_selector_get_num_columns (selector);
2111 mode = hildon_touch_selector_get_column_selection_mode (selector);
2113 return ((n_columns > 1) || (mode == HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE));
2117 * hildon_touch_selector_has_multiple_selection:
2118 * @selector: A #HildonTouchSelector
2120 * Determines whether @selector is complex enough to actually require an
2121 * extra selection step than only picking an item. This is normally %TRUE
2122 * if @selector has multiple columns, multiple selection, or when it is a
2123 * more complex widget, like #HildonTouchSelectorEntry.
2125 * This information is useful for widgets containing a #HildonTouchSelector,
2126 * like #HildonPickerDialog, that could need a "Done" button, in case that
2127 * its internal #HildonTouchSelector has multiple columns, for instance.
2129 * Returns: %TRUE if @selector requires multiple selection steps.
2134 hildon_touch_selector_has_multiple_selection (HildonTouchSelector * selector)
2136 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), FALSE);
2138 return HILDON_TOUCH_SELECTOR_GET_CLASS (selector)->has_multiple_selection (selector);
2143 * hildon_touch_selector_get_column:
2144 * @selector: A #HildonTouchSelector
2145 * @column: a column number
2147 * Use this method to retrieve a #HildonTouchSelectorColumn. Then, you can use
2148 * the #GtkCellLayout interface to set up the layout of the column.
2150 * Returns: the @column<!-- -->-th #HildonTouchSelectorColumn in @selector
2154 HildonTouchSelectorColumn *
2155 hildon_touch_selector_get_column (HildonTouchSelector * selector,
2158 gint num_columns = -1;
2160 g_return_val_if_fail (HILDON_IS_TOUCH_SELECTOR (selector), NULL);
2161 num_columns = hildon_touch_selector_get_num_columns (selector);
2162 g_return_val_if_fail (column < num_columns && column >= 0, NULL);
2164 return g_slist_nth_data (selector->priv->columns, column);
2169 * hildon_touch_selector_center_on_selected:
2170 * @selector: a #HildonTouchSelector
2172 * Ensures all the columns in a #HildonTouchSelector show a selected
2173 * item. If one of the columns is in
2174 * %HILDON_TOUCH_SELECTOR_SELECTION_MODE_MULTIPLE mode, that column
2175 * will be scrolled to ensure the selected item that is closest to the
2176 * currently visible area is shown.
2181 hildon_touch_selector_center_on_selected (HildonTouchSelector *selector)
2183 GSList *iter = NULL;
2185 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
2187 for (iter = selector->priv->columns; iter; iter = g_slist_next (iter)) {
2188 _hildon_touch_selector_center_on_selected_items (selector,
2189 HILDON_TOUCH_SELECTOR_COLUMN (iter->data));
2194 * hildon_touch_selector_optimal_size_request
2195 * @selector: a #HildonTouchSelector
2196 * @requisition: a #GtkRequisition
2198 * Gets the optimal size request of the touch selector. This function is mostly
2199 * intended for dialog implementations that include a #HildonTouchSelector and
2200 * want to optimize the screen real state, for example, when you want a dialog
2201 * to show as much of the selector, avoiding any extra empty space below the
2204 * See #HildonPickerDialog implementation for an example.
2206 * This function is oriented to be used in the size_request of a dialog or window,
2207 * if you are not sure do not use it.
2209 * There is a precondition to this function: Since this function does not
2210 * call the "size_request" method, it can only be used when you know that
2211 * gtk_widget_size_request() has been called since the last time a resize was
2217 hildon_touch_selector_optimal_size_request (HildonTouchSelector *selector,
2218 GtkRequisition *requisition)
2220 GSList *iter = NULL;
2222 gint base_height = 0;
2224 g_return_if_fail (HILDON_IS_TOUCH_SELECTOR (selector));
2226 iter = selector->priv->columns;
2228 /* Default optimal values are the current ones */
2229 gtk_widget_get_child_requisition (GTK_WIDGET (selector),
2233 height = requisition->height;
2235 /* we use the normal requisition as base, as the touch selector can has
2236 extra widgets, not only the columns (ie: HildonTouchSelectorEntry) */
2237 base_height = requisition->height;
2240 /* Compute optimal height for the columns */
2242 HildonTouchSelectorColumn *column;
2244 GtkRequisition child_requisition = {0};
2246 column = HILDON_TOUCH_SELECTOR_COLUMN (iter->data);
2247 child = GTK_WIDGET (column->priv->tree_view);
2249 gtk_widget_get_child_requisition (child, &child_requisition);
2251 height = MAX (height, child_requisition.height);
2253 iter = g_slist_next (iter);
2256 requisition->height = base_height + height;