1 #include <gtk/gtk.h>
2 
3 #include <string.h>
4 
5 typedef struct _Row Row;
6 typedef struct _RowClass RowClass;
7 
8 struct _Row
9 {
10   GtkListBoxRow parent_instance;
11   GtkWidget *label;
12   int sort_id;
13 };
14 
15 struct _RowClass
16 {
17   GtkListBoxRowClass parent_class;
18 };
19 
20 const char *css =
21   "list row {"
22   " border-width: 1px;"
23   " border-style: solid;"
24   " border-color: blue;"
25   "}"
26   "list row:hover {"
27   "background-color: green;"
28   "}"
29   "list row:active {"
30   "background-color: red;"
31   "}";
32 
33 static GType row_get_type (void);
G_DEFINE_TYPE(Row,row,GTK_TYPE_LIST_BOX_ROW)34 G_DEFINE_TYPE (Row, row, GTK_TYPE_LIST_BOX_ROW)
35 
36 static void
37 row_init (Row *row)
38 {
39 }
40 
41 static void
row_class_init(RowClass * class)42 row_class_init (RowClass *class)
43 {
44 }
45 
46 static GtkWidget *
row_new(const char * text,int sort_id)47 row_new (const char * text, int sort_id) {
48   Row *row;
49 
50   row = g_object_new (row_get_type (), NULL);
51   if (text != NULL)
52     {
53       row->label = gtk_label_new (text);
54       gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), row->label);
55     }
56   row->sort_id = sort_id;
57 
58   return GTK_WIDGET (row);
59 }
60 
61 
62 static void
update_header_cb(Row * row,Row * before,gpointer data)63 update_header_cb (Row *row, Row *before, gpointer data)
64 {
65   GtkWidget *hbox, *l, *b;
66 
67   if (before == NULL ||
68       (row->label != NULL &&
69        strcmp (gtk_label_get_text (GTK_LABEL (row->label)), "blah3") == 0))
70     {
71       /* Create header if needed */
72       if (gtk_list_box_row_get_header (GTK_LIST_BOX_ROW (row)) == NULL)
73         {
74           hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
75           l = gtk_label_new ("Header");
76           gtk_box_append (GTK_BOX (hbox), l);
77           b = gtk_button_new_with_label ("button");
78           gtk_box_append (GTK_BOX (hbox), b);
79           gtk_list_box_row_set_header (GTK_LIST_BOX_ROW (row), hbox);
80       }
81 
82       hbox = gtk_list_box_row_get_header(GTK_LIST_BOX_ROW (row));
83 
84       l = gtk_widget_get_first_child (hbox);
85       gtk_label_set_text (GTK_LABEL (l), g_strdup_printf ("Header %d", row->sort_id));
86     }
87   else
88     {
89       gtk_list_box_row_set_header(GTK_LIST_BOX_ROW (row), NULL);
90     }
91 }
92 
93 static int
sort_cb(Row * a,Row * b,gpointer data)94 sort_cb (Row *a, Row *b, gpointer data)
95 {
96   return a->sort_id - b->sort_id;
97 }
98 
99 static int
reverse_sort_cb(Row * a,Row * b,gpointer data)100 reverse_sort_cb (Row *a, Row *b, gpointer data)
101 {
102   return b->sort_id - a->sort_id;
103 }
104 
105 static gboolean
filter_cb(Row * row,gpointer data)106 filter_cb (Row *row, gpointer data)
107 {
108   const char *text;
109 
110   if (row->label != NULL)
111     {
112       text = gtk_label_get_text (GTK_LABEL (row->label));
113       return strcmp (text, "blah3") != 0;
114     }
115 
116   return TRUE;
117 }
118 
119 static void
row_activated_cb(GtkListBox * list_box,GtkListBoxRow * row)120 row_activated_cb (GtkListBox *list_box,
121                   GtkListBoxRow *row)
122 {
123   g_print ("activated row %p\n", row);
124 }
125 
126 static void
row_selected_cb(GtkListBox * list_box,GtkListBoxRow * row)127 row_selected_cb (GtkListBox *list_box,
128                  GtkListBoxRow *row)
129 {
130   g_print ("selected row %p\n", row);
131 }
132 
133 static void
sort_clicked_cb(GtkButton * button,gpointer data)134 sort_clicked_cb (GtkButton *button,
135                  gpointer data)
136 {
137   GtkListBox *list = data;
138 
139   gtk_list_box_set_sort_func (list, (GtkListBoxSortFunc)sort_cb, NULL, NULL);
140 }
141 
142 static void
reverse_sort_clicked_cb(GtkButton * button,gpointer data)143 reverse_sort_clicked_cb (GtkButton *button,
144                          gpointer data)
145 {
146   GtkListBox *list = data;
147 
148   gtk_list_box_set_sort_func (list, (GtkListBoxSortFunc)reverse_sort_cb, NULL, NULL);
149 }
150 
151 static void
filter_clicked_cb(GtkButton * button,gpointer data)152 filter_clicked_cb (GtkButton *button,
153                    gpointer data)
154 {
155   GtkListBox *list = data;
156 
157   gtk_list_box_set_filter_func (list, (GtkListBoxFilterFunc)filter_cb, NULL, NULL);
158 }
159 
160 static void
unfilter_clicked_cb(GtkButton * button,gpointer data)161 unfilter_clicked_cb (GtkButton *button,
162                    gpointer data)
163 {
164   GtkListBox *list = data;
165 
166   gtk_list_box_set_filter_func (list, NULL, NULL, NULL);
167 }
168 
169 static void
change_clicked_cb(GtkButton * button,gpointer data)170 change_clicked_cb (GtkButton *button,
171                    gpointer data)
172 {
173   Row *row = data;
174 
175   if (strcmp (gtk_label_get_text (GTK_LABEL (row->label)), "blah3") == 0)
176     {
177       gtk_label_set_text (GTK_LABEL (row->label), "blah5");
178       row->sort_id = 5;
179     }
180   else
181     {
182       gtk_label_set_text (GTK_LABEL (row->label), "blah3");
183       row->sort_id = 3;
184     }
185   gtk_list_box_row_changed (GTK_LIST_BOX_ROW (row));
186 }
187 
188 static void
add_clicked_cb(GtkButton * button,gpointer data)189 add_clicked_cb (GtkButton *button,
190                 gpointer data)
191 {
192   GtkListBox *list = data;
193   GtkWidget *new_row;
194   static int new_button_nr = 1;
195 
196   new_row = row_new( g_strdup_printf ("blah2 new %d", new_button_nr), new_button_nr);
197   gtk_list_box_insert (GTK_LIST_BOX (list), new_row, -1);
198   new_button_nr++;
199 }
200 
201 static void
separate_clicked_cb(GtkButton * button,gpointer data)202 separate_clicked_cb (GtkButton *button,
203                      gpointer data)
204 {
205   GtkListBox *list = data;
206 
207   gtk_list_box_set_header_func (list, (GtkListBoxUpdateHeaderFunc)update_header_cb, NULL, NULL);
208 }
209 
210 static void
unseparate_clicked_cb(GtkButton * button,gpointer data)211 unseparate_clicked_cb (GtkButton *button,
212                        gpointer data)
213 {
214   GtkListBox *list = data;
215 
216   gtk_list_box_set_header_func (list, NULL, NULL, NULL);
217 }
218 
219 static void
visibility_clicked_cb(GtkButton * button,gpointer data)220 visibility_clicked_cb (GtkButton *button,
221                        gpointer data)
222 {
223   GtkWidget *row = data;
224 
225   gtk_widget_set_visible (row, !gtk_widget_get_visible (row));
226 }
227 
228 static void
selection_mode_changed(GtkComboBox * combo,gpointer data)229 selection_mode_changed (GtkComboBox *combo, gpointer data)
230 {
231   GtkListBox *list = data;
232 
233   gtk_list_box_set_selection_mode (list, gtk_combo_box_get_active (combo));
234 }
235 
236 static void
single_click_clicked(GtkButton * check,gpointer data)237 single_click_clicked (GtkButton *check, gpointer data)
238 {
239   GtkListBox *list = data;
240 
241   g_print ("single: %d\n", gtk_check_button_get_active (GTK_CHECK_BUTTON (check)));
242   gtk_list_box_set_activate_on_single_click (list, gtk_check_button_get_active (GTK_CHECK_BUTTON (check)));
243 }
244 
245 int
main(int argc,char * argv[])246 main (int argc, char *argv[])
247 {
248   GtkCssProvider *provider;
249   GtkWidget *window, *hbox, *vbox, *list, *row, *row3, *row_vbox, *row_hbox, *l;
250   GtkWidget *check, *button, *combo, *scrolled;
251 
252   gtk_init ();
253 
254   window = gtk_window_new ();
255   hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
256   gtk_window_set_child (GTK_WINDOW (window), hbox);
257 
258   provider = gtk_css_provider_new ();
259   gtk_css_provider_load_from_data (provider, css, -1);
260   gtk_style_context_add_provider_for_display (gtk_widget_get_display (window),
261                                               GTK_STYLE_PROVIDER (provider),
262                                               GTK_STYLE_PROVIDER_PRIORITY_USER);
263 
264 
265   list = gtk_list_box_new ();
266 
267   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
268   gtk_box_append (GTK_BOX (hbox), vbox);
269 
270   combo = gtk_combo_box_text_new ();
271   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo),
272                                   "GTK_SELECTION_NONE");
273   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo),
274                                   "GTK_SELECTION_SINGLE");
275   gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo),
276                                   "GTK_SELECTION_BROWSE");
277   g_signal_connect (combo, "changed", G_CALLBACK (selection_mode_changed), list);
278   gtk_box_append (GTK_BOX (vbox), combo);
279   gtk_combo_box_set_active (GTK_COMBO_BOX (combo), gtk_list_box_get_selection_mode (GTK_LIST_BOX (list)));
280   check = gtk_check_button_new_with_label ("single click mode");
281   gtk_check_button_set_active (GTK_CHECK_BUTTON (check), gtk_list_box_get_activate_on_single_click (GTK_LIST_BOX (list)));
282   g_signal_connect (check, "toggled", G_CALLBACK (single_click_clicked), list);
283   gtk_box_append (GTK_BOX (vbox), check);
284 
285   scrolled = gtk_scrolled_window_new ();
286   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
287   gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled), list);
288   gtk_box_append (GTK_BOX (hbox), scrolled);
289 
290   g_signal_connect (list, "row-activated", G_CALLBACK (row_activated_cb), NULL);
291   g_signal_connect (list, "row-selected", G_CALLBACK (row_selected_cb), NULL);
292 
293   row = row_new ("blah4", 4);
294   gtk_list_box_insert (GTK_LIST_BOX (list), row, -1);
295   row3 = row = row_new ("blah3", 3);
296   gtk_list_box_insert (GTK_LIST_BOX (list), row, -1);
297   row = row_new ("blah1", 1);
298   gtk_list_box_insert (GTK_LIST_BOX (list), row, -1);
299   row = row_new ("blah2", 2);
300   gtk_list_box_insert (GTK_LIST_BOX (list), row, -1);
301 
302   row = row_new (NULL, 0);
303   row_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
304   row_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
305   l = gtk_label_new ("da box for da man");
306   gtk_box_append (GTK_BOX (row_hbox), l);
307   check = gtk_check_button_new ();
308   gtk_box_append (GTK_BOX (row_hbox), check);
309   button = gtk_button_new_with_label ("ya!");
310   gtk_box_append (GTK_BOX (row_hbox), button);
311   gtk_box_append (GTK_BOX (row_vbox), row_hbox);
312   check = gtk_check_button_new ();
313   gtk_box_append (GTK_BOX (row_vbox), check);
314   gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), row_vbox);
315   gtk_list_box_insert (GTK_LIST_BOX (list), row, -1);
316 
317   row = row_new (NULL, 0);
318   button = gtk_button_new_with_label ("focusable row");
319   gtk_widget_set_hexpand (button, FALSE);
320   gtk_widget_set_halign (button, GTK_ALIGN_START);
321   gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), button);
322   gtk_list_box_insert (GTK_LIST_BOX (list), row, -1);
323 
324   vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
325   gtk_box_append (GTK_BOX (hbox), vbox);
326 
327   button = gtk_button_new_with_label ("sort");
328   gtk_box_append (GTK_BOX (vbox), button);
329   g_signal_connect (button, "clicked", G_CALLBACK (sort_clicked_cb), list);
330 
331   button = gtk_button_new_with_label ("reverse");
332   gtk_box_append (GTK_BOX (vbox), button);
333   g_signal_connect (button, "clicked", G_CALLBACK (reverse_sort_clicked_cb), list);
334 
335   button = gtk_button_new_with_label ("change");
336   gtk_box_append (GTK_BOX (vbox), button);
337   g_signal_connect (button, "clicked", G_CALLBACK (change_clicked_cb), row3);
338 
339   button = gtk_button_new_with_label ("filter");
340   gtk_box_append (GTK_BOX (vbox), button);
341   g_signal_connect (button, "clicked", G_CALLBACK (filter_clicked_cb), list);
342 
343   button = gtk_button_new_with_label ("unfilter");
344   gtk_box_append (GTK_BOX (vbox), button);
345   g_signal_connect (button, "clicked", G_CALLBACK (unfilter_clicked_cb), list);
346 
347   button = gtk_button_new_with_label ("add");
348   gtk_box_append (GTK_BOX (vbox), button);
349   g_signal_connect (button, "clicked", G_CALLBACK (add_clicked_cb), list);
350 
351   button = gtk_button_new_with_label ("separate");
352   gtk_box_append (GTK_BOX (vbox), button);
353   g_signal_connect (button, "clicked", G_CALLBACK (separate_clicked_cb), list);
354 
355   button = gtk_button_new_with_label ("unseparate");
356   gtk_box_append (GTK_BOX (vbox), button);
357   g_signal_connect (button, "clicked", G_CALLBACK (unseparate_clicked_cb), list);
358 
359   button = gtk_button_new_with_label ("visibility");
360   gtk_box_append (GTK_BOX (vbox), button);
361   g_signal_connect (button, "clicked", G_CALLBACK (visibility_clicked_cb), row3);
362 
363   gtk_widget_show (window);
364 
365   while (TRUE)
366     g_main_context_iteration (NULL, TRUE);
367 
368   return 0;
369 }
370