1 | /* testtreeedit.c |
2 | * Copyright (C) 2001 Red Hat, Inc |
3 | * Author: Jonathan Blandford |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Library General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public |
16 | * License along with this library. If not, see <http://www.gnu.org/licenses/>. |
17 | */ |
18 | |
19 | #include "config.h" |
20 | #include <gtk/gtk.h> |
21 | |
22 | typedef struct { |
23 | const char *string; |
24 | gboolean is_editable; |
25 | gboolean is_sensitive; |
26 | int progress; |
27 | } ListEntry; |
28 | |
29 | enum { |
30 | STRING_COLUMN, |
31 | IS_EDITABLE_COLUMN, |
32 | IS_SENSITIVE_COLUMN, |
33 | ICON_NAME_COLUMN, |
34 | LAST_ICON_NAME_COLUMN, |
35 | PROGRESS_COLUMN, |
36 | NUM_COLUMNS |
37 | }; |
38 | |
39 | static ListEntry model_strings[] = |
40 | { |
41 | {"A simple string" , TRUE, TRUE, 0 }, |
42 | {"Another string!" , TRUE, TRUE, 10 }, |
43 | {"" , TRUE, TRUE, 0 }, |
44 | {"Guess what, a third string. This one can't be edited" , FALSE, TRUE, 47 }, |
45 | {"And then a fourth string. Neither can this" , FALSE, TRUE, 48 }, |
46 | {"Multiline\nFun!" , TRUE, FALSE, 75 }, |
47 | { NULL } |
48 | }; |
49 | |
50 | static GtkTreeModel * |
51 | create_model (void) |
52 | { |
53 | GtkTreeStore *model; |
54 | GtkTreeIter iter; |
55 | int i; |
56 | |
57 | model = gtk_tree_store_new (n_columns: NUM_COLUMNS, |
58 | G_TYPE_STRING, |
59 | G_TYPE_BOOLEAN, |
60 | G_TYPE_BOOLEAN, |
61 | G_TYPE_STRING, |
62 | G_TYPE_STRING, |
63 | G_TYPE_INT); |
64 | |
65 | for (i = 0; model_strings[i].string != NULL; i++) |
66 | { |
67 | gtk_tree_store_append (tree_store: model, iter: &iter, NULL); |
68 | |
69 | gtk_tree_store_set (tree_store: model, iter: &iter, |
70 | STRING_COLUMN, model_strings[i].string, |
71 | IS_EDITABLE_COLUMN, model_strings[i].is_editable, |
72 | IS_SENSITIVE_COLUMN, model_strings[i].is_sensitive, |
73 | ICON_NAME_COLUMN, "document-new" , |
74 | LAST_ICON_NAME_COLUMN, "edit-delete" , |
75 | PROGRESS_COLUMN, model_strings[i].progress, |
76 | -1); |
77 | } |
78 | |
79 | return GTK_TREE_MODEL (model); |
80 | } |
81 | |
82 | static void |
83 | editable_toggled (GtkCellRendererToggle *cell, |
84 | char *path_string, |
85 | gpointer data) |
86 | { |
87 | GtkTreeModel *model = GTK_TREE_MODEL (data); |
88 | GtkTreeIter iter; |
89 | GtkTreePath *path = gtk_tree_path_new_from_string (path: path_string); |
90 | gboolean value; |
91 | |
92 | gtk_tree_model_get_iter (tree_model: model, iter: &iter, path); |
93 | gtk_tree_model_get (tree_model: model, iter: &iter, IS_EDITABLE_COLUMN, &value, -1); |
94 | |
95 | value = !value; |
96 | gtk_tree_store_set (GTK_TREE_STORE (model), iter: &iter, IS_EDITABLE_COLUMN, value, -1); |
97 | |
98 | gtk_tree_path_free (path); |
99 | } |
100 | |
101 | static void |
102 | sensitive_toggled (GtkCellRendererToggle *cell, |
103 | char *path_string, |
104 | gpointer data) |
105 | { |
106 | GtkTreeModel *model = GTK_TREE_MODEL (data); |
107 | GtkTreeIter iter; |
108 | GtkTreePath *path = gtk_tree_path_new_from_string (path: path_string); |
109 | gboolean value; |
110 | |
111 | gtk_tree_model_get_iter (tree_model: model, iter: &iter, path); |
112 | gtk_tree_model_get (tree_model: model, iter: &iter, IS_SENSITIVE_COLUMN, &value, -1); |
113 | |
114 | value = !value; |
115 | gtk_tree_store_set (GTK_TREE_STORE (model), iter: &iter, IS_SENSITIVE_COLUMN, value, -1); |
116 | |
117 | gtk_tree_path_free (path); |
118 | } |
119 | |
120 | static void |
121 | edited (GtkCellRendererText *cell, |
122 | char *path_string, |
123 | char *new_text, |
124 | gpointer data) |
125 | { |
126 | GtkTreeModel *model = GTK_TREE_MODEL (data); |
127 | GtkTreeIter iter; |
128 | GtkTreePath *path = gtk_tree_path_new_from_string (path: path_string); |
129 | |
130 | gtk_tree_model_get_iter (tree_model: model, iter: &iter, path); |
131 | gtk_tree_store_set (GTK_TREE_STORE (model), iter: &iter, STRING_COLUMN, new_text, -1); |
132 | |
133 | gtk_tree_path_free (path); |
134 | } |
135 | |
136 | static void |
137 | pressed_cb (GtkGesture *gesture, |
138 | int n_press, |
139 | double x, |
140 | double y, |
141 | GtkWidget *widget) |
142 | { |
143 | /* Deselect if people click outside any row. */ |
144 | if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), x, y, NULL, NULL, NULL, NULL)) |
145 | gtk_tree_selection_unselect_all (selection: gtk_tree_view_get_selection (GTK_TREE_VIEW (widget))); |
146 | } |
147 | |
148 | typedef struct { |
149 | GtkCellArea *area; |
150 | GtkCellRenderer *renderer; |
151 | } CallbackData; |
152 | |
153 | static void |
154 | align_cell_toggled (GtkToggleButton *toggle, |
155 | CallbackData *data) |
156 | { |
157 | gboolean active = gtk_toggle_button_get_active (toggle_button: toggle); |
158 | |
159 | gtk_cell_area_cell_set (area: data->area, renderer: data->renderer, first_prop_name: "align" , active, NULL); |
160 | } |
161 | |
162 | static void |
163 | expand_cell_toggled (GtkToggleButton *toggle, |
164 | CallbackData *data) |
165 | { |
166 | gboolean active = gtk_toggle_button_get_active (toggle_button: toggle); |
167 | |
168 | gtk_cell_area_cell_set (area: data->area, renderer: data->renderer, first_prop_name: "expand" , active, NULL); |
169 | } |
170 | |
171 | static void |
172 | fixed_cell_toggled (GtkToggleButton *toggle, |
173 | CallbackData *data) |
174 | { |
175 | gboolean active = gtk_toggle_button_get_active (toggle_button: toggle); |
176 | |
177 | gtk_cell_area_cell_set (area: data->area, renderer: data->renderer, first_prop_name: "fixed-size" , active, NULL); |
178 | } |
179 | |
180 | enum { |
181 | CNTL_EXPAND, |
182 | CNTL_ALIGN, |
183 | CNTL_FIXED |
184 | }; |
185 | |
186 | static void |
187 | create_control (GtkWidget *box, int number, int cntl, CallbackData *data) |
188 | { |
189 | GtkWidget *checkbutton; |
190 | GCallback callback = NULL; |
191 | char *name = NULL; |
192 | |
193 | switch (cntl) |
194 | { |
195 | case CNTL_EXPAND: |
196 | name = g_strdup_printf (format: "Expand Cell #%d" , number); |
197 | callback = G_CALLBACK (expand_cell_toggled); |
198 | break; |
199 | case CNTL_ALIGN: |
200 | name = g_strdup_printf (format: "Align Cell #%d" , number); |
201 | callback = G_CALLBACK (align_cell_toggled); |
202 | break; |
203 | case CNTL_FIXED: |
204 | name = g_strdup_printf (format: "Fix size Cell #%d" , number); |
205 | callback = G_CALLBACK (fixed_cell_toggled); |
206 | break; |
207 | default: |
208 | g_assert_not_reached (); |
209 | } |
210 | |
211 | checkbutton = gtk_check_button_new_with_label (label: name); |
212 | gtk_check_button_set_active (GTK_CHECK_BUTTON (checkbutton), setting: cntl == CNTL_FIXED); |
213 | gtk_box_append (GTK_BOX (box), child: checkbutton); |
214 | |
215 | g_signal_connect (G_OBJECT (checkbutton), "toggled" , callback, data); |
216 | g_free (mem: name); |
217 | } |
218 | |
219 | static void |
220 | quit_cb (GtkWidget *widget, |
221 | gpointer data) |
222 | { |
223 | gboolean *done = data; |
224 | |
225 | *done = TRUE; |
226 | |
227 | g_main_context_wakeup (NULL); |
228 | } |
229 | |
230 | int |
231 | main (int argc, char **argv) |
232 | { |
233 | GtkWidget *window; |
234 | GtkWidget *scrolled_window; |
235 | GtkWidget *tree_view; |
236 | GtkWidget *vbox, *hbox, *cntl_vbox; |
237 | GtkTreeModel *tree_model; |
238 | GtkCellRenderer *renderer; |
239 | GtkTreeViewColumn *column; |
240 | GtkCellArea *area; |
241 | CallbackData callback[4]; |
242 | GtkGesture *gesture; |
243 | gboolean done = FALSE; |
244 | |
245 | gtk_init (); |
246 | |
247 | if (g_getenv (variable: "RTL" )) |
248 | gtk_widget_set_default_direction (dir: GTK_TEXT_DIR_RTL); |
249 | |
250 | window = gtk_window_new (); |
251 | gtk_window_set_title (GTK_WINDOW (window), title: "GtkTreeView editing sample" ); |
252 | g_signal_connect (window, "destroy" , G_CALLBACK (quit_cb), &done); |
253 | |
254 | vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 6); |
255 | gtk_window_set_child (GTK_WINDOW (window), child: vbox); |
256 | |
257 | scrolled_window = gtk_scrolled_window_new (); |
258 | gtk_scrolled_window_set_has_frame (GTK_SCROLLED_WINDOW (scrolled_window), TRUE); |
259 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), |
260 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
261 | gtk_widget_set_vexpand (widget: scrolled_window, TRUE); |
262 | gtk_box_append (GTK_BOX (vbox), child: scrolled_window); |
263 | |
264 | tree_model = create_model (); |
265 | tree_view = gtk_tree_view_new_with_model (model: tree_model); |
266 | gesture = gtk_gesture_click_new (); |
267 | g_signal_connect (gesture, "pressed" , G_CALLBACK (pressed_cb), tree_view); |
268 | gtk_widget_add_controller (widget: tree_view, GTK_EVENT_CONTROLLER (gesture)); |
269 | gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), TRUE); |
270 | |
271 | column = gtk_tree_view_column_new (); |
272 | gtk_tree_view_column_set_title (tree_column: column, title: "String" ); |
273 | area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column)); |
274 | |
275 | renderer = gtk_cell_renderer_pixbuf_new (); |
276 | gtk_tree_view_column_pack_start (tree_column: column, cell: renderer, FALSE); |
277 | gtk_tree_view_column_set_attributes (tree_column: column, cell_renderer: renderer, |
278 | "icon-name" , ICON_NAME_COLUMN, |
279 | "sensitive" , IS_SENSITIVE_COLUMN, |
280 | NULL); |
281 | callback[0].area = area; |
282 | callback[0].renderer = renderer; |
283 | |
284 | renderer = gtk_cell_renderer_text_new (); |
285 | gtk_tree_view_column_pack_start (tree_column: column, cell: renderer, FALSE); |
286 | gtk_tree_view_column_set_attributes (tree_column: column, cell_renderer: renderer, |
287 | "text" , STRING_COLUMN, |
288 | "editable" , IS_EDITABLE_COLUMN, |
289 | "sensitive" , IS_SENSITIVE_COLUMN, |
290 | NULL); |
291 | callback[1].area = area; |
292 | callback[1].renderer = renderer; |
293 | g_signal_connect (renderer, "edited" , |
294 | G_CALLBACK (edited), tree_model); |
295 | g_object_set (object: renderer, |
296 | first_property_name: "placeholder-text" , "Type here" , |
297 | NULL); |
298 | |
299 | renderer = gtk_cell_renderer_text_new (); |
300 | gtk_tree_view_column_pack_start (tree_column: column, cell: renderer, FALSE); |
301 | gtk_tree_view_column_set_attributes (tree_column: column, cell_renderer: renderer, |
302 | "text" , STRING_COLUMN, |
303 | "editable" , IS_EDITABLE_COLUMN, |
304 | "sensitive" , IS_SENSITIVE_COLUMN, |
305 | NULL); |
306 | callback[2].area = area; |
307 | callback[2].renderer = renderer; |
308 | g_signal_connect (renderer, "edited" , |
309 | G_CALLBACK (edited), tree_model); |
310 | g_object_set (object: renderer, |
311 | first_property_name: "placeholder-text" , "Type here too" , |
312 | NULL); |
313 | |
314 | renderer = gtk_cell_renderer_pixbuf_new (); |
315 | g_object_set (object: renderer, |
316 | first_property_name: "xalign" , 0.0, |
317 | NULL); |
318 | gtk_tree_view_column_pack_start (tree_column: column, cell: renderer, FALSE); |
319 | gtk_tree_view_column_set_attributes (tree_column: column, cell_renderer: renderer, |
320 | "icon-name" , LAST_ICON_NAME_COLUMN, |
321 | "sensitive" , IS_SENSITIVE_COLUMN, |
322 | NULL); |
323 | callback[3].area = area; |
324 | callback[3].renderer = renderer; |
325 | |
326 | gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); |
327 | |
328 | renderer = gtk_cell_renderer_toggle_new (); |
329 | g_signal_connect (renderer, "toggled" , |
330 | G_CALLBACK (editable_toggled), tree_model); |
331 | |
332 | g_object_set (object: renderer, |
333 | first_property_name: "xalign" , 0.0, |
334 | NULL); |
335 | gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), |
336 | position: -1, title: "Editable" , |
337 | cell: renderer, |
338 | "active" , IS_EDITABLE_COLUMN, |
339 | NULL); |
340 | |
341 | renderer = gtk_cell_renderer_toggle_new (); |
342 | g_signal_connect (renderer, "toggled" , |
343 | G_CALLBACK (sensitive_toggled), tree_model); |
344 | |
345 | g_object_set (object: renderer, |
346 | first_property_name: "xalign" , 0.0, |
347 | NULL); |
348 | gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), |
349 | position: -1, title: "Sensitive" , |
350 | cell: renderer, |
351 | "active" , IS_SENSITIVE_COLUMN, |
352 | NULL); |
353 | |
354 | renderer = gtk_cell_renderer_progress_new (); |
355 | gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), |
356 | position: -1, title: "Progress" , |
357 | cell: renderer, |
358 | "value" , PROGRESS_COLUMN, |
359 | NULL); |
360 | |
361 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window), child: tree_view); |
362 | |
363 | gtk_window_set_default_size (GTK_WINDOW (window), |
364 | width: 800, height: 250); |
365 | |
366 | hbox = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 6); |
367 | gtk_box_append (GTK_BOX (vbox), child: hbox); |
368 | |
369 | /* Alignment controls */ |
370 | cntl_vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 2); |
371 | gtk_box_append (GTK_BOX (hbox), child: cntl_vbox); |
372 | |
373 | create_control (box: cntl_vbox, number: 1, cntl: CNTL_ALIGN, data: &callback[0]); |
374 | create_control (box: cntl_vbox, number: 2, cntl: CNTL_ALIGN, data: &callback[1]); |
375 | create_control (box: cntl_vbox, number: 3, cntl: CNTL_ALIGN, data: &callback[2]); |
376 | create_control (box: cntl_vbox, number: 4, cntl: CNTL_ALIGN, data: &callback[3]); |
377 | |
378 | /* Expand controls */ |
379 | cntl_vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 2); |
380 | gtk_box_append (GTK_BOX (hbox), child: cntl_vbox); |
381 | |
382 | create_control (box: cntl_vbox, number: 1, cntl: CNTL_EXPAND, data: &callback[0]); |
383 | create_control (box: cntl_vbox, number: 2, cntl: CNTL_EXPAND, data: &callback[1]); |
384 | create_control (box: cntl_vbox, number: 3, cntl: CNTL_EXPAND, data: &callback[2]); |
385 | create_control (box: cntl_vbox, number: 4, cntl: CNTL_EXPAND, data: &callback[3]); |
386 | |
387 | /* Fixed controls */ |
388 | cntl_vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 2); |
389 | gtk_box_append (GTK_BOX (hbox), child: cntl_vbox); |
390 | |
391 | create_control (box: cntl_vbox, number: 1, cntl: CNTL_FIXED, data: &callback[0]); |
392 | create_control (box: cntl_vbox, number: 2, cntl: CNTL_FIXED, data: &callback[1]); |
393 | create_control (box: cntl_vbox, number: 3, cntl: CNTL_FIXED, data: &callback[2]); |
394 | create_control (box: cntl_vbox, number: 4, cntl: CNTL_FIXED, data: &callback[3]); |
395 | |
396 | gtk_widget_show (widget: window); |
397 | |
398 | while (!done) |
399 | g_main_context_iteration (NULL, TRUE); |
400 | |
401 | return 0; |
402 | } |
403 | |