[gtk+/wip/combo] Implement multi-selection
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/combo] Implement multi-selection
- Date: Wed, 7 Jan 2015 05:23:45 +0000 (UTC)
commit abae79f170f5ab4866a3db5c28639e1b5fd434dd
Author: Matthias Clasen <mclasen redhat com>
Date: Tue Jan 6 08:59:59 2015 -0500
Implement multi-selection
Add a selection-mode property to GtkCombo, and implement
suitable behaviors. This requires the selected property
to change to an array, instead of a single ID. At the
same time change the terminology from 'active' to 'selected'.
gtk/gtkcombo.c | 402 ++++++++++++++++++++++++++++++++++++-----------
gtk/gtkcombo.h | 25 +++-
gtk/ui/gtkcombo.ui | 3 +-
tests/testnewcombo.c | 107 +++++++++----
4 files changed, 401 insertions(+), 136 deletions(-)
---
diff --git a/gtk/gtkcombo.c b/gtk/gtkcombo.c
index 72d6753..e23be6d 100644
--- a/gtk/gtkcombo.c
+++ b/gtk/gtkcombo.c
@@ -28,6 +28,7 @@
#include "gtkbutton.h"
#include "gtkcontainer.h"
#include "gtkentry.h"
+#include "gtkenums.h"
#include "gtkframe.h"
#include "gtklabel.h"
#include "gtklistbox.h"
@@ -37,6 +38,7 @@
#include "gtksearchentry.h"
#include "gtkseparator.h"
#include "gtkstack.h"
+#include "gtktypebuiltins.h"
#include "gtkintl.h"
#include "gtkprivate.h"
@@ -54,9 +56,9 @@
*
* You can add items to a GtkCombo using gtk_combo_add_item() and remove
* them with gtk_combo_remove_item(). Each item has an ID that is returned
- * as the value of the #GtkCombo:active property when the item is currently
- * selected, an optional text that is used to display the item, and an
- * optional sort key that is used to sort the items.
+ * as the value of the #GtkCombo:selected property when the item is
+ * currently selected, an optional text that is used to display the item,
+ * and an optional sort key that is used to sort the items.
*
* If you want to allow the user to enter custom values, use
* gtk_combo_set_allow_custom().
@@ -437,6 +439,8 @@ static GtkWidget *group_get_item (GtkCombo *combo,
const gchar *group);
static void ensure_group (GtkCombo *combo,
const gchar *group);
+static void set_selected (GtkCombo *combo,
+ const gchar **ids);
static void gtk_combo_buildable_init (GtkBuildableIface *iface);
@@ -445,12 +449,13 @@ struct _GtkCombo
{
GtkBin parent;
- const gchar *active;
+ GPtrArray *selected;
gchar *placeholder;
gchar *custom_text;
gboolean allow_custom;
+ GtkSelectionMode selection_mode;
- GtkWidget *active_label;
+ GtkWidget *selected_label;
GtkWidget *popover;
GtkWidget *scrolled_window;
GtkWidget *list;
@@ -471,10 +476,11 @@ struct _GtkComboClass
};
enum {
- PROP_ACTIVE = 1,
+ PROP_SELECTED = 1,
PROP_PLACEHOLDER_TEXT,
PROP_ALLOW_CUSTOM,
- PROP_CUSTOM_TEXT
+ PROP_CUSTOM_TEXT,
+ PROP_SELECTION_MODE
};
static GtkBuildableIface *buildable_parent_iface = NULL;
@@ -488,6 +494,11 @@ gtk_combo_init (GtkCombo *combo)
{
g_type_ensure (GTK_TYPE_COMBO_ROW);
+ combo->selected = g_ptr_array_new ();
+ g_ptr_array_add (combo->selected, NULL);
+
+ combo->selection_mode = GTK_SELECTION_BROWSE;
+
gtk_widget_init_template (GTK_WIDGET (combo));
gtk_list_box_set_header_func (GTK_LIST_BOX (combo->list), list_header_func, combo, NULL);
@@ -508,6 +519,7 @@ gtk_combo_finalize (GObject *object)
g_free (combo->placeholder);
g_free (combo->custom_text);
+ g_ptr_array_free (combo->selected, TRUE);
G_OBJECT_CLASS (gtk_combo_parent_class)->finalize (object);
}
@@ -522,8 +534,8 @@ gtk_combo_set_property (GObject *object,
switch (prop_id)
{
- case PROP_ACTIVE:
- gtk_combo_set_active (combo, g_value_get_string (value));
+ case PROP_SELECTED:
+ set_selected (combo, (const gchar **)g_value_get_boxed (value));
break;
case PROP_PLACEHOLDER_TEXT:
gtk_combo_set_placeholder_text (combo, g_value_get_string (value));
@@ -534,6 +546,9 @@ gtk_combo_set_property (GObject *object,
case PROP_CUSTOM_TEXT:
gtk_combo_set_custom_text (combo, g_value_get_string (value));
break;
+ case PROP_SELECTION_MODE:
+ gtk_combo_set_selection_mode (combo, g_value_get_enum (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -549,8 +564,8 @@ gtk_combo_get_property (GObject *object,
switch (prop_id)
{
- case PROP_ACTIVE:
- g_value_set_string (value, gtk_combo_get_active (combo));
+ case PROP_SELECTED:
+ g_value_set_boxed (value, (gconstpointer)combo->selected->pdata);
break;
case PROP_PLACEHOLDER_TEXT:
g_value_set_string (value, gtk_combo_get_placeholder_text (combo));
@@ -561,6 +576,9 @@ gtk_combo_get_property (GObject *object,
case PROP_CUSTOM_TEXT:
g_value_set_string (value, gtk_combo_get_custom_text (combo));
break;
+ case PROP_SELECTION_MODE:
+ g_value_set_enum (value, gtk_combo_get_selection_mode (combo));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -577,18 +595,18 @@ gtk_combo_class_init (GtkComboClass *class)
object_class->get_property = gtk_combo_get_property;
/**
- * GtkCombo:active:
+ * GtkCombo:selected:
*
- * The ID of the currently selected item, or %NULL
- * if no item is currently selected.
+ * The IDs of the currently selected items, as a
+ * %NULL-terminated array of strings.
*/
g_object_class_install_property (object_class,
- PROP_ACTIVE,
- g_param_spec_string ("active",
- P_("Active"),
- P_("The ID of the active item"),
- NULL,
- GTK_PARAM_READWRITE));
+ PROP_SELECTED,
+ g_param_spec_boxed ("selected",
+ P_("Selected items"),
+ P_("The IDs of the selected items"),
+ G_TYPE_STRV,
+ GTK_PARAM_READWRITE));
/**
* GtkCombo:placeholder-text:
@@ -630,9 +648,18 @@ gtk_combo_class_init (GtkComboClass *class)
NULL,
GTK_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_SELECTION_MODE,
+ g_param_spec_enum ("selection-mode",
+ P_("Selection mode"),
+ P_("The selection mode"),
+ GTK_TYPE_SELECTION_MODE,
+ GTK_SELECTION_BROWSE,
+ GTK_PARAM_READWRITE));
+
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/ui/gtkcombo.ui");
- gtk_widget_class_bind_template_child (widget_class, GtkCombo, active_label);
+ gtk_widget_class_bind_template_child (widget_class, GtkCombo, selected_label);
gtk_widget_class_bind_template_child (widget_class, GtkCombo, popover);
gtk_widget_class_bind_template_child (widget_class, GtkCombo, scrolled_window);
gtk_widget_class_bind_template_child (widget_class, GtkCombo, list);
@@ -1114,53 +1141,13 @@ remove_from_list (GtkCombo *combo,
}
static void
-set_active (GtkCombo *combo,
- const gchar *id)
-{
- GtkWidget *item;
- GtkWidget *group;
-
- if (combo->active)
- {
- find_item (combo, combo->active, &item, &group);
- if (item)
- gtk_combo_row_set_active (GTK_COMBO_ROW (item), FALSE);
- if (group)
- gtk_combo_row_set_active (GTK_COMBO_ROW (group), FALSE);
- }
-
- if (id)
- {
- find_item (combo, id, &item, &group);
- if (item)
- gtk_combo_row_set_active (GTK_COMBO_ROW (item), TRUE);
- if (group)
- gtk_combo_row_set_active (GTK_COMBO_ROW (group), TRUE);
- }
- else
- item = NULL;
-
- if (item)
- {
- combo->active = gtk_combo_row_get_id (GTK_COMBO_ROW (item));
- gtk_label_set_text (GTK_LABEL (combo->active_label),
- gtk_combo_row_get_text (GTK_COMBO_ROW (item)));
- }
- else
- {
- combo->active = NULL;
- gtk_label_set_text (GTK_LABEL (combo->active_label), combo->placeholder);
- }
-
-
- g_object_notify (G_OBJECT (combo), "active");
-}
-
-static void
list_row_activated (GtkListBox *list,
GtkListBoxRow *row,
GtkCombo *combo)
{
+ const gchar *group;
+ const gchar *id;
+
if ((GtkWidget*)row == list_get_show_more_item (GTK_WIDGET (list)))
{
expand (combo, GTK_WIDGET (list));
@@ -1174,23 +1161,30 @@ list_row_activated (GtkListBox *list,
return;
}
- if (GTK_IS_COMBO_ROW (row))
- {
- const gchar *group;
+ if (!GTK_IS_COMBO_ROW (row))
+ return;
- group = gtk_combo_row_get_group (GTK_COMBO_ROW (row));
- if (group)
- {
- if (g_strcmp0 (group, "list") != 0)
- collapse (combo, group_get_list (combo, group));
- gtk_stack_set_visible_child_name (GTK_STACK (combo->stack), group);
- return;
- }
+ group = gtk_combo_row_get_group (GTK_COMBO_ROW (row));
+ if (group)
+ {
+ if (g_strcmp0 (group, "list") != 0)
+ collapse (combo, group_get_list (combo, group));
+ gtk_stack_set_visible_child_name (GTK_STACK (combo->stack), group);
+ return;
+ }
- set_active (combo, gtk_combo_row_get_id (GTK_COMBO_ROW (row)));
+ id = gtk_combo_row_get_id (GTK_COMBO_ROW (row));
+ if (GTK_COMBO_ROW (row)->active)
+ {
+ if (combo->selection_mode != GTK_SELECTION_BROWSE)
+ gtk_combo_unselect_item (combo, id);
+ }
+ else
+ {
+ gtk_combo_select_item (combo, id);
}
- gtk_widget_hide (combo->popover);
+ /* FIXME: hide the popover ? */
}
static void
@@ -1203,9 +1197,9 @@ custom_entry_done (GtkWidget *widget,
if (text[0] != '\0')
{
gtk_combo_add_item (combo, text, text);
- gtk_combo_set_active (combo, text);
+ gtk_combo_select_item (combo, text);
gtk_entry_set_text (GTK_ENTRY (combo->custom_entry), "");
- gtk_widget_hide (combo->popover);
+ gtk_stack_set_visible_child_name (GTK_STACK (combo->stack), "list");
}
}
@@ -1519,42 +1513,239 @@ gtk_combo_new (void)
}
/**
- * gtk_combo_get_active:
+ * gtk_combo_get_selected_item:
* @combo: a #GtkCombo
*
* Gets the ID of the currently selected item.
*
- * Returns: (transfer none): the active ID, or %NULL if no
+ * Returns: (transfer none): the ID of the selected item, or %NULL if no
* item is selected
*
* Since: 3.16
*/
const gchar *
-gtk_combo_get_active (GtkCombo *combo)
+gtk_combo_get_selected_item (GtkCombo *combo)
{
g_return_val_if_fail (GTK_IS_COMBO (combo), NULL);
- return combo->active;
+ return (const gchar *)combo->selected->pdata[0];
+}
+
+const gchar **
+gtk_combo_get_selected (GtkCombo *combo)
+{
+ g_return_val_if_fail (GTK_IS_COMBO (combo), NULL);
+
+ return (const gchar **)combo->selected->pdata;
+}
+
+typedef struct
+{
+ GtkCombo *combo;
+ gint count;
+} UpdateActiveData;
+
+static void
+update_active_cb (GtkWidget *row,
+ gpointer data)
+{
+ UpdateActiveData *d = data;
+ const gchar *group;
+ const gchar *id;
+
+ if (!GTK_IS_COMBO_ROW (row))
+ return;
+
+ group = gtk_combo_row_get_group (GTK_COMBO_ROW (row));
+ if (group &&
+ g_strcmp0 (group, "list") != 0 &&
+ g_strcmp0 (group, "custom") != 0)
+ {
+ GtkWidget *list;
+ UpdateActiveData d2;
+
+ d2.combo = d->combo;
+ d2.count = 0;
+
+ list = group_get_list (d->combo, group);
+ gtk_container_foreach (GTK_CONTAINER (list), update_active_cb, &d2);
+
+ gtk_combo_row_set_active (GTK_COMBO_ROW (row), d2.count > 0);
+ d->count += d2.count;
+ }
+
+ id = gtk_combo_row_get_id (GTK_COMBO_ROW (row));
+ if (id != NULL)
+ {
+ gint i;
+
+ for (i = 0; i < d->combo->selected->len; i++)
+ {
+ if (g_ptr_array_index (d->combo->selected, i) == id)
+ break;
+ }
+ gtk_combo_row_set_active (GTK_COMBO_ROW (row), i < d->combo->selected->len);
+ d->count += i < d->combo->selected->len ? 1 : 0;
+ }
+}
+
+static void
+update_active_rows (GtkCombo *combo)
+{
+ UpdateActiveData data;
+
+ data.combo = combo;
+ data.count = 0;
+ gtk_container_foreach (GTK_CONTAINER (combo->list), update_active_cb, &data);
+ g_assert (data.count + 1 == combo->selected->len);
+}
+
+static void
+update_selected_label (GtkCombo *combo)
+{
+ if (combo->selected->len == 0)
+ {
+ gtk_label_set_text (GTK_LABEL (combo->selected_label), combo->placeholder);
+ }
+ else
+ {
+ GString *str;
+ const gchar *id;
+ const gchar *text;
+ gint i;
+
+ str = g_string_new ("");
+ for (i = 0; i < combo->selected->len; i++)
+ {
+ id = (const gchar *)g_ptr_array_index (combo->selected, i);
+ if (id == NULL)
+ continue;
+
+ if (i > 0)
+ g_string_append (str, ", ");
+
+ text = gtk_combo_item_get_text (combo, id);
+ g_string_append (str, text);
+ }
+ gtk_label_set_text (GTK_LABEL (combo->selected_label), str->str);
+ g_string_free (str, TRUE);
+ }
+}
+
+static void
+set_selected (GtkCombo *combo,
+ const gchar **ids)
+{
+ gint i;
+ GtkWidget *item;
+ const gchar *id;
+
+ g_ptr_array_set_size (combo->selected, 0);
+ for (i = 0; ids[i]; i++)
+ {
+ find_item (combo, ids[i], &item, NULL);
+ if (item == NULL)
+ {
+ g_warning ("GtkCombo: no item with ID '%s' found", ids[i]);
+ continue;
+ }
+
+ id = gtk_combo_row_get_id (GTK_COMBO_ROW (item));
+
+ if (i > 0 && combo->selection_mode != GTK_SELECTION_MULTIPLE)
+ {
+ g_warning ("GtkCombo: ignoring extra item '%s' in single selection mode", id);
+ continue;
+ }
+
+ g_ptr_array_add (combo->selected, (gpointer)id);
+ }
+ g_ptr_array_add (combo->selected, NULL);
+
+ update_active_rows (combo);
+ update_selected_label (combo);
+ g_object_notify (G_OBJECT (combo), "selected");
}
/**
- * gtk_combo_set_active:
+ * gtk_combo_select_item:
* @combo: a #GtkCombo
- * @id: (allow-none): the ID to select, or %NULL
+ * @id: the ID to select
*
- * Sets the active ID to @id. If @id is not the ID
- * of an item of combo, no item will be selected
+ * Selects the item with the given ID. If the combo does
+ * not contain an item with this id, no item will be selected
* after this call.
*
* Since: 3.16
*/
void
-gtk_combo_set_active (GtkCombo *combo,
- const gchar *id)
+gtk_combo_select_item (GtkCombo *combo,
+ const gchar *id)
+{
+ GtkWidget *item;
+ gint i;
+
+ g_return_if_fail (GTK_IS_COMBO (combo));
+ g_return_if_fail (id != NULL);
+
+ find_item (combo, id, &item, NULL);
+ if (item == NULL)
+ {
+ g_warning ("GtkCombo: no item with ID '%s' found", id);
+ return;
+ }
+
+ id = gtk_combo_row_get_id (GTK_COMBO_ROW (item));
+
+ for (i = 0; i < combo->selected->len; i++)
+ {
+ if (g_ptr_array_index (combo->selected, i) == id)
+ return;
+ }
+
+ if (combo->selection_mode != GTK_SELECTION_MULTIPLE)
+ g_ptr_array_set_size (combo->selected, 1);
+
+ g_ptr_array_index (combo->selected, combo->selected->len - 1) = (gpointer)id;
+ g_ptr_array_add (combo->selected, NULL);
+
+ update_active_rows (combo);
+ update_selected_label (combo);
+ g_object_notify (G_OBJECT (combo), "selected");
+}
+
+void
+gtk_combo_unselect_item (GtkCombo *combo,
+ const gchar *id)
{
+ GtkWidget *item;
+ gint i;
+
g_return_if_fail (GTK_IS_COMBO (combo));
+ g_return_if_fail (id != NULL);
- set_active (combo, id);
+ find_item (combo, id, &item, NULL);
+ if (item == NULL)
+ {
+ g_warning ("GtkCombo: no item with ID '%s' found", id);
+ return;
+ }
+
+ id = gtk_combo_row_get_id (GTK_COMBO_ROW (item));
+
+ for (i = 0; i < combo->selected->len; i++)
+ {
+ if (g_ptr_array_index (combo->selected, i) == id)
+ break;
+ }
+ if (i == combo->selected->len)
+ return;
+
+ g_ptr_array_remove_index (combo->selected, i);
+
+ update_active_rows (combo);
+ update_selected_label (combo);
+ g_object_notify (G_OBJECT (combo), "selected");
}
/**
@@ -1605,6 +1796,7 @@ gtk_combo_item_get_text (GtkCombo *combo,
GtkWidget *item;
g_return_val_if_fail (GTK_IS_COMBO (combo), NULL);
+ g_return_val_if_fail (id != NULL, NULL);
if (!find_item (combo, id, &item, NULL))
return NULL;
@@ -1707,9 +1899,7 @@ gtk_combo_remove_item (GtkCombo *combo,
g_return_if_fail (GTK_IS_COMBO (combo));
g_return_if_fail (id != NULL);
- if (g_strcmp0 (id, combo->active) == 0)
- set_active (combo, NULL);
-
+ gtk_combo_unselect_item (combo, id);
remove_from_list (combo, id);
}
@@ -1733,8 +1923,8 @@ gtk_combo_set_placeholder_text (GtkCombo *combo,
g_free (combo->placeholder);
combo->placeholder = g_strdup (text);
- if (combo->active_label != NULL && combo->active == NULL)
- gtk_label_set_text (GTK_LABEL (combo->active_label), combo->placeholder);
+ if (combo->selected_label != NULL && combo->selected == NULL)
+ gtk_label_set_text (GTK_LABEL (combo->selected_label), combo->placeholder);
g_object_notify (G_OBJECT (combo), "placeholder-text");
}
@@ -1878,3 +2068,25 @@ gtk_combo_add_group (GtkCombo *combo,
gtk_list_box_invalidate_sort (GTK_LIST_BOX (combo->list));
}
+void
+gtk_combo_set_selection_mode (GtkCombo *combo,
+ GtkSelectionMode mode)
+{
+ g_return_if_fail (GTK_IS_COMBO (combo));
+ g_return_if_fail (mode != GTK_SELECTION_NONE);
+
+ if (combo->selection_mode == mode)
+ return;
+
+ combo->selection_mode = mode;
+
+ g_object_notify (G_OBJECT (combo), "selection-mode");
+}
+
+GtkSelectionMode
+gtk_combo_get_selection_mode (GtkCombo *combo)
+{
+ g_return_val_if_fail (GTK_IS_COMBO (combo), GTK_SELECTION_BROWSE);
+
+ return combo->selection_mode;
+}
diff --git a/gtk/gtkcombo.h b/gtk/gtkcombo.h
index 2e85dfb..bf079f4 100644
--- a/gtk/gtkcombo.h
+++ b/gtk/gtkcombo.h
@@ -44,10 +44,16 @@ GDK_AVAILABLE_IN_3_16
GtkWidget * gtk_combo_new (void);
GDK_AVAILABLE_IN_3_16
-const gchar * gtk_combo_get_active (GtkCombo *combo);
+const gchar * gtk_combo_get_selected_item (GtkCombo *combo);
GDK_AVAILABLE_IN_3_16
-void gtk_combo_set_active (GtkCombo *combo,
+const gchar **gtk_combo_get_selected (GtkCombo *combo);
+
+GDK_AVAILABLE_IN_3_16
+void gtk_combo_select_item (GtkCombo *combo,
+ const gchar *id);
+GDK_AVAILABLE_IN_3_16
+void gtk_combo_unselect_item (GtkCombo *combo,
const gchar *id);
GDK_AVAILABLE_IN_3_16
@@ -72,6 +78,12 @@ void gtk_combo_item_set_group_key (GtkCombo *combo,
const gchar *group);
GDK_AVAILABLE_IN_3_16
+void gtk_combo_add_group (GtkCombo *combo,
+ const gchar *group,
+ const gchar *text,
+ const gchar *sort);
+
+GDK_AVAILABLE_IN_3_16
void gtk_combo_set_placeholder_text (GtkCombo *combo,
const gchar *text);
GDK_AVAILABLE_IN_3_16
@@ -90,10 +102,11 @@ GDK_AVAILABLE_IN_3_16
const gchar * gtk_combo_get_custom_text (GtkCombo *combo);
GDK_AVAILABLE_IN_3_16
-void gtk_combo_add_group (GtkCombo *combo,
- const gchar *group,
- const gchar *text,
- const gchar *sort);
+void gtk_combo_set_selection_mode (GtkCombo *combo,
+ GtkSelectionMode mode);
+GDK_AVAILABLE_IN_3_16
+GtkSelectionMode gtk_combo_get_selection_mode (GtkCombo *combo);
+
G_END_DECLS
diff --git a/gtk/ui/gtkcombo.ui b/gtk/ui/gtkcombo.ui
index b13485e..0d976d4 100644
--- a/gtk/ui/gtkcombo.ui
+++ b/gtk/ui/gtkcombo.ui
@@ -13,8 +13,9 @@
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
<child type="center">
- <object class="GtkLabel" id="active_label">
+ <object class="GtkLabel" id="selected_label">
<property name="visible">True</property>
+ <property name="ellipsize">end</property>
</object>
</child>
<child>
diff --git a/gtk/ui/gtkcombotab.ui.h b/gtk/ui/gtkcombotab.ui.h
new file mode 100644
index 0000000..e69de29
diff --git a/tests/testnewcombo.c b/tests/testnewcombo.c
index f36f36c..38d7471 100644
--- a/tests/testnewcombo.c
+++ b/tests/testnewcombo.c
@@ -15,18 +15,18 @@ add_one (GtkButton *button, gpointer data)
sort = g_strdup_printf ("Value %03d", count);
gtk_combo_add_item (GTK_COMBO (data), id, text);
gtk_combo_item_set_sort_key (GTK_COMBO (data), id, sort);
- gtk_combo_set_active (GTK_COMBO (data), id);
+ gtk_combo_select_item (GTK_COMBO (data), id);
g_free (id);
g_free (text);
g_free (sort);
}
static void
-remove_active (GtkButton *button, gpointer data)
+remove_selected (GtkButton *button, gpointer data)
{
const gchar *id;
- id = gtk_combo_get_active (GTK_COMBO (data));
+ id = gtk_combo_get_selected_item (GTK_COMBO (data));
if (id != NULL)
gtk_combo_remove_item (GTK_COMBO (data), id);
}
@@ -34,7 +34,13 @@ remove_active (GtkButton *button, gpointer data)
static void
select_a (GtkButton *button, gpointer data)
{
- gtk_combo_set_active (GTK_COMBO (data), "1");
+ gtk_combo_select_item (GTK_COMBO (data), "1");
+}
+
+static void
+unselect_a (GtkButton *button, gpointer data)
+{
+ gtk_combo_unselect_item (GTK_COMBO (data), "1");
}
const gchar data[] =
@@ -44,7 +50,7 @@ const gchar data[] =
" <property name='halign'>center</property>"
" <property name='placeholder-text'>None</property>"
" <property name='custom-text'>Other</property>"
- " <property name='active'>1</property>"
+ " <property name='selection-mode'>multiple</property>"
" <items>"
" <item translatable='yes' id='1' sort='Value 001'>Value 1</item>"
" <item translatable='yes' id='2' sort='Value 002'>Value 2</item>"
@@ -55,16 +61,20 @@ const gchar data[] =
" <groups>"
" <group id='1' translatable='yes'>Group 1</group>"
" </groups>"
+ " <property name='selected'>1</property>"
" </object>"
"</interface>";
static gboolean
-string_to_bool (GBinding *binding,
- const GValue *from_value,
- GValue *to_value,
- gpointer data)
+selected_to_bool (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer data)
{
- g_value_set_boolean (to_value, g_value_get_string (from_value) != NULL);
+ const gchar * const *ids;
+
+ ids = g_value_get_boxed (from_value);
+ g_value_set_boolean (to_value, ids[0] != NULL);
return TRUE;
}
@@ -74,17 +84,40 @@ selected_to_string (GBinding *binding,
GValue *to_value,
gpointer data)
{
- const gchar *id;
- const gchar *text;
+ gchar **ids;
+ gchar *text;
- id = g_value_get_string (from_value);
+ ids = g_value_get_boxed (from_value);
+ text = g_strjoinv (", ", ids);
+ g_value_set_string (to_value, text);
+ g_free (text);
- if (id != NULL)
- text = gtk_combo_item_get_text (GTK_COMBO (g_binding_get_source (binding)), id);
- else
- text = "";
+ return TRUE;
+}
- g_value_set_string (to_value, text);
+static gboolean
+selected_to_text (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer data)
+{
+ const gchar * const *ids;
+ GString *str;
+ gint i;
+
+ str = g_string_new ("");
+ ids = g_value_get_boxed (from_value);
+ for (i = 0; ids[i]; i++)
+ {
+ const gchar *text;
+ if (i > 0)
+ g_string_append (str, ", ");
+ text = gtk_combo_item_get_text (GTK_COMBO (g_binding_get_source (binding)), ids[i]);
+ g_string_append (str, text);
+ }
+
+ g_value_set_string (to_value, str->str);
+ g_string_free (str, TRUE);
return TRUE;
}
@@ -116,7 +149,7 @@ main (int argc, char *argv[])
gtk_combo_add_item (GTK_COMBO (combo), "2", "Value 2");
gtk_combo_add_item (GTK_COMBO (combo), "3", "Value 3");
gtk_combo_set_placeholder_text (GTK_COMBO (combo), "None");
- gtk_combo_set_active (GTK_COMBO (combo), "1");
+ gtk_combo_select_item (GTK_COMBO (combo), "1");
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
@@ -150,7 +183,7 @@ main (int argc, char *argv[])
gtk_combo_item_set_sort_key (GTK_COMBO (combo), "10", "Value 10");
gtk_combo_item_set_sort_key (GTK_COMBO (combo), "11", "Value 11");
gtk_combo_set_placeholder_text (GTK_COMBO (combo), "None");
- gtk_combo_set_active (GTK_COMBO (combo), "1");
+ gtk_combo_select_item (GTK_COMBO (combo), "1");
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
@@ -166,7 +199,7 @@ main (int argc, char *argv[])
gtk_combo_add_item (GTK_COMBO (combo), "3", "Value 3");
gtk_combo_set_placeholder_text (GTK_COMBO (combo), "None");
gtk_combo_set_allow_custom (GTK_COMBO (combo), TRUE);
- gtk_combo_set_active (GTK_COMBO (combo), "1");
+ gtk_combo_select_item (GTK_COMBO (combo), "1");
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
@@ -228,15 +261,15 @@ main (int argc, char *argv[])
gtk_combo_item_set_group_key (GTK_COMBO (combo), "16", "Group 3");
gtk_combo_item_set_group_key (GTK_COMBO (combo), "17", "Group 3");
gtk_combo_item_set_group_key (GTK_COMBO (combo), "18", "Group 3");
- gtk_combo_set_active (GTK_COMBO (combo), "7");
- button = gtk_button_new_with_label ("Remove active");
+ gtk_combo_select_item (GTK_COMBO (combo), "7");
+ button = gtk_button_new_with_label ("Remove selected");
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
- g_signal_connect (button, "clicked", G_CALLBACK (remove_active), combo);
+ g_signal_connect (button, "clicked", G_CALLBACK (remove_selected), combo);
gtk_container_add (GTK_CONTAINER (box), button);
- g_object_bind_property_full (combo, "active",
+ g_object_bind_property_full (combo, "selected",
button, "sensitive",
G_BINDING_SYNC_CREATE,
- string_to_bool, NULL, NULL, NULL);
+ selected_to_bool, NULL, NULL, NULL);
gtk_container_add (GTK_CONTAINER (box), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
@@ -259,13 +292,16 @@ main (int argc, char *argv[])
button = gtk_button_new_with_label ("Select 1");
g_signal_connect (button, "clicked", G_CALLBACK (select_a), combo);
gtk_container_add (GTK_CONTAINER (box2), button);
- button = gtk_button_new_with_label ("Remove active");
- g_signal_connect (button, "clicked", G_CALLBACK (remove_active), combo);
+ button = gtk_button_new_with_label ("Unselect 1");
+ g_signal_connect (button, "clicked", G_CALLBACK (unselect_a), combo);
+ gtk_container_add (GTK_CONTAINER (box2), button);
+ button = gtk_button_new_with_label ("Remove selected");
+ g_signal_connect (button, "clicked", G_CALLBACK (remove_selected), combo);
gtk_container_add (GTK_CONTAINER (box2), button);
- g_object_bind_property_full (combo, "active",
+ g_object_bind_property_full (combo, "selected",
button, "sensitive",
G_BINDING_SYNC_CREATE,
- string_to_bool, NULL, NULL, NULL);
+ selected_to_bool, NULL, NULL, NULL);
button = gtk_check_button_new_with_label ("Allow custom");
gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
g_object_bind_property (button, "active",
@@ -279,9 +315,11 @@ main (int argc, char *argv[])
label = gtk_label_new ("Active:");
gtk_container_add (GTK_CONTAINER (box2), label);
label = gtk_label_new ("");
- g_object_bind_property (combo, "active",
- label, "label",
- G_BINDING_SYNC_CREATE);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ g_object_bind_property_full (combo, "selected",
+ label, "label",
+ G_BINDING_SYNC_CREATE,
+ selected_to_string, NULL, NULL, NULL);
gtk_container_add (GTK_CONTAINER (box2), label);
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
gtk_widget_set_halign (box2, GTK_ALIGN_CENTER);
@@ -289,10 +327,11 @@ main (int argc, char *argv[])
label = gtk_label_new ("Label:");
gtk_container_add (GTK_CONTAINER (box2), label);
label = gtk_label_new ("");
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
g_object_bind_property_full (combo, "selected",
label, "label",
G_BINDING_SYNC_CREATE,
- selected_to_string, NULL, NULL, NULL);
+ selected_to_text, NULL, NULL, NULL);
gtk_container_add (GTK_CONTAINER (box2), label);
gtk_widget_show_all (window);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]