1 | /* testcombochange.c |
2 | * Copyright (C) 2004 Red Hat, Inc. |
3 | * Author: Owen Taylor |
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 | #include <stdarg.h> |
22 | |
23 | GtkWidget *text_view; |
24 | GtkListStore *model; |
25 | GArray *contents; |
26 | |
27 | static char next_value = 'A'; |
28 | |
29 | G_GNUC_PRINTF (1, 2) static void |
30 | combochange_log (const char *fmt, |
31 | ...) |
32 | { |
33 | GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view)); |
34 | GtkTextIter iter; |
35 | va_list vap; |
36 | char *msg; |
37 | GString *order_string; |
38 | GtkTextMark *tmp_mark; |
39 | int i; |
40 | |
41 | va_start (vap, fmt); |
42 | |
43 | msg = g_strdup_vprintf (format: fmt, args: vap); |
44 | |
45 | gtk_text_buffer_get_end_iter (buffer, iter: &iter); |
46 | gtk_text_buffer_insert (buffer, iter: &iter, text: msg, len: -1); |
47 | |
48 | order_string = g_string_new (init: "\n " ); |
49 | for (i = 0; i < contents->len; i++) |
50 | { |
51 | if (i) |
52 | g_string_append_c (order_string, ' '); |
53 | g_string_append_c (order_string, g_array_index (contents, char, i)); |
54 | } |
55 | g_string_append_c (order_string, '\n'); |
56 | gtk_text_buffer_insert (buffer, iter: &iter, text: order_string->str, len: -1); |
57 | g_string_free (string: order_string, TRUE); |
58 | |
59 | tmp_mark = gtk_text_buffer_create_mark (buffer, NULL, where: &iter, FALSE); |
60 | gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (text_view), mark: tmp_mark); |
61 | gtk_text_buffer_delete_mark (buffer, mark: tmp_mark); |
62 | |
63 | g_free (mem: msg); |
64 | } |
65 | |
66 | static void |
67 | on_insert (void) |
68 | { |
69 | GtkTreeIter iter; |
70 | |
71 | int insert_pos; |
72 | char new_value[2]; |
73 | |
74 | new_value[0] = next_value++; |
75 | new_value[1] = '\0'; |
76 | |
77 | if (next_value > 'Z') |
78 | next_value = 'A'; |
79 | |
80 | if (contents->len) |
81 | insert_pos = g_random_int_range (begin: 0, end: contents->len + 1); |
82 | else |
83 | insert_pos = 0; |
84 | |
85 | gtk_list_store_insert (list_store: model, iter: &iter, position: insert_pos); |
86 | gtk_list_store_set (list_store: model, iter: &iter, 0, new_value, -1); |
87 | |
88 | g_array_insert_val (contents, insert_pos, new_value); |
89 | |
90 | combochange_log (fmt: "Inserted '%c' at position %d" , new_value[0], insert_pos); |
91 | } |
92 | |
93 | static void |
94 | on_delete (void) |
95 | { |
96 | GtkTreeIter iter; |
97 | |
98 | int delete_pos; |
99 | char old_val; |
100 | |
101 | if (!contents->len) |
102 | return; |
103 | |
104 | delete_pos = g_random_int_range (begin: 0, end: contents->len); |
105 | gtk_tree_model_iter_nth_child (GTK_TREE_MODEL (model), iter: &iter, NULL, n: delete_pos); |
106 | |
107 | gtk_list_store_remove (list_store: model, iter: &iter); |
108 | |
109 | old_val = g_array_index (contents, char, delete_pos); |
110 | g_array_remove_index (array: contents, index_: delete_pos); |
111 | combochange_log (fmt: "Deleted '%c' from position %d" , old_val, delete_pos); |
112 | } |
113 | |
114 | static void |
115 | on_reorder (void) |
116 | { |
117 | GArray *new_contents; |
118 | int *shuffle_array; |
119 | int i; |
120 | |
121 | shuffle_array = g_new (int, contents->len); |
122 | |
123 | for (i = 0; i < contents->len; i++) |
124 | shuffle_array[i] = i; |
125 | |
126 | for (i = 0; i + 1 < contents->len; i++) |
127 | { |
128 | int pos = g_random_int_range (begin: i, end: contents->len); |
129 | int tmp; |
130 | |
131 | tmp = shuffle_array[i]; |
132 | shuffle_array[i] = shuffle_array[pos]; |
133 | shuffle_array[pos] = tmp; |
134 | } |
135 | |
136 | gtk_list_store_reorder (store: model, new_order: shuffle_array); |
137 | |
138 | new_contents = g_array_new (FALSE, FALSE, element_size: sizeof (char)); |
139 | for (i = 0; i < contents->len; i++) |
140 | g_array_append_val (new_contents, |
141 | g_array_index (contents, char, shuffle_array[i])); |
142 | g_array_free (array: contents, TRUE); |
143 | contents = new_contents; |
144 | |
145 | combochange_log (fmt: "Reordered array" ); |
146 | |
147 | g_free (mem: shuffle_array); |
148 | } |
149 | |
150 | static int n_animations = 0; |
151 | static int timer = 0; |
152 | |
153 | static int |
154 | animation_timer (gpointer data) |
155 | { |
156 | switch (g_random_int_range (begin: 0, end: 3)) |
157 | { |
158 | case 0: |
159 | on_insert (); |
160 | break; |
161 | case 1: |
162 | on_delete (); |
163 | break; |
164 | case 2: |
165 | on_reorder (); |
166 | break; |
167 | default: |
168 | g_assert_not_reached (); |
169 | } |
170 | |
171 | n_animations--; |
172 | return n_animations > 0; |
173 | } |
174 | |
175 | static void |
176 | on_animate (void) |
177 | { |
178 | n_animations += 20; |
179 | |
180 | timer = g_timeout_add (interval: 1000, function: (GSourceFunc) animation_timer, NULL); |
181 | } |
182 | |
183 | int |
184 | main (int argc, char **argv) |
185 | { |
186 | GtkWidget *content_area; |
187 | GtkWidget *window; |
188 | GtkWidget *scrolled_window; |
189 | GtkWidget *hbox; |
190 | GtkWidget *button_vbox; |
191 | GtkWidget *combo_vbox; |
192 | GtkWidget *button; |
193 | GtkWidget *combo; |
194 | GtkCellRenderer *cell_renderer; |
195 | |
196 | gtk_init (); |
197 | |
198 | model = gtk_list_store_new (n_columns: 1, G_TYPE_STRING); |
199 | contents = g_array_new (FALSE, FALSE, element_size: sizeof (char)); |
200 | |
201 | window = gtk_window_new (); |
202 | gtk_window_set_title (GTK_WINDOW (window), title: "ComboBox Change" ); |
203 | |
204 | content_area = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 12); |
205 | gtk_window_set_child (GTK_WINDOW (window), child: content_area); |
206 | |
207 | hbox = gtk_box_new (orientation: GTK_ORIENTATION_HORIZONTAL, spacing: 12); |
208 | gtk_box_append (GTK_BOX (content_area), child: hbox); |
209 | |
210 | combo_vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 8); |
211 | gtk_box_append (GTK_BOX (hbox), child: combo_vbox); |
212 | |
213 | combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (model)); |
214 | cell_renderer = gtk_cell_renderer_text_new (); |
215 | gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), cell: cell_renderer, TRUE); |
216 | gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), cell: cell_renderer, |
217 | "text" , 0, NULL); |
218 | gtk_widget_set_margin_start (widget: combo, margin: 12); |
219 | gtk_box_append (GTK_BOX (combo_vbox), child: combo); |
220 | |
221 | scrolled_window = gtk_scrolled_window_new (); |
222 | gtk_widget_set_hexpand (widget: scrolled_window, TRUE); |
223 | gtk_box_append (GTK_BOX (hbox), child: scrolled_window); |
224 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), |
225 | hscrollbar_policy: GTK_POLICY_AUTOMATIC, vscrollbar_policy: GTK_POLICY_AUTOMATIC); |
226 | |
227 | text_view = gtk_text_view_new (); |
228 | gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), FALSE); |
229 | gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (text_view), FALSE); |
230 | |
231 | gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window), child: text_view); |
232 | |
233 | button_vbox = gtk_box_new (orientation: GTK_ORIENTATION_VERTICAL, spacing: 8); |
234 | gtk_box_append (GTK_BOX (hbox), child: button_vbox); |
235 | |
236 | gtk_window_set_default_size (GTK_WINDOW (window), width: 500, height: 300); |
237 | |
238 | button = gtk_button_new_with_label (label: "Insert" ); |
239 | gtk_box_append (GTK_BOX (button_vbox), child: button); |
240 | g_signal_connect (button, "clicked" , G_CALLBACK (on_insert), NULL); |
241 | |
242 | button = gtk_button_new_with_label (label: "Delete" ); |
243 | gtk_box_append (GTK_BOX (button_vbox), child: button); |
244 | g_signal_connect (button, "clicked" , G_CALLBACK (on_delete), NULL); |
245 | |
246 | button = gtk_button_new_with_label (label: "Reorder" ); |
247 | gtk_box_append (GTK_BOX (button_vbox), child: button); |
248 | g_signal_connect (button, "clicked" , G_CALLBACK (on_reorder), NULL); |
249 | |
250 | button = gtk_button_new_with_label (label: "Animate" ); |
251 | gtk_box_append (GTK_BOX (button_vbox), child: button); |
252 | g_signal_connect (button, "clicked" , G_CALLBACK (on_animate), NULL); |
253 | |
254 | GtkWidget *close_button = gtk_button_new_with_mnemonic (label: "_Close" ); |
255 | gtk_widget_set_hexpand (widget: close_button, TRUE); |
256 | gtk_box_append (GTK_BOX (content_area), child: close_button); |
257 | |
258 | gtk_widget_show (widget: window); |
259 | |
260 | GMainLoop *loop = g_main_loop_new (NULL, FALSE); |
261 | |
262 | g_signal_connect_swapped (close_button, "clicked" , |
263 | G_CALLBACK (gtk_window_destroy), |
264 | window); |
265 | g_signal_connect_swapped (window, "destroy" , |
266 | G_CALLBACK (g_main_loop_quit), |
267 | loop); |
268 | |
269 | g_main_loop_run (loop); |
270 | |
271 | g_main_loop_unref (loop); |
272 | |
273 | return 0; |
274 | } |
275 | |