]> Pileus Git - ~andy/gtk/blob - demos/gtk-demo/editable_cells.c
Use GtkCellRendererCombo (#169607, Mark McLoughlin)
[~andy/gtk] / demos / gtk-demo / editable_cells.c
1 /* Tree View/Editable Cells
2  *
3  * This demo demonstrates the use of editable cells in a GtkTreeView. If
4  * you're new to the GtkTreeView widgets and associates, look into
5  * the GtkListStore example first.
6  *
7  * The cell renderers used in this demo are GtkCellRendererText and 
8  * GtkCellRendererCombo.
9  */
10
11 #include <gtk/gtk.h>
12 #include <string.h>
13 #include <stdlib.h>
14
15 static GtkWidget *window = NULL;
16
17 typedef struct
18 {
19   gint   number;
20   gchar *product;
21 }
22 Item;
23
24 enum
25 {
26   COLUMN_ITEM_NUMBER,
27   COLUMN_ITEM_PRODUCT,
28   NUM_ITEM_COLUMNS
29 };
30
31 enum
32 {
33   COLUMN_NUMBER_TEXT,
34   NUM_NUMBER_COLUMNS
35 };
36
37 static GArray *articles = NULL;
38
39 static void
40 add_items (void)
41 {
42   Item foo;
43
44   g_return_if_fail (articles != NULL);
45
46   foo.number = 3;
47   foo.product = g_strdup ("bottles of coke");
48   g_array_append_vals (articles, &foo, 1);
49
50   foo.number = 5;
51   foo.product = g_strdup ("packages of noodles");
52   g_array_append_vals (articles, &foo, 1);
53
54   foo.number = 2;
55   foo.product = g_strdup ("packages of chocolate chip cookies");
56   g_array_append_vals (articles, &foo, 1);
57
58   foo.number = 1;
59   foo.product = g_strdup ("can vanilla ice cream");
60   g_array_append_vals (articles, &foo, 1);
61
62   foo.number = 6;
63   foo.product = g_strdup ("eggs");
64   g_array_append_vals (articles, &foo, 1);
65 }
66
67 static GtkTreeModel *
68 create_items_model (void)
69 {
70   gint i = 0;
71   GtkListStore *model;
72   GtkTreeIter iter;
73
74   /* create array */
75   articles = g_array_sized_new (FALSE, FALSE, sizeof (Item), 1);
76
77   add_items ();
78
79   /* create list store */
80   model = gtk_list_store_new (NUM_ITEM_COLUMNS, G_TYPE_INT, G_TYPE_STRING,
81                               G_TYPE_BOOLEAN);
82
83   /* add items */
84   for (i = 0; i < articles->len; i++)
85     {
86       gtk_list_store_append (model, &iter);
87
88       gtk_list_store_set (model, &iter,
89                           COLUMN_ITEM_NUMBER,
90                           g_array_index (articles, Item, i).number,
91                           COLUMN_ITEM_PRODUCT,
92                           g_array_index (articles, Item, i).product,
93                           -1);
94     }
95
96   return GTK_TREE_MODEL (model);
97 }
98
99 static GtkTreeModel *
100 create_numbers_model (void)
101 {
102 #define N_NUMBERS 10
103
104   gint i = 0;
105   GtkListStore *model;
106   GtkTreeIter iter;
107
108   /* create list store */
109   model = gtk_list_store_new (NUM_NUMBER_COLUMNS, G_TYPE_STRING, G_TYPE_INT);
110
111   /* add numbers */
112   for (i = 0; i < N_NUMBERS; i++)
113     {
114       char str[2] = { '0' + i, '\0' };
115
116       gtk_list_store_append (model, &iter);
117
118       gtk_list_store_set (model, &iter,
119                           COLUMN_NUMBER_TEXT, str,
120                           -1);
121     }
122
123   return GTK_TREE_MODEL (model);
124
125 #undef N_NUMBERS
126 }
127
128 static void
129 add_item (GtkWidget *button, gpointer data)
130 {
131   Item foo;
132   GtkTreeIter iter;
133   GtkTreeModel *model = (GtkTreeModel *)data;
134
135   g_return_if_fail (articles != NULL);
136
137   foo.number = 0;
138   foo.product = g_strdup ("Description here");
139   g_array_append_vals (articles, &foo, 1);
140
141   gtk_list_store_append (GTK_LIST_STORE (model), &iter);
142   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
143                       COLUMN_ITEM_NUMBER, foo.number,
144                       COLUMN_ITEM_PRODUCT, foo.product,
145                       -1);
146 }
147
148 static void
149 remove_item (GtkWidget *widget, gpointer data)
150 {
151   GtkTreeIter iter;
152   GtkTreeView *treeview = (GtkTreeView *)data;
153   GtkTreeModel *model = gtk_tree_view_get_model (treeview);
154   GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
155
156   if (gtk_tree_selection_get_selected (selection, NULL, &iter))
157     {
158       gint i;
159       GtkTreePath *path;
160
161       path = gtk_tree_model_get_path (model, &iter);
162       i = gtk_tree_path_get_indices (path)[0];
163       gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
164
165       g_array_remove_index (articles, i);
166
167       gtk_tree_path_free (path);
168     }
169 }
170
171 static void
172 cell_edited (GtkCellRendererText *cell,
173              const gchar         *path_string,
174              const gchar         *new_text,
175              gpointer             data)
176 {
177   GtkTreeModel *model = (GtkTreeModel *)data;
178   GtkTreePath *path = gtk_tree_path_new_from_string (path_string);
179   GtkTreeIter iter;
180
181   gint column = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cell), "column"));
182
183   gtk_tree_model_get_iter (model, &iter, path);
184
185   switch (column)
186     {
187     case COLUMN_ITEM_NUMBER:
188       {
189         gint i;
190
191         i = gtk_tree_path_get_indices (path)[0];
192         g_array_index (articles, Item, i).number = atoi (new_text);
193
194         gtk_list_store_set (GTK_LIST_STORE (model), &iter, column,
195                             g_array_index (articles, Item, i).number, -1);
196       }
197       break;
198
199     case COLUMN_ITEM_PRODUCT:
200       {
201         gint i;
202         gchar *old_text;
203
204         gtk_tree_model_get (model, &iter, column, &old_text, -1);
205         g_free (old_text);
206
207         i = gtk_tree_path_get_indices (path)[0];
208         g_free (g_array_index (articles, Item, i).product);
209         g_array_index (articles, Item, i).product = g_strdup (new_text);
210
211         gtk_list_store_set (GTK_LIST_STORE (model), &iter, column,
212                             g_array_index (articles, Item, i).product, -1);
213       }
214       break;
215     }
216
217   gtk_tree_path_free (path);
218 }
219
220 static void
221 add_columns (GtkTreeView  *treeview, 
222              GtkTreeModel *items_model,
223              GtkTreeModel *numbers_model)
224 {
225   GtkCellRenderer *renderer;
226
227   /* number column */
228   renderer = gtk_cell_renderer_combo_new ();
229   g_object_set (renderer,
230                 "model", numbers_model,
231                 "text-column", COLUMN_NUMBER_TEXT,
232                 "has-entry", FALSE,
233                 "editable", TRUE,
234                 NULL);
235   g_signal_connect (renderer, "edited",
236                     G_CALLBACK (cell_edited), items_model);
237   g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_ITEM_NUMBER));
238
239   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
240                                                -1, "Number", renderer,
241                                                "text", COLUMN_ITEM_NUMBER,
242                                                NULL);
243
244   /* product column */
245   renderer = gtk_cell_renderer_text_new ();
246   g_object_set (renderer,
247                 "editable", TRUE,
248                 NULL);
249   g_signal_connect (renderer, "edited",
250                     G_CALLBACK (cell_edited), items_model);
251   g_object_set_data (G_OBJECT (renderer), "column", GINT_TO_POINTER (COLUMN_ITEM_PRODUCT));
252
253   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (treeview),
254                                                -1, "Product", renderer,
255                                                "text", COLUMN_ITEM_PRODUCT,
256                                                NULL);
257 }
258
259 GtkWidget *
260 do_editable_cells (GtkWidget *do_widget)
261 {
262   if (!window)
263     {
264       GtkWidget *vbox;
265       GtkWidget *hbox;
266       GtkWidget *sw;
267       GtkWidget *treeview;
268       GtkWidget *button;
269       GtkTreeModel *items_model;
270       GtkTreeModel *numbers_model;
271
272       /* create window, etc */
273       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
274       gtk_window_set_screen (GTK_WINDOW (window),
275                              gtk_widget_get_screen (do_widget));
276       gtk_window_set_title (GTK_WINDOW (window), "Shopping list");
277       gtk_container_set_border_width (GTK_CONTAINER (window), 5);
278       g_signal_connect (window, "destroy",
279                         G_CALLBACK (gtk_widget_destroyed), &window);
280
281       vbox = gtk_vbox_new (FALSE, 5);
282       gtk_container_add (GTK_CONTAINER (window), vbox);
283
284       gtk_box_pack_start (GTK_BOX (vbox),
285                           gtk_label_new ("Shopping list (you can edit the cells!)"),
286                           FALSE, FALSE, 0);
287
288       sw = gtk_scrolled_window_new (NULL, NULL);
289       gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
290                                            GTK_SHADOW_ETCHED_IN);
291       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
292                                       GTK_POLICY_AUTOMATIC,
293                                       GTK_POLICY_AUTOMATIC);
294       gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
295
296       /* create models */
297       items_model = create_items_model ();
298       numbers_model = create_numbers_model ();
299
300       /* create tree view */
301       treeview = gtk_tree_view_new_with_model (items_model);
302       gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (treeview), TRUE);
303       gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
304                                    GTK_SELECTION_SINGLE);
305
306       add_columns (GTK_TREE_VIEW (treeview), items_model, numbers_model);
307
308       g_object_unref (numbers_model);
309       g_object_unref (items_model);
310
311       gtk_container_add (GTK_CONTAINER (sw), treeview);
312
313       /* some buttons */
314       hbox = gtk_hbox_new (TRUE, 4);
315       gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
316
317       button = gtk_button_new_with_label ("Add item");
318       g_signal_connect (button, "clicked",
319                         G_CALLBACK (add_item), items_model);
320       gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
321
322       button = gtk_button_new_with_label ("Remove item");
323       g_signal_connect (button, "clicked",
324                         G_CALLBACK (remove_item), treeview);
325       gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
326
327       gtk_window_set_default_size (GTK_WINDOW (window), 320, 200);
328     }
329
330   if (!GTK_WIDGET_VISIBLE (window))
331     gtk_widget_show_all (window);
332   else
333     {
334       gtk_widget_destroy (window);
335       window = NULL;
336     }
337
338   return window;
339 }